Merge pull request #4453 from lambdageek/bug-49721
[mono.git] / mcs / class / System.ServiceModel / System.ServiceModel / ServiceHostBase.cs
index 9d3d7c430d1145572ed653d13b604735919cfb6d..1a84cecc5842e18f6e3e6df25253cbea370641fd 100644 (file)
@@ -126,7 +126,7 @@ namespace System.ServiceModel
                        get { return description; }
                }
 
-               protected IDictionary<string,ContractDescription> ImplementedContracts {
+               protected internal IDictionary<string,ContractDescription> ImplementedContracts {
                        get { return contracts; }
                }
 
@@ -203,7 +203,6 @@ namespace System.ServiceModel
                        return AddServiceEndpointCore (cd, binding, ea, listenUri);
                }
 
-#if NET_4_0
                public virtual void AddServiceEndpoint (ServiceEndpoint endpoint)
                {
                        if (endpoint == null)
@@ -224,7 +223,6 @@ namespace System.ServiceModel
 
                        Description.Endpoints.Add (endpoint);
                }
-#endif
 
                Type PopulateType (string typeName)
                {
@@ -322,8 +320,9 @@ namespace System.ServiceModel
                        ServiceElement service = GetServiceElement ();
                        
                        if (service != null)
-                               ApplyServiceElement (service);
-
+                               LoadConfigurationSection (service);
+                       // simplified configuration
+                       AddServiceBehaviors (String.Empty, false);
                        // TODO: consider commonBehaviors here
 
                        // ensure ServiceAuthorizationBehavior
@@ -340,6 +339,26 @@ namespace System.ServiceModel
                                Description.Behaviors.Add (debugBehavior);
                        }
                }
+
+               void AddServiceBehaviors (string configurationName, bool throwIfNotFound)
+               {
+                       if (configurationName == null)
+                               return;
+                       ServiceBehaviorElement behavior = ConfigUtil.BehaviorsSection.ServiceBehaviors [configurationName];
+                       if (behavior == null) {
+                               if (throwIfNotFound)
+                                       throw new ArgumentException (String.Format ("Service behavior configuration '{0}' was not found", configurationName));
+                               return;
+                       }
+
+                       KeyedByTypeCollection<IServiceBehavior> behaviors = Description.Behaviors;
+                       foreach (var bxe in behavior) {
+                               IServiceBehavior b = (IServiceBehavior) bxe.CreateBehavior ();
+                               if (behaviors.Contains (b.GetType ()))
+                                       continue;
+                               behaviors.Add (b);
+                       }
+               }
                
                void ApplyServiceElement (ServiceElement service)
                {
@@ -350,39 +369,31 @@ namespace System.ServiceModel
                        }
 
                        // behaviors
-                       ServiceBehaviorElement behavior = ConfigUtil.BehaviorsSection.ServiceBehaviors [service.BehaviorConfiguration];
-                       if (behavior != null) {
-                               foreach (var bxe in behavior) {
-                                       IServiceBehavior b = (IServiceBehavior) bxe.CreateBehavior ();
-                                       Description.Behaviors.Add (b);
-                               }
-                       }
-                       else if (!String.IsNullOrEmpty (service.BehaviorConfiguration))
-                               throw new ArgumentException (String.Format ("Service behavior configuration '{0}' was not found", service.BehaviorConfiguration));
+                       AddServiceBehaviors (service.BehaviorConfiguration, true);
 
-                       // services
+                       // endpoints
                        foreach (ServiceEndpointElement endpoint in service.Endpoints) {
                                ServiceEndpoint se;
 
-#if NET_4_0
                                var binding = String.IsNullOrEmpty (endpoint.Binding) ? null : ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration);
 
