2 // System.Runtime.Remoting.RemotingConfiguration.cs
4 // Author: Jaime Anguiano Olarra (jaime@gnome.org)
5 // Lluis Sanchez Gual (lluis@ideary.com)
7 // (C) 2002, Jaime Anguiano Olarra
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Globalization;
36 using System.Reflection;
37 using System.Collections;
38 using System.Runtime.Remoting.Activation;
39 using System.Runtime.Remoting.Channels;
40 using System.Runtime.Remoting.Lifetime;
43 namespace System.Runtime.Remoting
45 [System.Runtime.InteropServices.ComVisible (true)]
46 public static class RemotingConfiguration
49 static string applicationID = null;
50 static string applicationName = null;
51 // static string configFile = "";
52 // static SmallXmlParser parser = null;
53 static string processGuid = null;
54 static bool defaultConfigRead = false;
55 static bool defaultDelayedConfigRead = false;
56 static string _errorMode;
58 static Hashtable wellKnownClientEntries = new Hashtable();
59 static Hashtable activatedClientEntries = new Hashtable();
60 static Hashtable wellKnownServiceEntries = new Hashtable();
61 static Hashtable activatedServiceEntries = new Hashtable();
63 static Hashtable channelTemplates = new Hashtable ();
64 static Hashtable clientProviderTemplates = new Hashtable ();
65 static Hashtable serverProviderTemplates = new Hashtable ();
68 // At this time the ID will be the application name
69 public static string ApplicationId
73 applicationID = ApplicationName;
78 public static string ApplicationName
80 get { return applicationName; }
81 set { applicationName = value; }
85 public static CustomErrorsModes CustomErrorsMode
87 get { throw new NotImplementedException (); }
88 set { throw new NotImplementedException (); }
91 public static string ProcessId
94 if (processGuid == null)
95 processGuid = AppDomain.GetProcessGuid ();
104 [MonoTODO ("ensureSecurity support has not been implemented")]
105 public static void Configure (string filename, bool ensureSecurity)
107 lock (channelTemplates) {
108 if (!defaultConfigRead) {
109 var bundled = Environment.GetBundledMachineConfig ();
111 ReadConfigString (bundled);
113 if (File.Exists (Environment.GetMachineConfigPath ()))
114 ReadConfigFile (Environment.GetMachineConfigPath ());
115 defaultConfigRead = true;
118 if (filename != null)
119 ReadConfigFile (filename);
123 [Obsolete ("Use Configure(String,Boolean)")]
124 public static void Configure (string filename)
126 Configure (filename, false);
129 private static void ReadConfigString (string filename)
133 SmallXmlParser parser = new SmallXmlParser ();
134 using (TextReader rreader = new StringReader (filename)) {
135 ConfigHandler handler = new ConfigHandler (false);
136 parser.Parse (rreader, handler);
141 throw new RemotingException ("Configuration string could not be loaded: " + ex.Message, ex);
145 private static void ReadConfigFile (string filename)
149 SmallXmlParser parser = new SmallXmlParser ();
150 using (TextReader rreader = new StreamReader (filename)) {
151 ConfigHandler handler = new ConfigHandler (false);
152 parser.Parse (rreader, handler);
157 throw new RemotingException ("Configuration file '" + filename + "' could not be loaded: " + ex.Message, ex);
161 internal static void LoadDefaultDelayedChannels ()
163 lock (channelTemplates)
165 if (defaultDelayedConfigRead || defaultConfigRead) return;
167 SmallXmlParser parser = new SmallXmlParser ();
168 using (TextReader rreader = new StreamReader (Environment.GetMachineConfigPath ())) {
169 ConfigHandler handler = new ConfigHandler (true);
170 parser.Parse (rreader, handler);
172 defaultDelayedConfigRead = true;
176 public static ActivatedClientTypeEntry[] GetRegisteredActivatedClientTypes ()
178 lock (channelTemplates)
180 ActivatedClientTypeEntry[] entries = new ActivatedClientTypeEntry[activatedClientEntries.Count];
181 activatedClientEntries.Values.CopyTo (entries,0);
186 public static ActivatedServiceTypeEntry[] GetRegisteredActivatedServiceTypes ()
188 lock (channelTemplates)
190 ActivatedServiceTypeEntry[] entries = new ActivatedServiceTypeEntry[activatedServiceEntries.Count];
191 activatedServiceEntries.Values.CopyTo (entries,0);
196 public static WellKnownClientTypeEntry[] GetRegisteredWellKnownClientTypes ()
198 lock (channelTemplates)
200 WellKnownClientTypeEntry[] entries = new WellKnownClientTypeEntry[wellKnownClientEntries.Count];
201 wellKnownClientEntries.Values.CopyTo (entries,0);
206 public static WellKnownServiceTypeEntry[] GetRegisteredWellKnownServiceTypes ()
208 lock (channelTemplates)
210 WellKnownServiceTypeEntry[] entries = new WellKnownServiceTypeEntry[wellKnownServiceEntries.Count];
211 wellKnownServiceEntries.Values.CopyTo (entries,0);
216 public static bool IsActivationAllowed (Type svrType)
218 lock (channelTemplates)
220 return activatedServiceEntries.ContainsKey (svrType);
224 public static ActivatedClientTypeEntry IsRemotelyActivatedClientType (Type svrType)
226 lock (channelTemplates)
228 return activatedClientEntries [svrType] as ActivatedClientTypeEntry;
232 public static ActivatedClientTypeEntry IsRemotelyActivatedClientType (string typeName, string assemblyName)
234 return IsRemotelyActivatedClientType (Assembly.Load(assemblyName).GetType (typeName));
237 public static WellKnownClientTypeEntry IsWellKnownClientType (Type svrType)
239 lock (channelTemplates)
241 return wellKnownClientEntries [svrType] as WellKnownClientTypeEntry;
245 public static WellKnownClientTypeEntry IsWellKnownClientType (string typeName, string assemblyName)
247 return IsWellKnownClientType (Assembly.Load(assemblyName).GetType (typeName));
250 public static void RegisterActivatedClientType (ActivatedClientTypeEntry entry)
252 lock (channelTemplates)
254 if (wellKnownClientEntries.ContainsKey (entry.ObjectType) || activatedClientEntries.ContainsKey (entry.ObjectType))
255 throw new RemotingException ("Attempt to redirect activation of type '" + entry.ObjectType.FullName + "' which is already redirected.");
257 activatedClientEntries[entry.ObjectType] = entry;
258 ActivationServices.EnableProxyActivation (entry.ObjectType, true);
262 public static void RegisterActivatedClientType (Type type, string appUrl)
264 if (type == null) throw new ArgumentNullException ("type");
265 if (appUrl == null) throw new ArgumentNullException ("appUrl");
267 RegisterActivatedClientType (new ActivatedClientTypeEntry (type, appUrl));
270 public static void RegisterActivatedServiceType (ActivatedServiceTypeEntry entry)
272 lock (channelTemplates)
274 activatedServiceEntries.Add (entry.ObjectType, entry);
278 public static void RegisterActivatedServiceType (Type type)
280 RegisterActivatedServiceType (new ActivatedServiceTypeEntry (type));
283 public static void RegisterWellKnownClientType (Type type, string objectUrl)
285 if (type == null) throw new ArgumentNullException ("type");
286 if (objectUrl == null) throw new ArgumentNullException ("objectUrl");
288 RegisterWellKnownClientType (new WellKnownClientTypeEntry (type, objectUrl));
291 public static void RegisterWellKnownClientType (WellKnownClientTypeEntry entry)
293 lock (channelTemplates)
295 if (wellKnownClientEntries.ContainsKey (entry.ObjectType) || activatedClientEntries.ContainsKey (entry.ObjectType))
296 throw new RemotingException ("Attempt to redirect activation of type '" + entry.ObjectType.FullName + "' which is already redirected.");
298 wellKnownClientEntries[entry.ObjectType] = entry;
299 ActivationServices.EnableProxyActivation (entry.ObjectType, true);
303 public static void RegisterWellKnownServiceType (Type type, string objectUri, WellKnownObjectMode mode)
305 RegisterWellKnownServiceType (new WellKnownServiceTypeEntry (type, objectUri, mode));
308 public static void RegisterWellKnownServiceType (WellKnownServiceTypeEntry entry)
310 lock (channelTemplates)
312 wellKnownServiceEntries [entry.ObjectUri] = entry;
313 RemotingServices.CreateWellKnownServerIdentity (entry.ObjectType, entry.ObjectUri, entry.Mode);
317 internal static void RegisterChannelTemplate (ChannelData channel)
319 channelTemplates [channel.Id] = channel;
322 internal static void RegisterClientProviderTemplate (ProviderData prov)
324 clientProviderTemplates [prov.Id] = prov;
327 internal static void RegisterServerProviderTemplate (ProviderData prov)
329 serverProviderTemplates [prov.Id] = prov;
332 internal static void RegisterChannels (ArrayList channels, bool onlyDelayed)
334 foreach (ChannelData channel in channels)
336 if (onlyDelayed && channel.DelayLoadAsClientChannel != "true")
339 if (defaultDelayedConfigRead && channel.DelayLoadAsClientChannel == "true")
342 if (channel.Ref != null)
344 ChannelData template = (ChannelData) channelTemplates [channel.Ref];
345 if (template == null) throw new RemotingException ("Channel template '" + channel.Ref + "' not found");
346 channel.CopyFrom (template);
349 foreach (ProviderData prov in channel.ServerProviders)
351 if (prov.Ref != null)
353 ProviderData template = (ProviderData) serverProviderTemplates [prov.Ref];
354 if (template == null) throw new RemotingException ("Provider template '" + prov.Ref + "' not found");
355 prov.CopyFrom (template);
359 foreach (ProviderData prov in channel.ClientProviders)
361 if (prov.Ref != null)
363 ProviderData template = (ProviderData) clientProviderTemplates [prov.Ref];
364 if (template == null) throw new RemotingException ("Provider template '" + prov.Ref + "' not found");
365 prov.CopyFrom (template);
369 ChannelServices.RegisterChannelConfig (channel);
373 internal static void RegisterTypes (ArrayList types)
375 foreach (TypeEntry type in types)
377 if (type is ActivatedClientTypeEntry)
378 RegisterActivatedClientType ((ActivatedClientTypeEntry)type);
379 else if (type is ActivatedServiceTypeEntry)
380 RegisterActivatedServiceType ((ActivatedServiceTypeEntry)type);
381 else if (type is WellKnownClientTypeEntry)
382 RegisterWellKnownClientType ((WellKnownClientTypeEntry)type);
383 else if (type is WellKnownServiceTypeEntry)
384 RegisterWellKnownServiceType ((WellKnownServiceTypeEntry)type);
388 public static bool CustomErrorsEnabled (bool isLocalRequest)
390 if (_errorMode == "off") return false;
391 if (_errorMode == "on") return true;
392 return !isLocalRequest;
395 internal static void SetCustomErrorsMode (string mode)
398 throw new RemotingException ("mode attribute is required");
400 // the mode is case insensitive
401 string m = mode.ToLower ();
403 if (m != "on" && m != "off" && m != "remoteonly")
404 throw new RemotingException ("Invalid custom error mode: " + mode);
410 /***************************************************************
411 * Internal classes used by RemotingConfiguration.Configure () *
412 ***************************************************************/
414 internal class ConfigHandler : SmallXmlParser.IContentHandler
416 ArrayList typeEntries = new ArrayList ();
417 ArrayList channelInstances = new ArrayList ();
419 ChannelData currentChannel = null;
420 Stack currentProviderData = null;
422 string currentClientUrl = null;
425 string currentXmlPath = "";
426 bool onlyDelayedChannels;
428 public ConfigHandler (bool onlyDelayedChannels)
430 this.onlyDelayedChannels = onlyDelayedChannels;
433 void ValidatePath (string element, params string[] paths)
435 foreach (string path in paths)
436 if (CheckPath (path)) return;
438 throw new RemotingException ("Element " + element + " not allowed in this context");
441 bool CheckPath (string path)
443 CompareInfo ci = CultureInfo.InvariantCulture.CompareInfo;
444 if (ci.IsPrefix (path, "/", CompareOptions.Ordinal))
445 return path == currentXmlPath;
447 return ci.IsSuffix (currentXmlPath, path, CompareOptions.Ordinal);
450 public void OnStartParsing (SmallXmlParser parser) {}
452 public void OnProcessingInstruction (string name, string text) {}
454 public void OnIgnorableWhitespace (string s) {}
456 public void OnStartElement (string name, SmallXmlParser.IAttrList attrs)
460 if (currentXmlPath.StartsWith ("/configuration/system.runtime.remoting"))
461 ParseElement (name, attrs);
463 currentXmlPath += "/" + name;
467 throw new RemotingException ("Error in element " + name + ": " + ex.Message, ex);
471 public void ParseElement (string name, SmallXmlParser.IAttrList attrs)
473 if (currentProviderData != null)
475 ReadCustomProviderData (name, attrs);
482 ValidatePath (name, "system.runtime.remoting");
483 if (attrs.Names.Length > 0)
484 appName = attrs.Values[0];
488 ValidatePath (name, "application");
489 ReadLifetine (attrs);
493 ValidatePath (name, "system.runtime.remoting", "application");
497 ValidatePath (name, "channels");
498 if (currentXmlPath.IndexOf ("application") != -1)
499 ReadChannel (attrs, false);
501 ReadChannel (attrs, true);
504 case "serverProviders":
505 ValidatePath (name, "channelSinkProviders", "channel");
508 case "clientProviders":
509 ValidatePath (name, "channelSinkProviders", "channel");
516 if (CheckPath ("application/channels/channel/serverProviders") ||
517 CheckPath ("channels/channel/serverProviders"))
519 prov = ReadProvider (name, attrs, false);
520 currentChannel.ServerProviders.Add (prov);
522 else if (CheckPath ("application/channels/channel/clientProviders") ||
523 CheckPath ("channels/channel/clientProviders"))
525 prov = ReadProvider (name, attrs, false);
526 currentChannel.ClientProviders.Add (prov);
528 else if (CheckPath ("channelSinkProviders/serverProviders"))
530 prov = ReadProvider (name, attrs, true);
531 RemotingConfiguration.RegisterServerProviderTemplate (prov);
533 else if (CheckPath ("channelSinkProviders/clientProviders"))
535 prov = ReadProvider (name, attrs, true);
536 RemotingConfiguration.RegisterClientProviderTemplate (prov);
543 ValidatePath (name, "application");
544 currentClientUrl = attrs.GetValue ("url");
548 ValidatePath (name, "application");
552 ValidatePath (name, "client", "service");
553 if (CheckPath ("client"))
554 ReadClientWellKnown (attrs);
556 ReadServiceWellKnown (attrs);
560 ValidatePath (name, "client", "service");
561 if (CheckPath ("client"))
562 ReadClientActivated (attrs);
564 ReadServiceActivated (attrs);
568 ValidatePath (name, "application");
571 case "interopXmlType":
572 ValidatePath (name, "soapInterop");
573 ReadInteropXml (attrs, false);
576 case "interopXmlElement":
577 ValidatePath (name, "soapInterop");
578 ReadInteropXml (attrs, false);
582 ValidatePath (name, "soapInterop");
587 ValidatePath (name, "system.runtime.remoting");
590 case "channelSinkProviders":
591 ValidatePath (name, "system.runtime.remoting");
595 ValidatePath (name, "system.runtime.remoting");
596 RemotingConfiguration.SetCustomErrorsMode (attrs.GetValue ("mode"));
600 throw new RemotingException ("Element '" + name + "' is not valid in system.remoting.configuration section");
604 public void OnEndElement (string name)
606 if (currentProviderData != null)
608 currentProviderData.Pop ();
609 if (currentProviderData.Count == 0)
610 currentProviderData = null;
613 currentXmlPath = currentXmlPath.Substring (0, currentXmlPath.Length - name.Length - 1);
616 void ReadCustomProviderData (string name, SmallXmlParser.IAttrList attrs)
618 SinkProviderData parent = (SinkProviderData) currentProviderData.Peek ();
620 SinkProviderData data = new SinkProviderData (name);
621 for (int i=0; i < attrs.Names.Length; ++i)
622 data.Properties [attrs.Names[i]] = attrs.GetValue (i);
624 parent.Children.Add (data);
625 currentProviderData.Push (data);
628 void ReadLifetine (SmallXmlParser.IAttrList attrs)
630 for (int i=0; i < attrs.Names.Length; ++i) {
631 switch (attrs.Names[i]) {
633 LifetimeServices.LeaseTime = ParseTime (attrs.GetValue(i));
635 case "sponsorshipTimeout":
636 LifetimeServices.SponsorshipTimeout = ParseTime (attrs.GetValue(i));
638 case "renewOnCallTime":
639 LifetimeServices.RenewOnCallTime = ParseTime (attrs.GetValue(i));
641 case "leaseManagerPollTime":
642 LifetimeServices.LeaseManagerPollTime = ParseTime (attrs.GetValue(i));
645 throw new RemotingException ("Invalid attribute: " + attrs.Names[i]);
650 TimeSpan ParseTime (string s)
652 if (s == "" || s == null) throw new RemotingException ("Invalid time value");
654 int i = s.IndexOfAny (new char[] { 'D','H','M','S' });
660 unit = s.Substring (i);
661 s = s.Substring (0,i);
666 val = double.Parse (s);
669 throw new RemotingException ("Invalid time value: " + s);
672 if (unit == "D") return TimeSpan.FromDays (val);
673 if (unit == "H") return TimeSpan.FromHours (val);
674 if (unit == "M") return TimeSpan.FromMinutes (val);
675 if (unit == "S") return TimeSpan.FromSeconds (val);
676 if (unit == "MS") return TimeSpan.FromMilliseconds (val);
677 throw new RemotingException ("Invalid time unit: " + unit);
680 void ReadChannel (SmallXmlParser.IAttrList attrs, bool isTemplate)
682 ChannelData channel = new ChannelData ();
684 for (int i=0; i < attrs.Names.Length; ++i)
686 string at = attrs.Names[i];
687 string val = attrs.Values[i];
689 if (at == "ref" && !isTemplate)
691 else if (at == "delayLoadAsClientChannel")
692 channel.DelayLoadAsClientChannel = val;
693 else if (at == "id" && isTemplate)
695 else if (at == "type")
698 channel.CustomProperties.Add (at, val);
703 if (channel.Id == null) throw new RemotingException ("id attribute is required");
704 if (channel.Type == null) throw new RemotingException ("id attribute is required");
705 RemotingConfiguration.RegisterChannelTemplate (channel);
708 channelInstances.Add (channel);
710 currentChannel = channel;
713 ProviderData ReadProvider (string name, SmallXmlParser.IAttrList attrs, bool isTemplate)
715 ProviderData prov = (name == "provider") ? new ProviderData () : new FormatterData ();
716 SinkProviderData data = new SinkProviderData ("root");
717 prov.CustomData = data.Children;
719 currentProviderData = new Stack ();
720 currentProviderData.Push (data);
722 for (int i=0; i < attrs.Names.Length; ++i)
724 string at = attrs.Names[i];
725 string val = attrs.Values[i];
727 if (at == "id" && isTemplate)
729 else if (at == "type")
731 else if (at == "ref" && !isTemplate)
734 prov.CustomProperties.Add (at, val);
737 if (prov.Id == null && isTemplate) throw new RemotingException ("id attribute is required");
741 void ReadClientActivated (SmallXmlParser.IAttrList attrs)
743 string type = GetNotNull (attrs, "type");
744 string assm = ExtractAssembly (ref type);
746 if (currentClientUrl == null || currentClientUrl == "")
747 throw new RemotingException ("url attribute is required in client element when it contains activated entries");
749 typeEntries.Add (new ActivatedClientTypeEntry (type, assm, currentClientUrl));
752 void ReadServiceActivated (SmallXmlParser.IAttrList attrs)
754 string type = GetNotNull (attrs, "type");
755 string assm = ExtractAssembly (ref type);
757 typeEntries.Add (new ActivatedServiceTypeEntry (type, assm));
760 void ReadClientWellKnown (SmallXmlParser.IAttrList attrs)
762 string url = GetNotNull (attrs, "url");
763 string type = GetNotNull (attrs, "type");
764 string assm = ExtractAssembly (ref type);
766 typeEntries.Add (new WellKnownClientTypeEntry (type, assm, url));
769 void ReadServiceWellKnown (SmallXmlParser.IAttrList attrs)
771 string objectUri = GetNotNull (attrs, "objectUri");
772 string smode = GetNotNull (attrs, "mode");
773 string type = GetNotNull (attrs, "type");
774 string assm = ExtractAssembly (ref type);
776 WellKnownObjectMode mode;
777 if (smode == "SingleCall") mode = WellKnownObjectMode.SingleCall;
778 else if (smode == "Singleton") mode = WellKnownObjectMode.Singleton;
779 else throw new RemotingException ("wellknown object mode '" + smode + "' is invalid");
781 typeEntries.Add (new WellKnownServiceTypeEntry (type, assm, objectUri, mode));
784 void ReadInteropXml (SmallXmlParser.IAttrList attrs, bool isElement)
786 Type t = Type.GetType (GetNotNull (attrs, "clr"));
787 string[] xmlName = GetNotNull (attrs, "xml").Split (',');
788 string localName = xmlName [0].Trim ();
789 string ns = xmlName.Length > 0 ? xmlName[1].Trim() : null;
791 if (isElement) SoapServices.RegisterInteropXmlElement (localName, ns, t);
792 else SoapServices.RegisterInteropXmlType (localName, ns, t);
795 void ReadPreload (SmallXmlParser.IAttrList attrs)
797 string type = attrs.GetValue ("type");
798 string assm = attrs.GetValue ("assembly");
800 if (type != null && assm != null)
801 throw new RemotingException ("Type and assembly attributes cannot be specified together");
804 SoapServices.PreLoad (Type.GetType (type));
805 else if (assm != null)
806 SoapServices.PreLoad (Assembly.Load (assm));
808 throw new RemotingException ("Either type or assembly attributes must be specified");
811 string GetNotNull (SmallXmlParser.IAttrList attrs, string name)
813 string value = attrs.GetValue (name);
814 if (value == null || value == "")
815 throw new RemotingException (name + " attribute is required");
819 string ExtractAssembly (ref string type)
821 int i = type.IndexOf (',');
822 if (i == -1) return "";
824 string asm = type.Substring (i+1).Trim();
825 type = type.Substring (0, i).Trim();
829 public void OnChars (string ch) {}
831 public void OnEndParsing (SmallXmlParser parser)
833 RemotingConfiguration.RegisterChannels (channelInstances, onlyDelayedChannels);
834 if (appName != null) RemotingConfiguration.ApplicationName = appName;
836 if (!onlyDelayedChannels)
837 RemotingConfiguration.RegisterTypes (typeEntries);
842 /*******************************************************************
843 * Internal data structures used by ConfigHandler, to store *
844 * machine.config's remoting related data. *
845 * If having them implemented this way, makes configuration too *
846 * slow, we can use string arrays. *
847 *******************************************************************/
849 internal class ChannelData {
851 internal string Type;
853 internal string DelayLoadAsClientChannel;
855 ArrayList _serverProviders = new ArrayList ();
856 ArrayList _clientProviders = new ArrayList ();
857 Hashtable _customProperties = new Hashtable ();
859 internal ArrayList ServerProviders {
861 if (_serverProviders == null) _serverProviders = new ArrayList ();
862 return _serverProviders;
866 public ArrayList ClientProviders {
868 if (_clientProviders == null) _clientProviders = new ArrayList ();
869 return _clientProviders;
873 public Hashtable CustomProperties {
875 if (_customProperties == null) _customProperties = new Hashtable ();
876 return _customProperties;
880 public void CopyFrom (ChannelData other)
882 if (Ref == null) Ref = other.Ref;
883 if (Id == null) Id = other.Id;
884 if (Type == null) Type = other.Type;
885 if (DelayLoadAsClientChannel == null) DelayLoadAsClientChannel = other.DelayLoadAsClientChannel;
887 if (other._customProperties != null)
889 foreach (DictionaryEntry entry in other._customProperties)
890 if (!CustomProperties.ContainsKey (entry.Key))
891 CustomProperties [entry.Key] = entry.Value;
894 if (_serverProviders == null && other._serverProviders != null)
896 foreach (ProviderData prov in other._serverProviders)
898 ProviderData np = new ProviderData();
900 ServerProviders.Add (np);
904 if (_clientProviders == null && other._clientProviders != null)
906 foreach (ProviderData prov in other._clientProviders)
908 ProviderData np = new ProviderData();
910 ClientProviders.Add (np);
916 internal class ProviderData {
918 internal string Type;
921 internal Hashtable CustomProperties = new Hashtable ();
922 internal IList CustomData;
924 public void CopyFrom (ProviderData other)
926 if (Ref == null) Ref = other.Ref;
927 if (Id == null) Id = other.Id;
928 if (Type == null) Type = other.Type;
930 foreach (DictionaryEntry entry in other.CustomProperties)
931 if (!CustomProperties.ContainsKey (entry.Key))
932 CustomProperties [entry.Key] = entry.Value;
934 if (other.CustomData != null)
936 if (CustomData == null) CustomData = new ArrayList ();
937 foreach (SinkProviderData data in other.CustomData)
938 CustomData.Add (data);
943 internal class FormatterData: ProviderData {