|
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
/*============================================================
**
** File: Configuration.cs
**
**
** Purpose: Classes used for reading and storing configuration
**
**
===========================================================*/
namespace System.Runtime.Remoting {
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Lifetime;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Metadata;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Threading;
using System.IO;
using System.Security;
using System.Security.Permissions;
using System.Collections;
using System.Reflection;
using System.Globalization;
using System.Runtime.Versioning;
using System.Diagnostics.Contracts;
[Serializable]
[System.Runtime.InteropServices.ComVisible(true)]
public enum WellKnownObjectMode
{
Singleton = 1,
SingleCall = 2
}
// This is the class that plays the role of per-appDomain statics
// till we have the real functionality.
internal class DomainSpecificRemotingData
{
const int ACTIVATION_INITIALIZING = 0x00000001;
const int ACTIVATION_INITIALIZED = 0x00000002;
const int ACTIVATOR_LISTENING = 0x00000004;
[System.Security.SecurityCritical] // auto-generated
LocalActivator _LocalActivator;
ActivationListener _ActivationListener;
IContextProperty[] _appDomainProperties;
int _flags;
Object _ConfigLock;
ChannelServicesData _ChannelServicesData;
LeaseManager _LeaseManager;
ReaderWriterLock _IDTableLock;
internal DomainSpecificRemotingData()
{
_flags = 0;
_ConfigLock = new Object();
_ChannelServicesData = new ChannelServicesData();
_IDTableLock = new ReaderWriterLock();
// Add the Lifetime service property to the appdomain.
// For now we are assuming that this is the only property
// If there are more properties, then an existing array
// will need to be expanded to add this property
// The property needs to be added here so that the default context
// for an appdomain has lifetime services activated
_appDomainProperties = new IContextProperty[1];
_appDomainProperties[0] = new System.Runtime.Remoting.Lifetime.LeaseLifeTimeServiceProperty();
}
internal LeaseManager LeaseManager
{
get
{
return _LeaseManager;
}
set
{
_LeaseManager = value;
}
}
// This lock object is exposed for various objects that need to synchronize
// there configuration behavior.
internal Object ConfigLock
{
get { return _ConfigLock; }
}
// This is the rwlock used by the uri table functions
internal ReaderWriterLock IDTableLock
{
get { return _IDTableLock; }
}
internal LocalActivator LocalActivator
{
[System.Security.SecurityCritical] // auto-generated
get{return _LocalActivator;}
[System.Security.SecurityCritical] // auto-generated
set{_LocalActivator=value;}
}
internal ActivationListener ActivationListener
{
get {return _ActivationListener;}
set {_ActivationListener=value;}
}
// access to InitializingActivation, ActivationInitialized
// and ActivatorListening should be guarded by ConfigLock
// by the caller.
internal bool InitializingActivation
{
get {return (_flags & ACTIVATION_INITIALIZING) == ACTIVATION_INITIALIZING;}
set
{
if (value == true)
{
_flags = _flags | ACTIVATION_INITIALIZING;
}
else
{
_flags = _flags & ~ACTIVATION_INITIALIZING;
}
}
}
internal bool ActivationInitialized
{
get {return (_flags & ACTIVATION_INITIALIZED) == ACTIVATION_INITIALIZED;}
set
{
if (value == true)
{
_flags = _flags | ACTIVATION_INITIALIZED;
}
else
{
_flags = _flags & ~ACTIVATION_INITIALIZED;
}
}
}
internal bool ActivatorListening
{
get {return (_flags & ACTIVATOR_LISTENING) == ACTIVATOR_LISTENING;}
set
{
if (value == true)
{
_flags = _flags | ACTIVATOR_LISTENING;
}
else
{
_flags = _flags & ~ACTIVATOR_LISTENING;
}
}
}
internal IContextProperty[] AppDomainContextProperties
{
get { return _appDomainProperties; }
}
internal ChannelServicesData ChannelServicesData
{
get
{
return _ChannelServicesData;
}
}
} // class DomainSpecificRemotingData
//------------------------------------------------------------------
//--------------------- Remoting Configuration ---------------------
//------------------------------------------------------------------
internal static class RemotingConfigHandler
{
static volatile String _applicationName;
static volatile CustomErrorsModes _errorMode = CustomErrorsModes.RemoteOnly;
static volatile bool _errorsModeSet = false;
static volatile bool _bMachineConfigLoaded = false;
static volatile bool _bUrlObjRefMode = false;
static Queue _delayLoadChannelConfigQueue = new Queue(); // queue of channels we might be able to use
// All functions of RemotingConfigHandler operate upon the config
// data stored on a per appDomain basis
public static RemotingConfigInfo Info = new RemotingConfigInfo();
private const String _machineConfigFilename = "machine.config";
internal static String ApplicationName
{
get
{
if (_applicationName == null)
{
throw new RemotingException(
Environment.GetResourceString(
"Remoting_Config_NoAppName"));
}
return _applicationName;
}
set
{
if (_applicationName != null)
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Config_AppNameSet"),
_applicationName));
}
_applicationName = value;
// get rid of any starting or trailing slashes
char[] slash = new char[]{'/'};
if (_applicationName.StartsWith("/", StringComparison.Ordinal))
_applicationName = _applicationName.TrimStart(slash);
if (_applicationName.EndsWith("/", StringComparison.Ordinal))
_applicationName = _applicationName.TrimEnd(slash);
}
}
internal static bool HasApplicationNameBeenSet()
{
return _applicationName != null;
}
internal static bool UrlObjRefMode
{
get { return _bUrlObjRefMode; }
}
internal static CustomErrorsModes CustomErrorsMode
{
get {
return _errorMode;
}
set
{
if (_errorsModeSet)
throw new RemotingException(Environment.GetResourceString("Remoting_Config_ErrorsModeSet"));
_errorMode = value;
_errorsModeSet = true;
}
}
[System.Security.SecurityCritical] // auto-generated
internal static IMessageSink FindDelayLoadChannelForCreateMessageSink(
String url, Object data, out String objectURI)
{
LoadMachineConfigIfNecessary();
objectURI = null;
IMessageSink msgSink = null;
foreach (DelayLoadClientChannelEntry entry in _delayLoadChannelConfigQueue)
{
IChannelSender channel = entry.Channel;
// if the channel is null, that means it has already been registered.
if (channel != null)
{
msgSink = channel.CreateMessageSink(url, data, out objectURI);
if (msgSink != null)
{
entry.RegisterChannel();
return msgSink;
}
}
}
return null;
} // FindChannelForCreateMessageSink
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
static void LoadMachineConfigIfNecessary()
{
// Load the machine.config file if we haven't already
if (!_bMachineConfigLoaded)
{
lock (Info)
{
if (!_bMachineConfigLoaded)
{
RemotingXmlConfigFileData configData = RemotingXmlConfigFileParser.ParseDefaultConfiguration();
if (configData != null)
ConfigureRemoting(configData, false/*ensureSecurity*/);
String machineDirectory = System.Security.Util.Config.MachineDirectory;
String longFileName = machineDirectory
+ _machineConfigFilename;
new FileIOPermission(FileIOPermissionAccess.Read, longFileName).Assert();
configData = LoadConfigurationFromXmlFile(longFileName);
if (configData != null)
ConfigureRemoting(configData, false/*ensureSecurity*/);
_bMachineConfigLoaded = true;
}
}
}
} // LoadMachineConfigIfNecessary
[System.Security.SecurityCritical] // auto-generated
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
internal static void DoConfiguration(String filename, bool ensureSecurity)
{
LoadMachineConfigIfNecessary();
// load specified config file
RemotingXmlConfigFileData configData = LoadConfigurationFromXmlFile(filename);
// Configure remoting based on data loaded from the config file.
// By design, we do nothing if no remoting config information was
// present in the file.
if (configData != null)
ConfigureRemoting(configData, ensureSecurity);
}
[ResourceExposure(ResourceScope.Machine)]
[ResourceConsumption(ResourceScope.Machine)]
private static RemotingXmlConfigFileData LoadConfigurationFromXmlFile(String filename)
{
try
{
if (filename != null)
return RemotingXmlConfigFileParser.ParseConfigFile(filename);
else
return null;
}
catch (Exception e)
{
Exception inner = e.InnerException as FileNotFoundException;
if (inner != null)
{
// if the file is missing, this gives a clearer message
e = inner;
}
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_Config_ReadFailure"),
filename,
e));
}
} // LoadConfigurationFromXmlFile
[System.Security.SecurityCritical] // auto-generated
private static void ConfigureRemoting(RemotingXmlConfigFileData configData, bool ensureSecurity)
{
try
{
String appName = configData.ApplicationName;
if (appName != null)
ApplicationName = appName;
if (configData.CustomErrors != null)
_errorMode = configData.CustomErrors.Mode;
// configure channels
ConfigureChannels(configData, ensureSecurity);
// configure lifetime
if (configData.Lifetime != null)
{
if (configData.Lifetime.IsLeaseTimeSet)
LifetimeServices.LeaseTime = configData.Lifetime.LeaseTime;
if (configData.Lifetime.IsRenewOnCallTimeSet)
LifetimeServices.RenewOnCallTime = configData.Lifetime.RenewOnCallTime;
if (configData.Lifetime.IsSponsorshipTimeoutSet)
LifetimeServices.SponsorshipTimeout = configData.Lifetime.SponsorshipTimeout;
if (configData.Lifetime.IsLeaseManagerPollTimeSet)
LifetimeServices.LeaseManagerPollTime = configData.Lifetime.LeaseManagerPollTime;
}
_bUrlObjRefMode = configData.UrlObjRefMode;
// configure other entries
Info.StoreRemoteAppEntries(configData);
Info.StoreActivatedExports(configData);
Info.StoreInteropEntries(configData);
Info.StoreWellKnownExports(configData);
// start up activation listener if there are any activated objects exposed
if (configData.ServerActivatedEntries.Count > 0)
ActivationServices.StartListeningForRemoteRequests();
}
catch (Exception e)
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_Config_ConfigurationFailure"),
e));
}
} // ConfigureRemoting
// configures channels loaded from remoting config file.
[System.Security.SecurityCritical] // auto-generated
private static void ConfigureChannels(RemotingXmlConfigFileData configData, bool ensureSecurity)
{
// Register our x-context & x-AD channels first
RemotingServices.RegisterWellKnownChannels();
foreach (RemotingXmlConfigFileData.ChannelEntry entry in configData.ChannelEntries)
{
if (!entry.DelayLoad)
{
IChannel chnl = CreateChannelFromConfigEntry(entry);
ChannelServices.RegisterChannel(chnl, ensureSecurity);
}
else
_delayLoadChannelConfigQueue.Enqueue(new DelayLoadClientChannelEntry(entry, ensureSecurity));
}
} // ConfigureChannels
[System.Security.SecurityCritical] // auto-generated
internal static IChannel CreateChannelFromConfigEntry(
RemotingXmlConfigFileData.ChannelEntry entry)
{
Type type = RemotingConfigInfo.LoadType(entry.TypeName, entry.AssemblyName);
bool isServerChannel = typeof(IChannelReceiver).IsAssignableFrom(type);
bool isClientChannel = typeof(IChannelSender).IsAssignableFrom(type);
IClientChannelSinkProvider clientProviderChain = null;
IServerChannelSinkProvider serverProviderChain = null;
if (entry.ClientSinkProviders.Count > 0)
clientProviderChain = CreateClientChannelSinkProviderChain(entry.ClientSinkProviders);
if (entry.ServerSinkProviders.Count > 0)
serverProviderChain = CreateServerChannelSinkProviderChain(entry.ServerSinkProviders);
// construct argument list
Object[] args;
if (isServerChannel && isClientChannel)
{
args = new Object[3];
args[0] = entry.Properties;
args[1] = clientProviderChain;
args[2] = serverProviderChain;
}
else
if (isServerChannel)
{
args = new Object[2];
args[0] = entry.Properties;
args[1] = serverProviderChain;
}
else
if (isClientChannel)
{
args = new Object[2];
args[0] = entry.Properties;
args[1] = clientProviderChain;
}
else
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Config_InvalidChannelType"),
type.FullName));
}
IChannel channel = null;
try
{
channel = (IChannel)Activator.CreateInstance(type,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance,
null,
args,
null,
null);
}
catch (MissingMethodException)
{
String ctor = null;
if (isServerChannel && isClientChannel)
ctor = "MyChannel(IDictionary properties, IClientChannelSinkProvider clientSinkProvider, IServerChannelSinkProvider serverSinkProvider)";
else
if (isServerChannel)
ctor = "MyChannel(IDictionary properties, IServerChannelSinkProvider serverSinkProvider)";
else
if (isClientChannel)
ctor = "MyChannel(IDictionary properties, IClientChannelSinkProvider clientSinkProvider)";
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Config_ChannelMissingCtor"),
type.FullName, ctor));
}
return channel;
} // CreateChannelFromEntry
// create a client sink provider chain
[System.Security.SecurityCritical] // auto-generated
private static IClientChannelSinkProvider CreateClientChannelSinkProviderChain(ArrayList entries)
{
IClientChannelSinkProvider chain = null;
IClientChannelSinkProvider current = null;
foreach (RemotingXmlConfigFileData.SinkProviderEntry entry in entries)
{
if (chain == null)
{
chain = (IClientChannelSinkProvider)CreateChannelSinkProvider(entry, false);
current = chain;
}
else
{
current.Next = (IClientChannelSinkProvider)CreateChannelSinkProvider(entry, false);
current = current.Next;
}
}
return chain;
} // CreateClientChannelSinkProviderChain
// create a client sink provider chain
[System.Security.SecurityCritical] // auto-generated
private static IServerChannelSinkProvider CreateServerChannelSinkProviderChain(ArrayList entries)
{
IServerChannelSinkProvider chain = null;
IServerChannelSinkProvider current = null;
foreach (RemotingXmlConfigFileData.SinkProviderEntry entry in entries)
{
if (chain == null)
{
chain = (IServerChannelSinkProvider)CreateChannelSinkProvider(entry, true);
current = chain;
}
else
{
current.Next = (IServerChannelSinkProvider)CreateChannelSinkProvider(entry, true);
current = current.Next;
}
}
return chain;
} // CreateServerChannelSinkProviderChain
// create a sink provider from the config file data
[System.Security.SecurityCritical] // auto-generated
private static Object CreateChannelSinkProvider(RemotingXmlConfigFileData.SinkProviderEntry entry,
bool bServer)
{
Object sinkProvider = null;
Type type = RemotingConfigInfo.LoadType(entry.TypeName, entry.AssemblyName);
if (bServer)
{
// make sure this is a client provider
if (!typeof(IServerChannelSinkProvider).IsAssignableFrom(type))
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Config_InvalidSinkProviderType"),
type.FullName,
"IServerChannelSinkProvider"));
}
}
else
{
// make sure this is a server provider
if (!typeof(IClientChannelSinkProvider).IsAssignableFrom(type))
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Config_InvalidSinkProviderType"),
type.FullName,
"IClientChannelSinkProvider"));
}
}
// check to see if something labelled as a formatter is a formatter
if (entry.IsFormatter)
{
if ((bServer && !typeof(IServerFormatterSinkProvider).IsAssignableFrom(type)) ||
(!bServer && !typeof(IClientFormatterSinkProvider).IsAssignableFrom(type)))
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Config_SinkProviderNotFormatter"),
type.FullName));
}
}
// setup the argument list and call the constructor
Object[] args = new Object[2];
args[0] = entry.Properties;
args[1] = entry.ProviderData;
try
{
sinkProvider = Activator.CreateInstance(type,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance,
null,
args,
null,
null);
}
catch (MissingMethodException)
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString("Remoting_Config_SinkProviderMissingCtor"),
type.FullName,
"MySinkProvider(IDictionary properties, ICollection providerData)"));
}
return sinkProvider;
} // CreateChannelSinkProvider
// This is used at the client end to check if an activation needs
// to go remote.
[System.Security.SecurityCritical] // auto-generated
internal static ActivatedClientTypeEntry IsRemotelyActivatedClientType(RuntimeType svrType)
{
RemotingTypeCachedData cache = (RemotingTypeCachedData)
InternalRemotingServices.GetReflectionCachedData(svrType);
String assemblyName = cache.SimpleAssemblyName;
ActivatedClientTypeEntry entry = Info.QueryRemoteActivate(svrType.FullName, assemblyName);
if (entry == null)
{
// If not found try with the full assembly name
String fullAssemblyName = cache.AssemblyName;
entry = Info.QueryRemoteActivate(svrType.FullName, fullAssemblyName);
if (entry == null){
// If still not found try with partial type name (without namespace)
entry = Info.QueryRemoteActivate(svrType.Name, assemblyName);
}
}
return entry;
} // IsRemotelyActivatedClientType
// This is used at the client end to check if an activation needs
// to go remote.
internal static ActivatedClientTypeEntry IsRemotelyActivatedClientType(String typeName, String assemblyName)
{
return Info.QueryRemoteActivate(typeName, assemblyName);
}
// This is used at the client end to check if a "new Foo" needs to
// happen via a Connect() under the covers.
[System.Security.SecurityCritical] // auto-generated
internal static WellKnownClientTypeEntry IsWellKnownClientType(RuntimeType svrType)
{
RemotingTypeCachedData cache = (RemotingTypeCachedData)
InternalRemotingServices.GetReflectionCachedData(svrType);
String assemblyName = cache.SimpleAssemblyName;
WellKnownClientTypeEntry wke = Info.QueryConnect(svrType.FullName, assemblyName);
if (wke == null)
{
wke= Info.QueryConnect(svrType.Name, assemblyName);
}
return wke;
}
// This is used at the client end to check if a "new Foo" needs to
// happen via a Connect() under the covers.
internal static WellKnownClientTypeEntry IsWellKnownClientType(String typeName,
String assemblyName)
{
return Info.QueryConnect(typeName, assemblyName);
}
//
// helper functions for processing and parsing data
//
private static void ParseGenericType(String typeAssem, int indexStart, out String typeName, out String assemName)
{
int len = typeAssem.Length;
int depth = 1;
int index = indexStart;
while(depth > 0 && (++index < len - 1))
{
if (typeAssem[index] == '[') {
depth++;
}
else if (typeAssem[index] == ']') {
depth--;
}
}
if (depth > 0 || index >= len) {
typeName = null;
assemName = null;
}
else {
index = typeAssem.IndexOf(',', index);
// comma must be present, and can't be last character
if ((index >= 0) && (index < (len - 1)))
{
typeName = typeAssem.Substring(0, index).Trim();
assemName = typeAssem.Substring(index + 1).Trim();
}
else
{
typeName = null;
assemName = null;
}
}
}
internal static void ParseType(String typeAssem, out String typeName, out String assemName)
{
String value = typeAssem;
int genericTypeIndex = value.IndexOf("[");
if ((genericTypeIndex >= 0) && (genericTypeIndex < (value.Length - 1)))
{
ParseGenericType(value, genericTypeIndex, out typeName, out assemName);
}
else
{
int index = value.IndexOf(",");
// comma must be present, and can't be last character
if ((index >= 0) && (index < (value.Length - 1)))
{
typeName = value.Substring(0, index).Trim();
assemName = value.Substring(index + 1).Trim();
}
else
{
typeName = null;
assemName = null;
}
}
} // ParseType
// This is used at the server end to check if a type being activated
// is explicitly allowed by the server.
[System.Security.SecurityCritical] // auto-generated
internal static bool IsActivationAllowed(RuntimeType svrType)
{
if (svrType == null)
return false;
RemotingTypeCachedData cache = (RemotingTypeCachedData)
InternalRemotingServices.GetReflectionCachedData(svrType);
String assemblyName = cache.SimpleAssemblyName;
return Info.ActivationAllowed(svrType.FullName, assemblyName);
} // IsActivationAllowed
// This is the flavor that we call from the activation listener
// code path. This ensures that we don't load a type before checking
// that it is configured for remote activation
[System.Security.SecurityCritical] // auto-generated
internal static bool IsActivationAllowed(String TypeName)
{
String svrTypeName = RemotingServices.InternalGetTypeNameFromQualifiedTypeName(TypeName);
if (svrTypeName == null)
{
return false;
}
String typeName;
String asmName;
ParseType(svrTypeName, out typeName, out asmName);
if (asmName == null)
return false;
int index = asmName.IndexOf(',');
if (index != -1)
{
// strip off the version info
asmName = asmName.Substring(0,index);
}
return Info.ActivationAllowed(typeName, asmName);
}
// helper for Configuration::RegisterActivatedServiceType
internal static void RegisterActivatedServiceType(ActivatedServiceTypeEntry entry)
{
Info.AddActivatedType(entry.TypeName, entry.AssemblyName,
entry.ContextAttributes);
} // RegisterActivatedServiceType
// helper for Configuration::RegisterWellKnownServiceType
[System.Security.SecurityCritical] // auto-generated
internal static void RegisterWellKnownServiceType(WellKnownServiceTypeEntry entry)
{
BCLDebug.Trace("REMOTE", "Adding well known service type for " + entry.ObjectUri);
// <
String serverType = entry.TypeName;
String asmName = entry.AssemblyName;
String URI = entry.ObjectUri;
WellKnownObjectMode mode = entry.Mode;
lock (Info)
{
// We make an entry in our config tables so as to keep
// both the file-based and programmatic config in sync.
Info.AddWellKnownEntry(entry);
}
} // RegisterWellKnownServiceType
// helper for Configuration::RegisterActivatedClientType
internal static void RegisterActivatedClientType(ActivatedClientTypeEntry entry)
{
Info.AddActivatedClientType(entry);
}
// helper for Configuration::RegisterWellKnownClientType
internal static void RegisterWellKnownClientType(WellKnownClientTypeEntry entry)
{
Info.AddWellKnownClientType(entry);
}
//helper for Configuration::GetServerTypeForUri
[System.Security.SecurityCritical] // auto-generated
internal static Type GetServerTypeForUri(String URI)
{
URI = Identity.RemoveAppNameOrAppGuidIfNecessary(URI);
return Info.GetServerTypeForUri(URI);
}
// helper for Configuration::GetRegisteredActivatedServiceTypes
internal static ActivatedServiceTypeEntry[] GetRegisteredActivatedServiceTypes()
{
return Info.GetRegisteredActivatedServiceTypes();
} // GetRegisteredActivatedServiceTypes
// helper for Configuration::GetRegisteredWellKnownServiceTypes
internal static WellKnownServiceTypeEntry[] GetRegisteredWellKnownServiceTypes()
{
return Info.GetRegisteredWellKnownServiceTypes();
} // GetRegisteredWellKnownServiceTypes
// helper for Configuration::GetRegisteredActivatedClientTypes
internal static ActivatedClientTypeEntry[] GetRegisteredActivatedClientTypes()
{
return Info.GetRegisteredActivatedClientTypes();
} // GetRegisteredActivatedClientTypes
// helper for Configuration::GetRegisteredWellKnownClientTypes
internal static WellKnownClientTypeEntry[] GetRegisteredWellKnownClientTypes()
{
return Info.GetRegisteredWellKnownClientTypes();
} // GetRegisteredWellKnownClientTypes
// helper for creating well known objects on demand
[System.Security.SecurityCritical] // auto-generated
internal static ServerIdentity CreateWellKnownObject(String uri)
{
uri = Identity.RemoveAppNameOrAppGuidIfNecessary(uri);
return Info.StartupWellKnownObject(uri);
}
internal class RemotingConfigInfo
{
Hashtable _exportableClasses; // list of objects that can be client-activated
// (this should be a StringTable since we only use the key,
// but that type was removed from the BCL :( )
Hashtable _remoteTypeInfo;
Hashtable _remoteAppInfo;
Hashtable _wellKnownExportInfo; //well known exports indexed by object URI in lower-case
static char[] SepSpace = {' '};
static char[] SepPound = {'#'};
static char[] SepSemiColon = {';'};
static char[] SepEquals = {'='};
private static Object s_wkoStartLock = new Object();
private static PermissionSet s_fullTrust = new PermissionSet(PermissionState.Unrestricted);
internal RemotingConfigInfo()
{
// <
_remoteTypeInfo = Hashtable.Synchronized(new Hashtable());
_exportableClasses = Hashtable.Synchronized(new Hashtable());
_remoteAppInfo = Hashtable.Synchronized(new Hashtable());
_wellKnownExportInfo = Hashtable.Synchronized(new Hashtable());
}
// encodes type name and assembly name into one string for purposes of
// indexing in lists and hash tables
private String EncodeTypeAndAssemblyNames(String typeName, String assemblyName)
{
return typeName + ", " + assemblyName.ToLower(CultureInfo.InvariantCulture);
}
//
// XML Configuration Helper Functions
//
internal void StoreActivatedExports(RemotingXmlConfigFileData configData)
{
foreach (RemotingXmlConfigFileData.TypeEntry entry in configData.ServerActivatedEntries)
{
ActivatedServiceTypeEntry aste =
new ActivatedServiceTypeEntry(entry.TypeName, entry.AssemblyName);
aste.ContextAttributes =
CreateContextAttributesFromConfigEntries(entry.ContextAttributes);
RemotingConfiguration.RegisterActivatedServiceType(aste);
}
} // StoreActivatedExports
[System.Security.SecurityCritical] // auto-generated
internal void StoreInteropEntries(RemotingXmlConfigFileData configData)
{
// process interop xml element entries
foreach (RemotingXmlConfigFileData.InteropXmlElementEntry entry in
configData.InteropXmlElementEntries)
{
Assembly assembly = Assembly.Load(entry.UrtAssemblyName);
Type type = assembly.GetType(entry.UrtTypeName);
SoapServices.RegisterInteropXmlElement(entry.XmlElementName,
entry.XmlElementNamespace,
type);
}
// process interop xml type entries
foreach (RemotingXmlConfigFileData.InteropXmlTypeEntry entry in
configData.InteropXmlTypeEntries)
{
Assembly assembly = Assembly.Load(entry.UrtAssemblyName);
Type type = assembly.GetType(entry.UrtTypeName);
SoapServices.RegisterInteropXmlType(entry.XmlTypeName,
entry.XmlTypeNamespace,
type);
}
// process preload entries
foreach (RemotingXmlConfigFileData.PreLoadEntry entry in configData.PreLoadEntries)
{
Assembly assembly = Assembly.Load(entry.AssemblyName);
if (entry.TypeName != null)
{
Type type = assembly.GetType(entry.TypeName);
SoapServices.PreLoad(type);
}
else
{
SoapServices.PreLoad(assembly);
}
}
} // StoreInteropEntries
internal void StoreRemoteAppEntries(RemotingXmlConfigFileData configData)
{
char[] slash = new char[]{'/'};
// add each remote app to the table
foreach (RemotingXmlConfigFileData.RemoteAppEntry remApp in configData.RemoteAppEntries)
{
// form complete application uri by combining specified uri with app-name
// (make sure appUri ends with slash, and that app name doesn't start,
// with one. then make sure that the combined form has no trailing slashes).
String appUri = remApp.AppUri;
if ((appUri != null) && !appUri.EndsWith("/", StringComparison.Ordinal))
appUri = appUri.TrimEnd(slash);
// add each client activated type for this remote app
foreach (RemotingXmlConfigFileData.TypeEntry cae in remApp.ActivatedObjects)
{
ActivatedClientTypeEntry acte =
new ActivatedClientTypeEntry(cae.TypeName, cae.AssemblyName,
appUri);
acte.ContextAttributes =
CreateContextAttributesFromConfigEntries(cae.ContextAttributes);
RemotingConfiguration.RegisterActivatedClientType(acte);
}
// add each well known object for this remote app
foreach (RemotingXmlConfigFileData.ClientWellKnownEntry cwke in remApp.WellKnownObjects)
{
WellKnownClientTypeEntry wke =
new WellKnownClientTypeEntry(cwke.TypeName, cwke.AssemblyName,
cwke.Url);
wke.ApplicationUrl = appUri;
RemotingConfiguration.RegisterWellKnownClientType(wke);
}
}
} // StoreRemoteAppEntries
[System.Security.SecurityCritical] // auto-generated
internal void StoreWellKnownExports(RemotingXmlConfigFileData configData)
{
// <
foreach (RemotingXmlConfigFileData.ServerWellKnownEntry entry in configData.ServerWellKnownEntries)
{
WellKnownServiceTypeEntry wke =
new WellKnownServiceTypeEntry(
entry.TypeName, entry.AssemblyName, entry.ObjectURI,
entry.ObjectMode);
wke.ContextAttributes = null;
// Register the well known entry but do not startup the object
RemotingConfigHandler.RegisterWellKnownServiceType(wke);
}
} // StoreWellKnownExports
// helper functions for above configuration helpers
static IContextAttribute[] CreateContextAttributesFromConfigEntries(ArrayList contextAttributes)
{
// create context attribute entry list
int numAttrs = contextAttributes.Count;
if (numAttrs == 0)
return null;
IContextAttribute[] attrs = new IContextAttribute[numAttrs];
int co = 0;
foreach (RemotingXmlConfigFileData.ContextAttributeEntry cae in contextAttributes)
{
Assembly asm = Assembly.Load(cae.AssemblyName);
IContextAttribute attr = null;
Hashtable properties = cae.Properties;
if ((properties != null) && (properties.Count > 0))
{
Object[] args = new Object[1];
args[0] = properties;
// We explicitly allow the ability to create internal
// only attributes
attr = (IContextAttribute)
Activator.CreateInstance(
asm.GetType(cae.TypeName, false, false),
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance,
null,
args,
null,
null);
}
else
{
attr = (IContextAttribute)
Activator.CreateInstance(
asm.GetType(cae.TypeName, false, false),
true);
}
attrs[co++] = attr;
}
return attrs;
} // CreateContextAttributesFromConfigEntries
//
// end of XML configuration helper functions
//
internal bool ActivationAllowed(String typeName, String assemblyName)
{
// the assembly name is stored in lower-case to let it be case-insensitive
return _exportableClasses.ContainsKey(EncodeTypeAndAssemblyNames(typeName, assemblyName));
}
internal ActivatedClientTypeEntry QueryRemoteActivate(String typeName, String assemblyName)
{
String index = EncodeTypeAndAssemblyNames(typeName, assemblyName);
ActivatedClientTypeEntry typeEntry = _remoteTypeInfo[index] as ActivatedClientTypeEntry;
if (typeEntry == null)
return null;
if (typeEntry.GetRemoteAppEntry() == null)
{
RemoteAppEntry appEntry = (RemoteAppEntry)
_remoteAppInfo[typeEntry.ApplicationUrl];
if (appEntry == null)
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_Activation_MissingRemoteAppEntry"),
typeEntry.ApplicationUrl));
}
typeEntry.CacheRemoteAppEntry(appEntry);
}
return typeEntry;
}
internal WellKnownClientTypeEntry QueryConnect(String typeName, String assemblyName)
{
String index = EncodeTypeAndAssemblyNames(typeName, assemblyName);
WellKnownClientTypeEntry typeEntry = _remoteTypeInfo[index] as WellKnownClientTypeEntry;
if (typeEntry == null)
return null;
return typeEntry;
}
//
// helper functions to retrieve registered types
//
internal ActivatedServiceTypeEntry[] GetRegisteredActivatedServiceTypes()
{
ActivatedServiceTypeEntry[] entries =
new ActivatedServiceTypeEntry[_exportableClasses.Count];
int co = 0;
foreach (DictionaryEntry dictEntry in _exportableClasses)
{
entries[co++] = (ActivatedServiceTypeEntry)dictEntry.Value;
}
return entries;
} // GetRegisteredActivatedServiceTypes
internal WellKnownServiceTypeEntry[] GetRegisteredWellKnownServiceTypes()
{
WellKnownServiceTypeEntry[] entries =
new WellKnownServiceTypeEntry[_wellKnownExportInfo.Count];
int co = 0;
foreach (DictionaryEntry dictEntry in _wellKnownExportInfo)
{
WellKnownServiceTypeEntry entry = (WellKnownServiceTypeEntry)dictEntry.Value;
WellKnownServiceTypeEntry wkste =
new WellKnownServiceTypeEntry(
entry.TypeName, entry.AssemblyName,
entry.ObjectUri, entry.Mode);
wkste.ContextAttributes = entry.ContextAttributes;
entries[co++] = wkste;
}
return entries;
} // GetRegisteredWellKnownServiceTypes
internal ActivatedClientTypeEntry[] GetRegisteredActivatedClientTypes()
{
// count number of well known client types
int count = 0;
foreach (DictionaryEntry dictEntry in _remoteTypeInfo)
{
ActivatedClientTypeEntry entry = dictEntry.Value as ActivatedClientTypeEntry;
if (entry != null)
count++;
}
ActivatedClientTypeEntry[] entries =
new ActivatedClientTypeEntry[count];
int co = 0;
foreach (DictionaryEntry dictEntry in _remoteTypeInfo)
{
ActivatedClientTypeEntry entry = dictEntry.Value as ActivatedClientTypeEntry;
if (entry != null)
{
// retrieve application url
String appUrl = null;
RemoteAppEntry remApp = entry.GetRemoteAppEntry();
if (remApp != null)
appUrl = remApp.GetAppURI();
ActivatedClientTypeEntry wkcte =
new ActivatedClientTypeEntry(entry.TypeName,
entry.AssemblyName, appUrl);
// Fetch the context attributes
wkcte.ContextAttributes = entry.ContextAttributes;
entries[co++] = wkcte;
}
}
return entries;
} // GetRegisteredActivatedClientTypes
internal WellKnownClientTypeEntry[] GetRegisteredWellKnownClientTypes()
{
// count number of well known client types
int count = 0;
foreach (DictionaryEntry dictEntry in _remoteTypeInfo)
{
WellKnownClientTypeEntry entry = dictEntry.Value as WellKnownClientTypeEntry;
if (entry != null)
count++;
}
WellKnownClientTypeEntry[] entries =
new WellKnownClientTypeEntry[count];
int co = 0;
foreach (DictionaryEntry dictEntry in _remoteTypeInfo)
{
WellKnownClientTypeEntry entry = dictEntry.Value as WellKnownClientTypeEntry;
if (entry != null)
{
WellKnownClientTypeEntry wkcte =
new WellKnownClientTypeEntry(entry.TypeName,
entry.AssemblyName, entry.ObjectUrl);
// see if there is an associated app
RemoteAppEntry remApp = entry.GetRemoteAppEntry();
if (remApp != null)
wkcte.ApplicationUrl = remApp.GetAppURI();
entries[co++] = wkcte;
}
}
return entries;
} // GetRegisteredWellKnownClientTypes
//
// end of helper functions to retrieve registered types
//
internal void AddActivatedType(String typeName, String assemblyName,
IContextAttribute[] contextAttributes)
{
if (typeName == null)
throw new ArgumentNullException("typeName");
if (assemblyName == null)
throw new ArgumentNullException("assemblyName");
Contract.EndContractBlock();
if (CheckForRedirectedClientType(typeName, assemblyName))
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_Config_CantUseRedirectedTypeForWellKnownService"),
typeName, assemblyName));
}
ActivatedServiceTypeEntry aste =
new ActivatedServiceTypeEntry(typeName, assemblyName);
aste.ContextAttributes = contextAttributes;
// The assembly name is stored in lowercase to let it be case-insensitive.
String key = EncodeTypeAndAssemblyNames(typeName, assemblyName);
_exportableClasses.Add(key, aste);
} // AddActivatedType
// determines if either a wellknown or activated service type entry
// is associated with the given type name and assembly name
private bool CheckForServiceEntryWithType(String typeName, String asmName)
{
return
CheckForWellKnownServiceEntryWithType(typeName, asmName) ||
ActivationAllowed(typeName, asmName);
} // CheckForServiceEntryWithType
private bool CheckForWellKnownServiceEntryWithType(String typeName, String asmName)
{
foreach (DictionaryEntry entry in _wellKnownExportInfo)
{
WellKnownServiceTypeEntry svc =
(WellKnownServiceTypeEntry)entry.Value;
if (typeName == svc.TypeName)
{
bool match = false;
// need to ignore version while checking
if (asmName == svc.AssemblyName)
match = true;
else
{
// only well known service entry can have version info
if (String.Compare(svc.AssemblyName, 0, asmName, 0, asmName.Length, StringComparison.OrdinalIgnoreCase) == 0)
{
// if asmName != svc.AssemblyName and svc.AssemblyName
// starts with asmName we know that svc.AssemblyName is
// longer. If the next character is a comma, then the
// assembly names match except for version numbers
// which is ok.
if (svc.AssemblyName[asmName.Length] == ',')
match = true;
}
}
// We were trying to redirect
if (match)
return true;
}
}
return false;
} // CheckForWellKnownServiceEntryOfType
// returns true if activation for the type has been redirected.
private bool CheckForRedirectedClientType(String typeName, String asmName)
{
// if asmName has version information, remove it.
int index = asmName.IndexOf(",");
if (index != -1)
asmName = asmName.Substring(0, index);
return
(QueryRemoteActivate(typeName, asmName) != null) ||
(QueryConnect(typeName, asmName) != null);
} // CheckForRedirectedClientType
internal void AddActivatedClientType(ActivatedClientTypeEntry entry)
{
if (CheckForRedirectedClientType(entry.TypeName, entry.AssemblyName))
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_Config_TypeAlreadyRedirected"),
entry.TypeName, entry.AssemblyName));
}
if (CheckForServiceEntryWithType(entry.TypeName, entry.AssemblyName))
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_Config_CantRedirectActivationOfWellKnownService"),
entry.TypeName, entry.AssemblyName));
}
String appUrl = entry.ApplicationUrl;
RemoteAppEntry appEntry = (RemoteAppEntry)_remoteAppInfo[appUrl];
if (appEntry == null)
{
appEntry = new RemoteAppEntry(appUrl, appUrl);
_remoteAppInfo.Add(appUrl, appEntry);
}
if (appEntry != null)
{
entry.CacheRemoteAppEntry(appEntry);
}
String index = EncodeTypeAndAssemblyNames(entry.TypeName, entry.AssemblyName);
_remoteTypeInfo.Add(index, entry);
} // AddActivatedClientType
internal void AddWellKnownClientType(WellKnownClientTypeEntry entry)
{
if (CheckForRedirectedClientType(entry.TypeName, entry.AssemblyName))
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_Config_TypeAlreadyRedirected"),
entry.TypeName, entry.AssemblyName));
}
if (CheckForServiceEntryWithType(entry.TypeName, entry.AssemblyName))
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_Config_CantRedirectActivationOfWellKnownService"),
entry.TypeName, entry.AssemblyName));
}
String appUrl = entry.ApplicationUrl;
RemoteAppEntry appEntry = null;
if (appUrl != null)
{
appEntry = (RemoteAppEntry)_remoteAppInfo[appUrl];
if (appEntry == null)
{
appEntry = new RemoteAppEntry(appUrl, appUrl);
_remoteAppInfo.Add(appUrl, appEntry);
}
}
if (appEntry != null)
entry.CacheRemoteAppEntry(appEntry);
String index = EncodeTypeAndAssemblyNames(entry.TypeName, entry.AssemblyName);
_remoteTypeInfo.Add(index, entry);
} // AddWellKnownClientType
// This is to add programmatically registered well known objects
// so that we keep all this data in one place
[System.Security.SecurityCritical] // auto-generated
internal void AddWellKnownEntry(WellKnownServiceTypeEntry entry)
{
AddWellKnownEntry(entry, true);
}
[System.Security.SecurityCritical] // auto-generated
internal void AddWellKnownEntry(WellKnownServiceTypeEntry entry, bool fReplace)
{
if (CheckForRedirectedClientType(entry.TypeName, entry.AssemblyName))
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_Config_CantUseRedirectedTypeForWellKnownService"),
entry.TypeName, entry.AssemblyName));
}
String key = entry.ObjectUri.ToLower(CultureInfo.InvariantCulture);
if (fReplace)
{
// Registering a well known object twice replaces the old one, so
// we null out the old entry in the identity table after adding
// this one. The identity will be recreated the next time someone
// asks for this object.
_wellKnownExportInfo[key] = entry;
IdentityHolder.RemoveIdentity(entry.ObjectUri);
}
else
{
_wellKnownExportInfo.Add(key, entry);
}
}
//This API exposes a way to get server type information wiihout booting the object
[System.Security.SecurityCritical] // auto-generated
internal Type GetServerTypeForUri(String URI)
{
Contract.Assert(null != URI, "null != URI");
Type serverType = null;
String uriLower = URI.ToLower(CultureInfo.InvariantCulture);
WellKnownServiceTypeEntry entry =
(WellKnownServiceTypeEntry)_wellKnownExportInfo[uriLower];
if(entry != null)
{
serverType = LoadType(entry.TypeName, entry.AssemblyName);
}
return serverType;
}
[System.Security.SecurityCritical] // auto-generated
internal ServerIdentity StartupWellKnownObject(String URI)
{
Contract.Assert(null != URI, "null != URI");
String uriLower = URI.ToLower(CultureInfo.InvariantCulture);
ServerIdentity ident = null;
WellKnownServiceTypeEntry entry =
(WellKnownServiceTypeEntry)_wellKnownExportInfo[uriLower];
if (entry != null)
{
ident = StartupWellKnownObject(
entry.AssemblyName,
entry.TypeName,
entry.ObjectUri,
entry.Mode);
}
return ident;
}
[System.Security.SecurityCritical] // auto-generated
internal ServerIdentity StartupWellKnownObject(
String asmName, String svrTypeName, String URI,
WellKnownObjectMode mode)
{
return StartupWellKnownObject(asmName, svrTypeName, URI, mode, false);
}
[System.Security.SecurityCritical] // auto-generated
internal ServerIdentity StartupWellKnownObject(
String asmName, String svrTypeName, String URI,
WellKnownObjectMode mode,
bool fReplace)
{
lock (s_wkoStartLock)
{
MarshalByRefObject obj = null;
ServerIdentity srvID = null;
// attempt to load the type
Type serverType = LoadType(svrTypeName, asmName);
// make sure the well known object derives from MarshalByRefObject
if(!serverType.IsMarshalByRef)
{
throw new RemotingException(
Environment.GetResourceString("Remoting_WellKnown_MustBeMBR",
svrTypeName));
}
// make sure that no one beat us to creating
// the well known object
srvID = (ServerIdentity)IdentityHolder.ResolveIdentity(URI);
if ((srvID != null) && srvID.IsRemoteDisconnected())
{
IdentityHolder.RemoveIdentity(URI);
srvID = null;
}
if (srvID == null)
{
//WellKnown type instances need to be created under full trust
//since the permission set might have been restricted by the channel
//pipeline.
//This assert is protected by Infrastructure link demands.
s_fullTrust.Assert();
try {
obj = (MarshalByRefObject)Activator.CreateInstance(serverType, true);
if (RemotingServices.IsClientProxy(obj))
{
// The wellknown type is remoted so we must wrap the proxy
// with a local object.
// The redirection proxy masquerades as an object of the appropriate
// type, and forwards incoming messages to the actual proxy.
RedirectionProxy redirectedProxy = new RedirectionProxy(obj, serverType);
redirectedProxy.ObjectMode = mode;
// DevDiv 720951 and 911924:
// 'isInitializing' is propagated into the new ServerIdentity so that other concurrent
// operations that find it in URITable do not use it prematurely.
RemotingServices.MarshalInternal(redirectedProxy, URI, serverType, updateChannelData: true, isInitializing: true);
srvID = (ServerIdentity)IdentityHolder.ResolveIdentity(URI);
Contract.Assert(null != srvID, "null != srvID");
// The redirection proxy handles SingleCall versus Singleton,
// so we always set its mode to Singleton.
srvID.SetSingletonObjectMode();
}
else
if (serverType.IsCOMObject && (mode == WellKnownObjectMode.Singleton))
{
// Singleton COM objects are wrapped, so that they will be
// recreated when an RPC server not available is thrown
// if dllhost.exe is killed.
ComRedirectionProxy comRedirectedProxy = new ComRedirectionProxy(obj, serverType);
// DevDiv 720951 and 911924: isInitializing = true
RemotingServices.MarshalInternal(comRedirectedProxy, URI, serverType, updateChannelData: true, isInitializing: true);
srvID = (ServerIdentity)IdentityHolder.ResolveIdentity(URI);
Contract.Assert(null != srvID, "null != srvID");
// Only singleton COM objects are redirected this way.
srvID.SetSingletonObjectMode();
}
else
{
// make sure the object didn't Marshal itself.
String tempUri = RemotingServices.GetObjectUri(obj);
if (tempUri != null)
{
throw new RemotingException(
String.Format(
CultureInfo.CurrentCulture, Environment.GetResourceString(
"Remoting_WellKnown_CtorCantMarshal"),
URI));
}
// DevDiv 720951 and 911924: isInitializing = true
RemotingServices.MarshalInternal(obj, URI, serverType, updateChannelData: true, isInitializing: true);
srvID = (ServerIdentity)IdentityHolder.ResolveIdentity(URI);
Contract.Assert(null != srvID, "null != srvID");
if (mode == WellKnownObjectMode.SingleCall)
{
// We need to set a special flag in the serverId
// so that every dispatch to this type creates
// a new instance of the server object
srvID.SetSingleCallObjectMode();
}
else
{
srvID.SetSingletonObjectMode();
}
}
}
catch
{
// DevDiv 720951 and 911924:
// An exception thrown in the scope of this attempt to create a
// new ServerIdentity may leave a ServerIdentity instance in the
// URITable that has not been properly initialized. This condition
// has been true for all versions of the framework but was first
// recognized in making this fix in 4.5.3. Ideally, a damaged
// ServerIdentity should be removed from URITable. But due to risk
// and lack of customer reports of a problem, we chose not to fix it.
throw;
}
finally {
// DevDiv 720951 and 911924:
// This flag is cleared only after the new ServerIdentity is completely
// initialized and ready for use. It is done here in the 'finally' to
// ensure all exit paths reset the flag, including exceptions.
if (srvID != null)
{
srvID.IsInitializing = false;
}
SecurityPermission.RevertAssert();
}
}
Contract.Assert(null != srvID, "null != srvID");
return srvID;
}
} // StartupWellKnownObject
[System.Security.SecurityCritical] // auto-generated
internal static Type LoadType(String typeName, String assemblyName)
{
Assembly asm = null;
// All the LoadType callers have been protected by
// Infrastructure LinkDemand, it is safe to assert
// this permission.
// Assembly.Load demands FileIO when the target
// assembly is the same as the executable running.
new FileIOPermission(PermissionState.Unrestricted).Assert();
try {
asm = Assembly.Load(assemblyName);
}
finally {
CodeAccessPermission.RevertAssert();
}
if (asm == null)
{
throw new RemotingException(
Environment.GetResourceString("Remoting_AssemblyLoadFailed",
assemblyName));
}
Type type = asm.GetType(typeName, false, false);
if (type == null)
{
throw new RemotingException(
Environment.GetResourceString("Remoting_BadType",
typeName + ", " + assemblyName));
}
return type;
} // LoadType
}// class RemotingConfigInfo
} // class RemotingConfigHandler
internal class DelayLoadClientChannelEntry
{
private RemotingXmlConfigFileData.ChannelEntry _entry;
private IChannelSender _channel;
private bool _bRegistered;
private bool _ensureSecurity;
internal DelayLoadClientChannelEntry(RemotingXmlConfigFileData.ChannelEntry entry, bool ensureSecurity)
{
_entry = entry;
_channel = null;
_bRegistered = false;
_ensureSecurity = ensureSecurity;
}
internal IChannelSender Channel
{
[System.Security.SecurityCritical] // auto-generated
get
{
// If this method returns null, that means the channel has already been registered.
// NOTE: Access to delay load client entries is synchronized at a higher level.
if (_channel == null)
{
if (!_bRegistered)
{
_channel = (IChannelSender)RemotingConfigHandler.CreateChannelFromConfigEntry(_entry);
_entry = null;
}
}
return _channel;
} // get
} // Channel
internal void RegisterChannel()
{
Contract.Assert(_channel != null, "channel shouldn't be null");
// NOTE: Access to delay load client entries is synchronized at a higher level.
ChannelServices.RegisterChannel(_channel, _ensureSecurity);
_bRegistered = true;
_channel = null;
} // RegisterChannel
} // class DelayLoadChannelEntry
} // namespace
|