New tests.
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel / ServiceHostBase.cs
index 5add53257d0a5960505a1bd4546d649be9de7d99..81b5608aabdaa9e6acbd19776e59d7d5e5c23a3a 100644 (file)
@@ -28,6 +28,7 @@
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Linq;
 using System.ServiceModel.Channels;
 using System.ServiceModel.Configuration;
 using System.ServiceModel.Description;
@@ -37,9 +38,12 @@ using System.Reflection;
 
 namespace System.ServiceModel
 {
-       public abstract class ServiceHostBase
+       public abstract partial class ServiceHostBase
                : CommunicationObject, IExtensibleObject<ServiceHostBase>, IDisposable
        {
+               // It is used for mapping a ServiceHostBase to HttpChannelListener precisely.
+               internal static ServiceHostBase CurrentServiceHostHack;
+
                ServiceCredentials credentials;
                ServiceDescription description;
                UriSchemeKeyedCollection base_addresses;
@@ -67,20 +71,43 @@ namespace System.ServiceModel
                public event EventHandler<UnknownMessageReceivedEventArgs>
                        UnknownMessageReceived;
 
+               internal void OnUnknownMessageReceived (Message message)
+               {
+                       if (UnknownMessageReceived != null)
+                               UnknownMessageReceived (this, new UnknownMessageReceivedEventArgs (message));
+                       else
+                               // FIXME: better be logged
+                               throw new EndpointNotFoundException (String.Format ("The request message has the target '{0}' with action '{1}' which is not reachable in this service contract", message.Headers.To, message.Headers.Action));
+               }
+
                public ReadOnlyCollection<Uri> BaseAddresses {
-                       get { return new ReadOnlyCollection<Uri> (base_addresses.InternalItems); }
+                       get {
+                               if (base_addresses == null)
+                                       base_addresses = new UriSchemeKeyedCollection ();
+                               return new ReadOnlyCollection<Uri> (base_addresses.InternalItems);
+                       }
                }
 
-               internal Uri CreateUri (string sheme, Uri relatieUri) {
-                       Uri baseUri = base_addresses.Contains (sheme) ? base_addresses [sheme] : null;
+               internal Uri CreateUri (string scheme, Uri relativeUri)
+               {
+                       Uri baseUri = base_addresses.Contains (scheme) ? base_addresses [scheme] : null;
 
-                       if (relatieUri == null)
+                       if (relativeUri == null)
                                return baseUri;
-                       if (relatieUri.IsAbsoluteUri)
-                               return relatieUri;
+                       if (relativeUri.IsAbsoluteUri)
+                               return relativeUri;
                        if (baseUri == null)
                                return null;
-                       return new Uri (baseUri, relatieUri);
+                       var s = relativeUri.ToString ();
+                       if (s.Length == 0)
+                               return baseUri;
+                       var l = baseUri.LocalPath;
+                       var r = relativeUri.ToString ();
+
+                       if (l.Length > 0 && l [l.Length - 1] != '/' && r [0] != '/')
+                               return new Uri (String.Concat (baseUri.ToString (), "/", r));
+                       else
+                               return new Uri (String.Concat (baseUri.ToString (), r));
                }
 
                public ChannelDispatcherCollection ChannelDispatchers {
@@ -137,6 +164,13 @@ namespace System.ServiceModel
                        set { flow_limit = value; }
                }
 
+               protected void AddBaseAddress (Uri baseAddress)
+               {
+                       if (base_addresses == null)
+                               throw new InvalidOperationException ("Base addresses must be added before the service description is initialized");
+                       base_addresses.Add (baseAddress);
+               }
+
                public ServiceEndpoint AddServiceEndpoint (
                        string implementedContract, Binding binding, string address)
                {
@@ -151,7 +185,7 @@ namespace System.ServiceModel
                {
                        Uri uri = new Uri (address, UriKind.RelativeOrAbsolute);
                        return AddServiceEndpoint (
-                               implementedContract, binding, uri, uri);
+                               implementedContract, binding, uri, listenUri);
                }
 
                public ServiceEndpoint AddServiceEndpoint (
@@ -166,7 +200,7 @@ namespace System.ServiceModel
                        Uri address, Uri listenUri)
                {
                        EndpointAddress ea = BuildEndpointAddress (address, binding);
-                       ContractDescription cd = GetContract (implementedContract);
+                       ContractDescription cd = GetContract (implementedContract, binding.Namespace == "http://schemas.microsoft.com/ws/2005/02/mex/bindings");
                        if (cd == null)
                                throw new InvalidOperationException (String.Format ("Contract '{0}' was not found in the implemented contracts in this service host.", implementedContract));
                        return AddServiceEndpointCore (cd, binding, ea, listenUri);
@@ -185,36 +219,37 @@ namespace System.ServiceModel
                        return null;
                }
 
-               ContractDescription GetContract (string typeName)
-               {
-                       //FIXME: hack hack hack
-                       ImplementedContracts ["IHttpGetHelpPageAndMetadataContract"] =
-                               ContractDescription.GetContract (typeof (IHttpGetHelpPageAndMetadataContract));
-
-                       // FIXME: As long as I tried, *only* IMetadataExchange
-                       // is the exception case that does not require full
-                       // type name. Hence I treat it as a special case.
-                       if (typeName == ServiceMetadataBehavior.MexContractName) {
-                               if (!Description.Behaviors.Contains (typeof (ServiceMetadataBehavior)) && Array.IndexOf (Description.ServiceType.GetInterfaces (), typeof (IMetadataExchange)) < 0)
-                                       throw new InvalidOperationException (
-                                               "Add ServiceMetadataBehavior to the ServiceHost to add a endpoint for IMetadataExchange contract.");
-                                       
-                               ImplementedContracts [ServiceMetadataBehavior.MexContractName] =
-                                       ContractDescription.GetContract (typeof (IMetadataExchange));
+               ContractDescription mex_contract, help_page_contract;
 
-                               foreach (ContractDescription cd in ImplementedContracts.Values)
-                                       if (cd.ContractType == typeof (IMetadataExchange))
-                                               return cd;
-                               return null;
+               ContractDescription GetContract (string name, bool mexBinding)
+               {
+                       // FIXME: not sure if they should really be special cases.
+                       switch (name) {
+                       case "IHttpGetHelpPageAndMetadataContract":
+                               if (help_page_contract == null)
+                                       help_page_contract = ContractDescription.GetContract (typeof (IHttpGetHelpPageAndMetadataContract));
+                               return help_page_contract;
+                       case "IMetadataExchange":
+                               // this is certainly looking special (or we may 
+                               // be missing something around ServiceMetadataExtension).
+                               // It seems .NET WCF has some "infrastructure"
+                               // endpoints. .NET ServiceHost fails to Open()
+                               // if it was added only IMetadataExchange 
+                               // endpoint (and you'll see the word
+                               // "infrastructure" in the exception message).
+                               if (mexBinding && Description.Behaviors.Find<ServiceMetadataBehavior> () == null)
+                                       break;
+                               if (mex_contract == null)
+                                       mex_contract = ContractDescription.GetContract (typeof (IMetadataExchange));
+                               return mex_contract;
                        }
 
-                       Type type = PopulateType (typeName);
+                       Type type = PopulateType (name);
                        if (type == null)
                                return null;
 
                        foreach (ContractDescription cd in ImplementedContracts.Values) {
-                               // FIXME: This check is a negative side effect 
-                               // of the above hack.
+                               // This check is a negative side effect of the above match-by-name design.
                                if (cd.ContractType == typeof (IMetadataExchange))
                                        continue;
 
@@ -236,7 +271,7 @@ namespace System.ServiceModel
 
                                Uri baseaddr = base_addresses [binding.Scheme];
 
-                               if (!baseaddr.AbsoluteUri.EndsWith ("/"))
+                               if (!baseaddr.AbsoluteUri.EndsWith ("/") && address.OriginalString.Length > 0) // with empty URI it should not add '/' to possible file name of the absolute URI
                                        baseaddr = new Uri (baseaddr.AbsoluteUri + "/");
                                address = new Uri (baseaddr, address);
                        }
@@ -247,7 +282,7 @@ namespace System.ServiceModel
                        ContractDescription cd, Binding binding, EndpointAddress address, Uri listenUri)
                {
                        foreach (ServiceEndpoint e in Description.Endpoints)
-                               if (e.Contract == cd)
+                               if (e.Contract == cd && e.Binding == binding && e.Address == address && e.ListenUri.Equals (listenUri))
                                        return e;
                        ServiceEndpoint se = new ServiceEndpoint (cd, binding, address);
                        se.ListenUri = listenUri.IsAbsoluteUri ? listenUri : new Uri (address.Uri, listenUri);
@@ -255,7 +290,6 @@ namespace System.ServiceModel
                        return se;
                }
 
-               [MonoTODO]
                protected virtual void ApplyConfiguration ()
                {
                        if (Description == null)
@@ -269,26 +303,31 @@ namespace System.ServiceModel
                                //base addresses
                                HostElement host = service.Host;
                                foreach (BaseAddressElement baseAddress in host.BaseAddresses) {
-                                       this.base_addresses.Add (new Uri (baseAddress.BaseAddress));
+                                       AddBaseAddress (new Uri (baseAddress.BaseAddress));
+                               }
+
+                               // behaviors
+                               // TODO: use EvaluationContext of ServiceElement.
+                               ServiceBehaviorElement behavior = ConfigUtil.BehaviorsSection.ServiceBehaviors [service.BehaviorConfiguration];
+                               if (behavior != null) {
+                                       foreach (var bxe in behavior) {
+                                               IServiceBehavior b = (IServiceBehavior) bxe.CreateBehavior ();
+                                               Description.Behaviors.Add (b);
+                                       }
                                }
 
                                // services
                                foreach (ServiceEndpointElement endpoint in service.Endpoints) {
-                                       // FIXME: consider BindingName as well
                                        ServiceEndpoint se = AddServiceEndpoint (
                                                endpoint.Contract,
                                                ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration),
                                                endpoint.Address.ToString ());
-                               }
-                               // behaviors
-                               // TODO: use EvaluationContext of ServiceElement.
-                               ServiceBehaviorElement behavior = ConfigUtil.BehaviorsSection.ServiceBehaviors.Find (service.BehaviorConfiguration);
-                               if (behavior != null) {
-                                       for (int i = 0; i < behavior.Count; i++) {
-                                               BehaviorExtensionElement bxel = behavior [i];
-                                               IServiceBehavior b = (IServiceBehavior) behavior [i].CreateBehavior ();
-                                               if (b != null)
-                                                       Description.Behaviors.Add (b);
+                                       // endpoint behaviors
+                                       EndpointBehaviorElement epbehavior = ConfigUtil.BehaviorsSection.EndpointBehaviors [endpoint.BehaviorConfiguration];
+                                       if (epbehavior != null)
+                                               foreach (var bxe in epbehavior) {
+                                                       IEndpointBehavior b = (IEndpointBehavior) bxe.CreateBehavior ();
+                                                       se.Behaviors.Add (b);
                                        }
                                }
                        }
@@ -317,14 +356,6 @@ namespace System.ServiceModel
                        return ConfigUtil.ServicesSection.Services [serviceType.FullName];                      
                }
 
-               internal ContractDescription GetContract (string name, string ns)
-               {
-                       foreach (ContractDescription d in ImplementedContracts.Values)
-                               if (d.Name == name && d.Namespace == ns)
-                                       return d;
-                       return null;
-               }
-
                protected abstract ServiceDescription CreateDescription (
                        out IDictionary<string,ContractDescription> implementedContracts);
 
@@ -347,17 +378,18 @@ namespace System.ServiceModel
                        //Build all ChannelDispatchers, one dispatcher per user configured EndPoint.
                        //We must keep thet ServiceEndpoints as a seperate collection, since the user
                        //can change the collection in the description during the behaviors events.
-                       Dictionary<ServiceEndpoint, ChannelDispatcher> endPointToDispatcher = new Dictionary<ServiceEndpoint,ChannelDispatcher>();
                        ServiceEndpoint[] endPoints = new ServiceEndpoint[Description.Endpoints.Count];
                        Description.Endpoints.CopyTo (endPoints, 0);
+                       var builder = new DispatcherBuilder (this);
                        foreach (ServiceEndpoint se in endPoints) {
-                               //Let all behaviors add their binding parameters
-                               BindingParameterCollection commonParams =
-                                       new BindingParameterCollection ();
-                               AddBindingParameters (commonParams, se);
-                               ChannelDispatcher channel = BuildChannelDispatcher (se, commonParams);
-                               ChannelDispatchers.Add (channel);                               
-                               endPointToDispatcher[se] = channel;                             
+
+                               var commonParams = new BindingParameterCollection ();
+                               foreach (IServiceBehavior b in Description.Behaviors)
+                                       b.AddBindingParameters (Description, this, Description.Endpoints, commonParams);
+
+                               var channel = builder.BuildChannelDispatcher (Description.ServiceType, se, commonParams);
+                               if (!ChannelDispatchers.Contains (channel))
+                                       ChannelDispatchers.Add (channel);
                        }
 
                        //After the ChannelDispatchers are created, and attached to the service host
@@ -365,8 +397,7 @@ namespace System.ServiceModel
                        foreach (IServiceBehavior b in Description.Behaviors)
                                b.ApplyDispatchBehavior (Description, this);
 
-                       foreach(KeyValuePair<ServiceEndpoint, ChannelDispatcher> val in endPointToDispatcher)
-                               ApplyDispatchBehavior(val.Value, val.Key);                      
+                       builder.ApplyDispatchBehaviors ();
                }
 
                private void ValidateDescription ()
@@ -375,125 +406,9 @@ namespace System.ServiceModel
                                b.Validate (Description, this);
                        foreach (ServiceEndpoint endPoint in Description.Endpoints)
                                endPoint.Validate ();
-               }               
-
-               private void ApplyDispatchBehavior (ChannelDispatcher dispatcher, ServiceEndpoint endPoint) {                   
-                       foreach (IContractBehavior b in endPoint.Contract.Behaviors)
-                               b.ApplyDispatchBehavior (endPoint.Contract, endPoint, dispatcher.Endpoints[0].DispatchRuntime);
-                       foreach (IEndpointBehavior b in endPoint.Behaviors)
-                               b.ApplyDispatchBehavior (endPoint, dispatcher.Endpoints [0]);
-                       foreach (OperationDescription operation in endPoint.Contract.Operations) {
-                               foreach (IOperationBehavior b in operation.Behaviors)
-                                       b.ApplyDispatchBehavior (operation, dispatcher.Endpoints [0].DispatchRuntime.Operations [operation.Name]);
-                       }
 
-               }
-
-               internal ChannelDispatcher BuildChannelDispatcher (ServiceEndpoint se, BindingParameterCollection commonParams)
-               {
-                       //User the binding parameters to build the channel listener and Dispatcher
-                       IChannelListener lf = BuildListener (se, commonParams);
-                       ChannelDispatcher cd = new ChannelDispatcher (
-                               lf, se.Binding.Name);
-                       cd.MessageVersion = se.Binding.MessageVersion;
-                       if (cd.MessageVersion == null)
-                               cd.MessageVersion = MessageVersion.Default;
-
-                       //Attach one EndpointDispacher to the ChannelDispatcher
-                       EndpointDispatcher endpoint_dispatcher =
-                               new EndpointDispatcher (se.Address, se.Contract.Name, se.Contract.Namespace);
-                       endpoint_dispatcher.DispatchRuntime.Type = Description.ServiceType;
-                       endpoint_dispatcher.ContractFilter = GetContractFilter (se.Contract);
-                       endpoint_dispatcher.AddressFilter = new EndpointAddressMessageFilter (se.Address);
-                       endpoint_dispatcher.ChannelDispatcher = cd;
-                       cd.Endpoints.Add (endpoint_dispatcher);
-                       
-                       //Build the dispatch operations
-                       DispatchRuntime db = endpoint_dispatcher.DispatchRuntime;
-                       if (se.Contract.CallbackContractType != null) {
-                               var ccd = ContractDescriptionGenerator.GetCallbackContract (se.Contract.CallbackContractType);
-                               db.CallbackClientRuntime = ccd.CreateClientRuntime ();
-                               db.CallbackClientRuntime.CallbackClientType = ccd.ContractType;
-                       }
-                       foreach (OperationDescription od in se.Contract.Operations)
-                               if (!db.Operations.Contains (od.Name))
-                                       PopulateDispatchOperation (db, od);
-
-                       return cd;
-               }
-
-               private MessageFilter GetContractFilter (ContractDescription contractDescription)
-               {
-                       List<string> actions = new List<string> ();
-                       foreach (OperationDescription od in contractDescription.Operations)
-                               foreach (MessageDescription md in od.Messages)
-                                       if (md.Direction == MessageDirection.Input)
-                                               if (md.Action == "*")
-                                                       return new MatchAllMessageFilter ();
-                                               else
-                                                       actions.Add (md.Action);
-
-                       return new ActionMessageFilter (actions.ToArray ());
-               }
-
-               private void AddBindingParameters (BindingParameterCollection commonParams, ServiceEndpoint endPoint) {
-
-                       commonParams.Add (ChannelProtectionRequirements.CreateFromContract (endPoint.Contract));
-                       foreach (IServiceBehavior b in Description.Behaviors)
-                               b.AddBindingParameters (Description, this, Description.Endpoints, commonParams);
-
-                       foreach (IContractBehavior b in endPoint.Contract.Behaviors)
-                               b.AddBindingParameters (endPoint.Contract, endPoint, commonParams);
-                       foreach (IEndpointBehavior b in endPoint.Behaviors)
-                               b.AddBindingParameters (endPoint, commonParams);
-                       foreach (OperationDescription operation in endPoint.Contract.Operations) {
-                               foreach (IOperationBehavior b in operation.Behaviors)
-                                       b.AddBindingParameters (operation, commonParams);
-                       }
-               }
-
-               void PopulateDispatchOperation (DispatchRuntime db, OperationDescription od) {
-                       string reqA = null, resA = null;
-                       foreach (MessageDescription m in od.Messages) {
-                               if (m.Direction == MessageDirection.Input)
-                                       reqA = m.Action;
-                               else
-                                       resA = m.Action;
-                       }
-                       DispatchOperation o =
-                               od.IsOneWay ?
-                               new DispatchOperation (db, od.Name, reqA) :
-                               new DispatchOperation (db, od.Name, reqA, resA);
-                       bool no_serialized_reply = od.IsOneWay;
-                       foreach (MessageDescription md in od.Messages) {
-                               if (md.Direction == MessageDirection.Input &&
-                                       md.Body.Parts.Count == 1 &&
-                                       md.Body.Parts [0].Type == typeof (Message))
-                                       o.DeserializeRequest = false;
-                               if (md.Direction == MessageDirection.Output &&
-                                       md.Body.ReturnValue != null) {
-                                       if (md.Body.ReturnValue.Type == typeof (Message))
-                                               o.SerializeReply = false;
-                                       else if (md.Body.ReturnValue.Type == typeof (void))
-                                               no_serialized_reply = true;
-                               }
-                       }
-
-                       // Setup Invoker
-                       o.Invoker = new DefaultOperationInvoker (od);
-
-                       // Setup Formater
-                       o.Formatter = BaseMessagesFormatter.Create (od);
-
-                       if (o.Action == "*" && (o.IsOneWay || o.ReplyAction == "*")) {
-                               //Signature : Message  (Message)
-                               //          : void  (Message)
-                               //FIXME: void (IChannel)
-                               if (!o.DeserializeRequest && (!o.SerializeReply || no_serialized_reply)) // what is this double-ish check for?
-                                       db.UnhandledDispatchOperation = o;
-                       }
-
-                       db.Operations.Add (o);
+                       if (Description.Endpoints.FirstOrDefault (e => e.Contract != mex_contract) == null)
+                               throw new InvalidOperationException ("The ServiceHost must have at least one application endpoint (that does not include metadata exchange contract) defined by either configuration, behaviors or call to AddServiceEndpoint methods.");
                }
 
                [MonoTODO]
@@ -502,36 +417,6 @@ namespace System.ServiceModel
                        ServicesSection services = ConfigUtil.ServicesSection;
                }
 
-               void DoOpen (TimeSpan timeout)
-               {
-                       foreach (var cd in ChannelDispatchers) {
-                               cd.Open (timeout);
-                               // This is likely hack.
-                               if (cd is ChannelDispatcher)
-                                       ((ChannelDispatcher) cd).StartLoop ();
-                       }
-               }
-
-               IChannelListener BuildListener (ServiceEndpoint se,
-                       BindingParameterCollection pl)
-               {
-                       Binding b = se.Binding;
-                       if (b.CanBuildChannelListener<IReplySessionChannel> (pl))
-                               return b.BuildChannelListener<IReplySessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
-                       if (b.CanBuildChannelListener<IReplyChannel> (pl))
-                               return b.BuildChannelListener<IReplyChannel> (se.ListenUri, "", se.ListenUriMode, pl);
-                       if (b.CanBuildChannelListener<IInputSessionChannel> (pl))
-                               return b.BuildChannelListener<IInputSessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
-                       if (b.CanBuildChannelListener<IInputChannel> (pl))
-                               return b.BuildChannelListener<IInputChannel> (se.ListenUri, "", se.ListenUriMode, pl);
-
-                       if (b.CanBuildChannelListener<IDuplexChannel> (pl))
-                               return b.BuildChannelListener<IDuplexChannel> (se.ListenUri, "", se.ListenUriMode, pl);
-                       if (b.CanBuildChannelListener<IDuplexSessionChannel> (pl))
-                               return b.BuildChannelListener<IDuplexSessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
-                       throw new InvalidOperationException ("None of the listener channel types is supported");
-               }
-
                [MonoTODO]
                protected override sealed void OnAbort ()
                {
@@ -577,8 +462,13 @@ namespace System.ServiceModel
 
                protected override sealed void OnOpen (TimeSpan timeout)
                {
+                       DateTime start = DateTime.Now;
                        InitializeRuntime ();
-                       DoOpen (timeout);
+                       foreach (var cd in ChannelDispatchers)
+                               cd.Open (timeout - (DateTime.Now - start));
+
+                       // FIXME: remove this hack. It should make sure that each ChannelDispatcher's loop has started, using WaitHandle.WaitAll() or something similar.
+                       System.Threading.Thread.Sleep (300);
                }
 
                protected override void OnEndClose (IAsyncResult result)
@@ -597,6 +487,7 @@ namespace System.ServiceModel
 
                protected override void OnOpened ()
                {
+                       base.OnOpened ();
                }
 
                [MonoTODO]
@@ -693,4 +584,109 @@ namespace System.ServiceModel
                */
        }
 
+       /// <summary>
+       ///  Builds ChannelDispatchers as appropriate to service the service endpoints. 
+       /// </summary>
+       /// <remarks>Will re-use ChannelDispatchers when two endpoint uris are the same</remarks>
+       partial class DispatcherBuilder
+       {
+               ServiceHostBase host;
+
+               public DispatcherBuilder (ServiceHostBase host)
+               {
+                       this.host = host;
+               }
+
+               List<ChannelDispatcher> built_dispatchers = new List<ChannelDispatcher> ();
+               Dictionary<ServiceEndpoint, EndpointDispatcher> ep_to_dispatcher_ep = new Dictionary<ServiceEndpoint, EndpointDispatcher> ();
+
+               internal static Action<ChannelDispatcher> ChannelDispatcherSetter;
+
+               internal ChannelDispatcher BuildChannelDispatcher (Type serviceType, ServiceEndpoint se, BindingParameterCollection commonParams)
+               {
+                       //Let all behaviors add their binding parameters
+                       AddBindingParameters (commonParams, se);
+                       
+                       // See if there's an existing channel that matches this endpoint
+                       ChannelDispatcher cd = FindExistingDispatcher (se);
+                       EndpointDispatcher ep;
+                       if (cd != null) {
+                               ep = cd.InitializeServiceEndpoint (serviceType, se);
+                       } else {
+                               // Use the binding parameters to build the channel listener and Dispatcher.
+                               lock (HttpTransportBindingElement.ListenerBuildLock) {
+                                       ServiceHostBase.CurrentServiceHostHack = host;
+                                       IChannelListener lf = BuildListener (se, commonParams);
+                                       cd = new ChannelDispatcher (lf, se.Binding.Name);
+                                       if (ChannelDispatcherSetter != null) {
+                                               ChannelDispatcherSetter (cd);
+                                               ChannelDispatcherSetter = null;
+                                       }
+                                       ServiceHostBase.CurrentServiceHostHack = null;
+                               }
+                               ep = cd.InitializeServiceEndpoint (serviceType, se);
+                               built_dispatchers.Add (cd);
+                       }
+                       ep_to_dispatcher_ep[se] = ep;
+                       return cd;
+               }
+               
+               ChannelDispatcher FindExistingDispatcher (ServiceEndpoint se)
+               {
+                       return built_dispatchers.FirstOrDefault ((ChannelDispatcher cd) => (cd.Listener.Uri.Equals (se.ListenUri)) && cd.MessageVersion.Equals (se.Binding.MessageVersion));
+               }
+
+               internal void ApplyDispatchBehaviors ()
+               {
+                       foreach (KeyValuePair<ServiceEndpoint, EndpointDispatcher> val in ep_to_dispatcher_ep)
+                               ApplyDispatchBehavior (val.Value, val.Key);
+               }
+               
+               private void ApplyDispatchBehavior (EndpointDispatcher ed, ServiceEndpoint endPoint)
+               {
+                       foreach (IContractBehavior b in endPoint.Contract.Behaviors)
+                               b.ApplyDispatchBehavior (endPoint.Contract, endPoint, ed.DispatchRuntime);
+                       foreach (IEndpointBehavior b in endPoint.Behaviors)
+                               b.ApplyDispatchBehavior (endPoint, ed);
+                       foreach (OperationDescription operation in endPoint.Contract.Operations) {
+                               foreach (IOperationBehavior b in operation.Behaviors)
+                                       b.ApplyDispatchBehavior (operation, ed.DispatchRuntime.Operations [operation.Name]);
+                       }
+
+               }
+
+               private void AddBindingParameters (BindingParameterCollection commonParams, ServiceEndpoint endPoint) {
+
+                       commonParams.Add (ChannelProtectionRequirements.CreateFromContract (endPoint.Contract));
+
+                       foreach (IContractBehavior b in endPoint.Contract.Behaviors)
+                               b.AddBindingParameters (endPoint.Contract, endPoint, commonParams);
+                       foreach (IEndpointBehavior b in endPoint.Behaviors)
+                               b.AddBindingParameters (endPoint, commonParams);
+                       foreach (OperationDescription operation in endPoint.Contract.Operations) {
+                               foreach (IOperationBehavior b in operation.Behaviors)
+                                       b.AddBindingParameters (operation, commonParams);
+                       }
+               }
+
+               static IChannelListener BuildListener (ServiceEndpoint se,
+                       BindingParameterCollection pl)
+               {
+                       Binding b = se.Binding;
+                       if (b.CanBuildChannelListener<IReplySessionChannel> (pl))
+                               return b.BuildChannelListener<IReplySessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
+                       if (b.CanBuildChannelListener<IReplyChannel> (pl))
+                               return b.BuildChannelListener<IReplyChannel> (se.ListenUri, "", se.ListenUriMode, pl);
+                       if (b.CanBuildChannelListener<IInputSessionChannel> (pl))
+                               return b.BuildChannelListener<IInputSessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
+                       if (b.CanBuildChannelListener<IInputChannel> (pl))
+                               return b.BuildChannelListener<IInputChannel> (se.ListenUri, "", se.ListenUriMode, pl);
+
+                       if (b.CanBuildChannelListener<IDuplexChannel> (pl))
+                               return b.BuildChannelListener<IDuplexChannel> (se.ListenUri, "", se.ListenUriMode, pl);
+                       if (b.CanBuildChannelListener<IDuplexSessionChannel> (pl))
+                               return b.BuildChannelListener<IDuplexSessionChannel> (se.ListenUri, "", se.ListenUriMode, pl);
+                       throw new InvalidOperationException ("None of the listener channel types is supported");
+               }
+       }
 }