-                               if (endpoint.Kind != null) {
+                               if (!String.IsNullOrEmpty (endpoint.Kind)) {
                                        var contract = String.IsNullOrEmpty (endpoint.Contract) ? null : GetContract (endpoint.Contract, false);
                                        se = ConfigUtil.ConfigureStandardEndpoint (contract, endpoint);
                                        if (se.Binding == null)
                                                se.Binding = binding;
-                                       if (se.Address == null && se.Binding != null)
+                                       if (se.Address == null && se.Binding != null) // standard endpoint might have empty address
                                                se.Address = new EndpointAddress (CreateUri (se.Binding.Scheme, endpoint.Address));
+                                       if (se.Binding == null && se.Address != null) // look for protocol mapping
+                                               se.Binding = ConfigUtil.GetBindingByProtocolMapping (se.Address.Uri);
 
                                        AddServiceEndpoint (se);
                                }
-                               else
+                               else {
+                                       if (binding == null && endpoint.Address != null) // look for protocol mapping
+                                               binding = ConfigUtil.GetBindingByProtocolMapping (endpoint.Address);
                                        se = AddServiceEndpoint (endpoint.Contract, binding, endpoint.Address);
-#else
-                               var binding = ConfigUtil.CreateBinding (endpoint.Binding, endpoint.BindingConfiguration);
-                               se = AddServiceEndpoint (endpoint.Contract, binding, endpoint.Address);
-#endif
+                               }
 
                                // endpoint behaviors
                                EndpointBehaviorElement epbehavior = ConfigUtil.BehaviorsSection.EndpointBehaviors [endpoint.BehaviorConfiguration];
@@ -463,19 +474,32 @@ namespace System.ServiceModel
                        foreach (ServiceEndpoint endPoint in Description.Endpoints)
                                endPoint.Validate ();
 
+                       // In 4.0, it seems that if there is no configured ServiceEndpoint, infer them from the service type.
+                       if (Description.Endpoints.Count == 0) {
+                               foreach (Type iface in Description.ServiceType.GetInterfaces ())
+                                       if (iface.GetCustomAttributes (typeof (ServiceContractAttribute), true).Length > 0)
+                                               foreach (var baddr in BaseAddresses) {
+                                                       if (!baddr.IsAbsoluteUri)
+                                                               continue;
+                                                       var binding = ConfigUtil.GetBindingByProtocolMapping (baddr);
+                                                       if (binding == null)
+                                                               continue;
+                                                       AddServiceEndpoint (iface.FullName, binding, baddr);
+                                               }
+                       }
+
                        if (Description.Endpoints.FirstOrDefault (e => e.Contract != mex_contract && !e.IsSystemEndpoint) == null)
                                throw new InvalidOperationException ("The ServiceHost must have at least one application endpoint (that does not include metadata exchange endpoint) defined by either configuration, behaviors or call to AddServiceEndpoint methods.");
                }
 
-               [MonoTODO]
-               protected void LoadConfigurationSection (ServiceElement element)
+               protected void LoadConfigurationSection (ServiceElement serviceSection)
                {
-                       ServicesSection services = ConfigUtil.ServicesSection;
+                       ApplyServiceElement (serviceSection);
                }
 
-               [MonoTODO]
                protected override sealed void OnAbort ()
                {
+                       OnCloseOrAbort (TimeSpan.Zero);
                }
 
                Action<TimeSpan> close_delegate;
@@ -498,6 +522,11 @@ namespace System.ServiceModel
                }
 
                protected override void OnClose (TimeSpan timeout)
+               {
+                       OnCloseOrAbort (timeout);
+               }
+               
+               void OnCloseOrAbort (TimeSpan timeout)
                {
                        DateTime start = DateTime.Now;
                        ReleasePerformanceCounters ();
@@ -643,6 +672,8 @@ namespace System.ServiceModel
                        foreach (IEndpointBehavior b in endPoint.Behaviors)
                                b.ApplyDispatchBehavior (endPoint, ed);
                        foreach (OperationDescription operation in endPoint.Contract.Operations) {
+                               if (operation.InCallbackContract)
+                                       continue; // irrelevant
                                foreach (IOperationBehavior b in operation.Behaviors)
                                        b.ApplyDispatchBehavior (operation, ed.DispatchRuntime.Operations [operation.Name]);
                        }