From 96e79a7539fc49d013feee2e3b212a914719c81a Mon Sep 17 00:00:00 2001 From: cneuwirt Date: Thu, 3 Apr 2008 19:28:26 +0000 Subject: [PATCH] Support ability to scope how global behaviors are applied to clients and services. Allow specific behaviors to be added as well. git-svn-id: https://svn.castleproject.org/svn/castle/trunk@4988 73e77b4c-caa6-f847-a29a-24ab75ae54b6 --- .../WcfBehaviorScope.cs} | 19 +- .../Behaviors/WcfEndpointBehaviors.cs | 55 ++++ .../Behaviors/WcfExplicitBehavior.cs | 140 +++++++++ .../Behaviors/WcfServiceBehaviors.cs | 44 +++ .../Castle.Facilities.WcfIntegration-vs2008.csproj | 10 + .../Client/AbstractChannelBuilder.Generic.cs | 139 +++++++++ .../Client/AbstractChannelBuilder.cs | 320 +++++++-------------- .../Client/Rest/RestChannelBuilder.cs | 9 +- .../Client/ServiceEndpointBehaviors.cs | 53 ++++ .../Client/WcfClientModel.cs | 24 ++ .../{IWcfClientModel.cs => IWcfBehavior.cs} | 26 +- ...cfEndpointVisitor.cs => IWcfBehaviorVisitor.cs} | 8 +- .../IWcfClientModel.cs | 6 + .../IWcfEndpointVisitor.cs | 8 +- .../IWcfServiceModel.cs | 5 + .../Internal/WcfConstants.cs | 2 + .../Internal/WcfUtils.cs | 21 ++ .../Service/AbstractServiceHostBuilder.Generic.cs | 103 +++++++ .../Service/AbstractServiceHostBuilder.cs | 151 ++-------- .../Service/ServiceHostBehaviors.cs | 55 ++++ .../Service/WcfServiceModel.cs | 68 +++-- .../WcfEndpoint.cs | 8 +- 22 files changed, 868 insertions(+), 406 deletions(-) copy Facilities/Wcf/Castle.Facilities.WcfIntegration/{IWcfClientModel.cs => Behaviors/WcfBehaviorScope.cs} (72%) create mode 100644 Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfEndpointBehaviors.cs create mode 100644 Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfExplicitBehavior.cs create mode 100644 Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfServiceBehaviors.cs create mode 100644 Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/AbstractChannelBuilder.Generic.cs rewrite Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/AbstractChannelBuilder.cs (61%) create mode 100644 Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/ServiceEndpointBehaviors.cs copy Facilities/Wcf/Castle.Facilities.WcfIntegration/{IWcfClientModel.cs => IWcfBehavior.cs} (62%) copy Facilities/Wcf/Castle.Facilities.WcfIntegration/{IWcfEndpointVisitor.cs => IWcfBehaviorVisitor.cs} (67%) create mode 100644 Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/AbstractServiceHostBuilder.Generic.cs create mode 100644 Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/ServiceHostBehaviors.cs diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfClientModel.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfBehaviorScope.cs similarity index 72% copy from Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfClientModel.cs copy to Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfBehaviorScope.cs index 84f462a5a..466a9d7d7 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfClientModel.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfBehaviorScope.cs @@ -14,21 +14,22 @@ namespace Castle.Facilities.WcfIntegration { - using System; - /// - /// Contract for all WCF client models. + /// Determines how a global behavior will be applied. /// - public interface IWcfClientModel + public enum WcfBehaviorScope { /// - /// Gets the endpoint contract. + /// Only apply to client endpoints. /// - Type Contract { get; } - + Clients, + /// + /// Only apply to service hosts. + /// + Services, /// - /// Gets the endpoint of the service. + /// Do not apply automatically. /// - IWcfEndpoint Endpoint { get; } + Explicit } } diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfEndpointBehaviors.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfEndpointBehaviors.cs new file mode 100644 index 000000000..2fb91069d --- /dev/null +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfEndpointBehaviors.cs @@ -0,0 +1,55 @@ +// Copyright 2004-2008 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Facilities.WcfIntegration +{ + using System.Collections.Generic; + using System.ServiceModel.Description; + using Castle.MicroKernel; + using Castle.Facilities.WcfIntegration.Internal; + + internal class WcfEndpointBehaviors : IWcfEndpointBehavior + { + private readonly WcfBehaviorScope scope; + + public WcfEndpointBehaviors(WcfBehaviorScope scope) + { + this.scope = scope; + } + + public void Install(ServiceEndpoint endpoint, IKernel kernel) + { + ICollection endpointBehaviors = WcfUtils.FindBehaviors(kernel, scope); + ICollection operationBehaviors = WcfUtils.FindBehaviors(kernel, scope); + + foreach (IHandler handler in endpointBehaviors) + { + endpoint.Behaviors.Add((IEndpointBehavior)handler.Resolve(CreationContext.Empty)); + } + + foreach (OperationDescription operation in endpoint.Contract.Operations) + { + foreach (IHandler operationHandler in operationBehaviors) + { + operation.Behaviors.Add((IOperationBehavior)operationHandler.Resolve(CreationContext.Empty)); + } + } + } + + public void Accept(IWcfBehaviorVisitor visitor) + { + visitor.VisitEndpointBehavior(this); + } + } +} diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfExplicitBehavior.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfExplicitBehavior.cs new file mode 100644 index 000000000..2f26a8bdd --- /dev/null +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfExplicitBehavior.cs @@ -0,0 +1,140 @@ +// Copyright 2004-2008 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Facilities.WcfIntegration +{ + using System; + using System.ServiceModel.Description; + using Castle.MicroKernel; + + internal abstract class WcfExplcitBehavior : IWcfServiceBehavior, IWcfEndpointBehavior + { + + #region IWcfServiceBehavior + + public void Install(ServiceDescription description, IKernel kernel) + { + object behavior = GetBehaviorInstance(kernel); + + if (behavior is IServiceBehavior) + { + description.Behaviors.Add((IServiceBehavior)behavior); + } + } + + #endregion + + #region IWcfEndpointBehavior + + public void Install(ServiceEndpoint endpoint, IKernel kernel) + { + object behavior = GetBehaviorInstance(kernel); + + if (behavior is IEndpointBehavior) + { + endpoint.Behaviors.Add((IEndpointBehavior)behavior); + } + else if (behavior is IOperationBehavior) + { + foreach (OperationDescription operation in endpoint.Contract.Operations) + { + operation.Behaviors.Add((IOperationBehavior)behavior); + } + } + } + + #endregion + + protected abstract object GetBehaviorInstance(IKernel kernel); + + internal static WcfExplcitBehavior CreateFrom(object behavior) + { + if (behavior is Type) + { + return new WcfServiceTypeBehavior((Type)behavior); + } + else if (behavior is string) + { + return new WcfServiceKeyBehavior((string)behavior); + } + else + { + return new WcfInstanceBehavior(behavior); + } + } + + public void Accept(IWcfBehaviorVisitor visitor) + { + visitor.VisitServiceBehavior(this); + visitor.VisitEndpointBehavior(this); + } + } + + #region Class: WcfServiceKeyBehavior + + internal class WcfServiceKeyBehavior : WcfExplcitBehavior + { + private readonly string key; + + internal WcfServiceKeyBehavior(string key) + { + this.key = key; + } + + protected override object GetBehaviorInstance(IKernel kernel) + { + return kernel[key]; + } + } + + #endregion + + #region Class: WcfServiceTypeBehavior + + internal class WcfServiceTypeBehavior : WcfExplcitBehavior + { + private readonly Type service; + + internal WcfServiceTypeBehavior(Type service) + { + this.service = service; + } + + protected override object GetBehaviorInstance(IKernel kernel) + { + return kernel.Resolve(service); + } + } + + #endregion + + #region Class: WcfInstanceBehavior + + internal class WcfInstanceBehavior : WcfExplcitBehavior + { + private readonly object instance; + + internal WcfInstanceBehavior(object instance) + { + this.instance = instance; + } + + protected override object GetBehaviorInstance(IKernel kernel) + { + return instance; + } + } + + #endregion +} diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfServiceBehaviors.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfServiceBehaviors.cs new file mode 100644 index 000000000..fa5492af8 --- /dev/null +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Behaviors/WcfServiceBehaviors.cs @@ -0,0 +1,44 @@ +// Copyright 2004-2008 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Facilities.WcfIntegration +{ + using System.Collections.Generic; + using System.ServiceModel.Description; + using Castle.MicroKernel; + using Castle.Facilities.WcfIntegration.Internal; + + internal class WcfServiceBehaviors : IWcfServiceBehavior + { + public void Install(ServiceDescription description, IKernel kernel) + { + ICollection serviceBehaviors = WcfUtils.FindBehaviors( + kernel, WcfBehaviorScope.Services); + + foreach (IHandler handler in serviceBehaviors) + { + if (handler.ComponentModel.Implementation == typeof(ServiceDebugBehavior)) + { + description.Behaviors.Remove(); + } + description.Behaviors.Add((IServiceBehavior)handler.Resolve(CreationContext.Empty)); + } + } + + public void Accept(IWcfBehaviorVisitor visitor) + { + visitor.VisitServiceBehavior(this); + } + } +} diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Castle.Facilities.WcfIntegration-vs2008.csproj b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Castle.Facilities.WcfIntegration-vs2008.csproj index 807cd134f..8f55b6517 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Castle.Facilities.WcfIntegration-vs2008.csproj +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Castle.Facilities.WcfIntegration-vs2008.csproj @@ -76,6 +76,12 @@ + + + + + + @@ -95,11 +101,14 @@ + + + @@ -107,6 +116,7 @@ + diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/AbstractChannelBuilder.Generic.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/AbstractChannelBuilder.Generic.cs new file mode 100644 index 000000000..94404ba66 --- /dev/null +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/AbstractChannelBuilder.Generic.cs @@ -0,0 +1,139 @@ +// Copyright 2004-2008 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Facilities.WcfIntegration +{ + using System; + using System.Reflection; + using Castle.MicroKernel; + using System.ServiceModel; + using System.ServiceModel.Description; + using System.ServiceModel.Channels; + + public abstract class AbstractChannelBuilder : AbstractChannelBuilder, IClientChannelBuilder + where M : IWcfClientModel + { + private M clientModel; + + public AbstractChannelBuilder(IKernel kernel) + : base(kernel) + { + } + + /// + /// Get a delegate capable of creating channels. + /// + /// The client model. + /// The + public ChannelCreator GetChannelCreator(M clientModel) + { + this.clientModel = clientModel; + return GetEndpointChannelCreator(clientModel.Endpoint); + } + + /// + /// Get a delegate capable of creating channels. + /// + /// The component model. + /// The client model. + /// The contract override. + /// The + public ChannelCreator GetChannelCreator(M clientModel, Type contract) + { + this.clientModel = clientModel; + return GetEndpointChannelCreator(clientModel.Endpoint, contract); + } + + #region AbstractChannelBuilder Members + + protected override ChannelCreator GetChannelCreator(Type contract, ServiceEndpoint endpoint) + { + return GetChannelCreator(clientModel, contract, endpoint); + } + + protected override ChannelCreator GetChannelCreator(Type contract, string configurationName) + { + return GetChannelCreator(clientModel, contract, configurationName); + } + + protected override ChannelCreator GetChannelCreator(Type contract, Binding binding, string address) + { + return GetChannelCreator(clientModel, contract, binding, address); + } + + protected override ChannelCreator GetChannelCreator(Type contract, Binding binding, EndpointAddress address) + { + return GetChannelCreator(contract, binding, address); + } + + #endregion + + #region GetChannelCreator Members + + protected virtual ChannelCreator GetChannelCreator(M clientModel, Type contract, + ServiceEndpoint endpoint) + { + return CreateChannelCreator(contract, clientModel, endpoint); + } + + protected virtual ChannelCreator GetChannelCreator(M clientModel, Type contract, + string configurationName) + { + return CreateChannelCreator(contract, clientModel, configurationName); + } + + protected virtual ChannelCreator GetChannelCreator(M clientModel, Type contract, + Binding binding, string address) + { + return CreateChannelCreator(contract, clientModel, binding, address); + } + + protected virtual ChannelCreator GetChannelCreator(M clientModel, Type contract, + Binding binding, EndpointAddress address) + { + return CreateChannelCreator(contract, clientModel, binding, address); + } + + protected virtual ChannelCreator CreateChannelCreator(Type contract, M clientModel, + params object[] channelFactoryArgs) + { + Type type = typeof(ChannelFactory<>).MakeGenericType(new Type[] { contract }); + + ChannelFactory channelFactory = (ChannelFactory) + Activator.CreateInstance(type, channelFactoryArgs); + channelFactory.Opening += delegate { OnOpening(channelFactory, clientModel); }; + + MethodInfo methodInfo = type.GetMethod("CreateChannel", new Type[0]); + return (ChannelCreator)Delegate.CreateDelegate( + typeof(ChannelCreator), channelFactory, methodInfo); + } + + protected virtual void OnOpening(ChannelFactory channelFactory, M clientModel) + { + ServiceEndpointBehaviors behaviors = + new ServiceEndpointBehaviors(channelFactory.Endpoint, Kernel) + .Install(new WcfEndpointBehaviors(WcfBehaviorScope.Clients)); + + if (clientModel != null) + { + foreach (IWcfBehavior behavior in clientModel.Behaviors) + { + behaviors.Install(behavior); + } + } + } + + #endregion + } +} diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/AbstractChannelBuilder.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/AbstractChannelBuilder.cs dissimilarity index 61% index 07f377d32..0a451f430 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/AbstractChannelBuilder.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/AbstractChannelBuilder.cs @@ -1,222 +1,98 @@ -// Copyright 2004-2008 Castle Project - http://www.castleproject.org/ -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -namespace Castle.Facilities.WcfIntegration -{ - using System; - using System.Reflection; - using System.ServiceModel; - using System.ServiceModel.Description; - using System.ServiceModel.Channels; - using Castle.MicroKernel; - - public abstract class AbstractChannelBuilder : IWcfEndpointVisitor - { - private Type contract; - private readonly IKernel kernel; - private ChannelCreator channelCreator; - - public AbstractChannelBuilder(IKernel kernel) - { - this.kernel = kernel; - } - - protected IKernel Kernel - { - get { return kernel; } - } - - protected ChannelCreator GetEndpointChannelCreator(IWcfEndpoint endpoint) - { - return GetEndpointChannelCreator(endpoint, null); - } - - protected ChannelCreator GetEndpointChannelCreator(IWcfEndpoint endpoint, Type contract) - { - this.contract = contract ?? endpoint.Contract; - endpoint.Accept(this); - return channelCreator; - } - - protected void AttachEndpointBehaviors(ServiceEndpoint endpoint) - { - IHandler[] endPointBehaviors = Kernel.GetAssignableHandlers(typeof(IEndpointBehavior)); - foreach (IHandler handler in endPointBehaviors) - { - endpoint.Behaviors.Add((IEndpointBehavior)handler.Resolve(CreationContext.Empty)); - } - - IHandler[] operationBehaviors = Kernel.GetAssignableHandlers(typeof(IOperationBehavior)); - foreach (OperationDescription operation in endpoint.Contract.Operations) - { - foreach (IHandler operationHandler in operationBehaviors) - { - operation.Behaviors.Add((IOperationBehavior) - operationHandler.Resolve(CreationContext.Empty)); - } - } - } - - protected abstract ChannelCreator GetChannelCreator(Type contract, ServiceEndpoint endpoint); - protected abstract ChannelCreator GetChannelCreator(Type contract, string configurationName); - protected abstract ChannelCreator GetChannelCreator(Type contract, Binding binding, string address); - protected abstract ChannelCreator GetChannelCreator(Type contract, Binding binding, EndpointAddress address); - - #region IWcfEndpointVisitor Members - - void IWcfEndpointVisitor.VisitServiceEndpointModel(ServiceEndpointModel model) - { - channelCreator = GetChannelCreator(contract, model.ServiceEndpoint); - } - - void IWcfEndpointVisitor.VisitConfigurationEndpointModel(ConfigurationEndpointModel model) - { - channelCreator = GetChannelCreator(contract, model.EndpointName); - } - - void IWcfEndpointVisitor.VisitBindingEndpointModel(BindingEndpointModel model) - { - channelCreator = GetChannelCreator(contract, model.Binding, string.Empty); - } - - void IWcfEndpointVisitor.VisitBindingAddressEndpointModel(BindingAddressEndpointModel model) - { - if (model.HasViaAddress) - { - EndpointAddress address = model.EndpointAddress ?? new EndpointAddress(model.Address); - ContractDescription description = ContractDescription.GetContract(contract); - ServiceEndpoint endpoint = new ServiceEndpoint(description, model.Binding, address); - endpoint.Behaviors.Add(new ClientViaBehavior(model.ViaAddress)); - channelCreator = GetChannelCreator(contract, endpoint); - } - else - { - if (model.EndpointAddress != null) - { - channelCreator = GetChannelCreator(contract, model.Binding, model.EndpointAddress); - } - else - { - channelCreator = GetChannelCreator(contract, model.Binding, model.Address); - } - } - } - - #endregion - } - - public abstract class AbstractChannelBuilder : AbstractChannelBuilder, IClientChannelBuilder - where M : IWcfClientModel - { - private M clientModel; - - public AbstractChannelBuilder(IKernel kernel) - : base(kernel) - { - } - - /// - /// Get a delegate capable of creating channels. - /// - /// The client model. - /// The - public ChannelCreator GetChannelCreator(M clientModel) - { - this.clientModel = clientModel; - return GetEndpointChannelCreator(clientModel.Endpoint); - } - - /// - /// Get a delegate capable of creating channels. - /// - /// The client model. - /// The contract override. - /// The - public ChannelCreator GetChannelCreator(M clientModel, Type contract) - { - this.clientModel = clientModel; - return GetEndpointChannelCreator(clientModel.Endpoint, contract); - } - - #region AbstractChannelBuilder Members - - protected override ChannelCreator GetChannelCreator(Type contract, ServiceEndpoint endpoint) - { - return GetChannelCreator(clientModel, contract, endpoint); - } - - protected override ChannelCreator GetChannelCreator(Type contract, string configurationName) - { - return GetChannelCreator(clientModel, contract, configurationName); - } - - protected override ChannelCreator GetChannelCreator(Type contract, Binding binding, string address) - { - return GetChannelCreator(clientModel, contract, binding, address); - } - - protected override ChannelCreator GetChannelCreator(Type contract, Binding binding, EndpointAddress address) - { - return GetChannelCreator(contract, binding, address); - } - - #endregion - - #region GetChannelCreator Members - - protected virtual ChannelCreator GetChannelCreator(M clientModel, Type contract, - ServiceEndpoint endpoint) - { - return CreateChannelCreator(contract, endpoint); - } - - protected virtual ChannelCreator GetChannelCreator(M clientModel, Type contract, - string configurationName) - { - return CreateChannelCreator(contract, configurationName); - } - - protected virtual ChannelCreator GetChannelCreator(M clientModel, Type contract, - Binding binding, string address) - { - return CreateChannelCreator(contract, binding, address); - } - - protected virtual ChannelCreator GetChannelCreator(M clientModel, Type contract, - Binding binding, EndpointAddress address) - { - return CreateChannelCreator(contract, binding, address); - } - - protected virtual ChannelCreator CreateChannelCreator(Type contract, params object[] channelFactoryArgs) - { - Type type = typeof(ChannelFactory<>).MakeGenericType(new Type[] { contract }); - - ChannelFactory channelFactory = (ChannelFactory) - Activator.CreateInstance(type, channelFactoryArgs); - channelFactory.Opening += delegate { OnOpening(channelFactory); }; - - MethodInfo methodInfo = type.GetMethod("CreateChannel", new Type[0]); - return (ChannelCreator)Delegate.CreateDelegate( - typeof(ChannelCreator), channelFactory, methodInfo); - } - - protected virtual void OnOpening(ChannelFactory channelFactory) - { - AttachEndpointBehaviors(channelFactory.Endpoint); - } - - #endregion - } -} +// Copyright 2004-2008 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Facilities.WcfIntegration +{ + using System; + using System.ServiceModel; + using System.ServiceModel.Description; + using System.ServiceModel.Channels; + using Castle.MicroKernel; + + public abstract class AbstractChannelBuilder : IWcfEndpointVisitor + { + private Type contract; + private readonly IKernel kernel; + private ChannelCreator channelCreator; + + public AbstractChannelBuilder(IKernel kernel) + { + this.kernel = kernel; + } + + protected IKernel Kernel + { + get { return kernel; } + } + + protected ChannelCreator GetEndpointChannelCreator(IWcfEndpoint endpoint) + { + return GetEndpointChannelCreator(endpoint, null); + } + + protected ChannelCreator GetEndpointChannelCreator(IWcfEndpoint endpoint, Type contract) + { + this.contract = contract ?? endpoint.Contract; + endpoint.Accept(this); + return channelCreator; + } + + protected abstract ChannelCreator GetChannelCreator(Type contract, ServiceEndpoint endpoint); + protected abstract ChannelCreator GetChannelCreator(Type contract, string configurationName); + protected abstract ChannelCreator GetChannelCreator(Type contract, Binding binding, string address); + protected abstract ChannelCreator GetChannelCreator(Type contract, Binding binding, EndpointAddress address); + + #region IWcfEndpointVisitor Members + + void IWcfEndpointVisitor.VisitServiceEndpoint(ServiceEndpointModel model) + { + channelCreator = GetChannelCreator(contract, model.ServiceEndpoint); + } + + void IWcfEndpointVisitor.VisitConfigurationEndpoint(ConfigurationEndpointModel model) + { + channelCreator = GetChannelCreator(contract, model.EndpointName); + } + + void IWcfEndpointVisitor.VisitBindingEndpoint(BindingEndpointModel model) + { + channelCreator = GetChannelCreator(contract, model.Binding, string.Empty); + } + + void IWcfEndpointVisitor.VisitBindingAddressEndpoint(BindingAddressEndpointModel model) + { + if (model.HasViaAddress) + { + EndpointAddress address = model.EndpointAddress ?? new EndpointAddress(model.Address); + ContractDescription description = ContractDescription.GetContract(contract); + ServiceEndpoint endpoint = new ServiceEndpoint(description, model.Binding, address); + endpoint.Behaviors.Add(new ClientViaBehavior(model.ViaAddress)); + channelCreator = GetChannelCreator(contract, endpoint); + } + else + { + if (model.EndpointAddress != null) + { + channelCreator = GetChannelCreator(contract, model.Binding, model.EndpointAddress); + } + else + { + channelCreator = GetChannelCreator(contract, model.Binding, model.Address); + } + } + } + + #endregion + } +} diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/Rest/RestChannelBuilder.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/Rest/RestChannelBuilder.cs index b2218599f..6f173abf8 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/Rest/RestChannelBuilder.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/Rest/RestChannelBuilder.cs @@ -37,9 +37,10 @@ namespace Castle.Facilities.WcfIntegration.Rest if (binding == null) { - return CreateChannelCreator(contract, remoteAddress); + return CreateChannelCreator(contract, clientModel, remoteAddress); } - return CreateChannelCreator(contract, binding, remoteAddress); + + return CreateChannelCreator(contract, clientModel, binding, remoteAddress); } protected override ChannelCreator GetChannelCreator(RestClientModel clientModel, Type contract, @@ -48,14 +49,14 @@ namespace Castle.Facilities.WcfIntegration.Rest return GetChannelCreator(clientModel, contract, binding, address.Uri.AbsoluteUri); } - protected override ChannelCreator CreateChannelCreator(Type contract, + protected override ChannelCreator CreateChannelCreator(Type contract, RestClientModel clientModel, params object[] channelFactoryArgs) { Type type = typeof(WebChannelFactory<>).MakeGenericType(new Type[] { contract }); ChannelFactory channelFactory = (ChannelFactory) Activator.CreateInstance(type, channelFactoryArgs); - channelFactory.Opening += delegate { OnOpening(channelFactory); }; + channelFactory.Opening += delegate { OnOpening(channelFactory, clientModel); }; MethodInfo methodInfo = type.GetMethod("CreateChannel", new Type[0]); return (ChannelCreator)Delegate.CreateDelegate( diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/ServiceEndpointBehaviors.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/ServiceEndpointBehaviors.cs new file mode 100644 index 000000000..c8c192070 --- /dev/null +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/ServiceEndpointBehaviors.cs @@ -0,0 +1,53 @@ +// Copyright 2004-2008 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Facilities.WcfIntegration +{ + using System; + using System.ServiceModel.Description; + using Castle.Core; + using Castle.MicroKernel; + + internal class ServiceEndpointBehaviors : IWcfBehaviorVisitor + { + private readonly ServiceEndpoint endpoint; + private readonly IKernel kernel; + + public ServiceEndpointBehaviors(ServiceEndpoint endpoint, IKernel kernel) + { + this.endpoint = endpoint; + this.kernel = kernel; + } + + public ServiceEndpointBehaviors Install(IWcfBehavior behavior) + { + behavior.Accept(this); + return this; + } + + #region IWcfBehaviorVisitor Members + + void IWcfBehaviorVisitor.VisitServiceBehavior(IWcfServiceBehavior behavior) + { + throw new InvalidOperationException("Service behaviors cannot be installed on a client endpoint."); + } + + void IWcfBehaviorVisitor.VisitEndpointBehavior(IWcfEndpointBehavior behavior) + { + behavior.Install(endpoint, kernel); + } + + #endregion + } +} diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/WcfClientModel.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/WcfClientModel.cs index 020bd642e..c4b78b690 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/WcfClientModel.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Client/WcfClientModel.cs @@ -15,10 +15,12 @@ namespace Castle.Facilities.WcfIntegration { using System; + using System.Collections.Generic; public class WcfClientModel : IWcfClientModel { private IWcfEndpoint endpoint; + private ICollection behaviors; public WcfClientModel() { @@ -49,7 +51,29 @@ namespace Castle.Facilities.WcfIntegration } } + public ICollection Behaviors + { + get + { + if (behaviors == null) + { + behaviors = new List(); + } + return behaviors; + } + } + #endregion + + + public WcfClientModel AddBehaviors(params object[] behaviors) + { + foreach (object behavior in behaviors) + { + Behaviors.Add(WcfExplcitBehavior.CreateFrom(behavior)); + } + return this; + } } } diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfClientModel.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfBehavior.cs similarity index 62% copy from Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfClientModel.cs copy to Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfBehavior.cs index 84f462a5a..f2b083a72 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfClientModel.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfBehavior.cs @@ -14,21 +14,21 @@ namespace Castle.Facilities.WcfIntegration { - using System; + using System.ServiceModel.Description; + using Castle.MicroKernel; - /// - /// Contract for all WCF client models. - /// - public interface IWcfClientModel + public interface IWcfBehavior { - /// - /// Gets the endpoint contract. - /// - Type Contract { get; } + void Accept(IWcfBehaviorVisitor visitor); + } - /// - /// Gets the endpoint of the service. - /// - IWcfEndpoint Endpoint { get; } + public interface IWcfServiceBehavior : IWcfBehavior + { + void Install(ServiceDescription description, IKernel kernel); + } + + public interface IWcfEndpointBehavior : IWcfBehavior + { + void Install(ServiceEndpoint endpoint, IKernel kernel); } } diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfEndpointVisitor.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfBehaviorVisitor.cs similarity index 67% copy from Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfEndpointVisitor.cs copy to Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfBehaviorVisitor.cs index da3f6587a..8932766c7 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfEndpointVisitor.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfBehaviorVisitor.cs @@ -14,11 +14,9 @@ namespace Castle.Facilities.WcfIntegration { - public interface IWcfEndpointVisitor + public interface IWcfBehaviorVisitor { - void VisitServiceEndpointModel(ServiceEndpointModel model); - void VisitConfigurationEndpointModel(ConfigurationEndpointModel model); - void VisitBindingEndpointModel(BindingEndpointModel model); - void VisitBindingAddressEndpointModel(BindingAddressEndpointModel model); + void VisitServiceBehavior(IWcfServiceBehavior behavior); + void VisitEndpointBehavior(IWcfEndpointBehavior behavior); } } diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfClientModel.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfClientModel.cs index 84f462a5a..477d4512f 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfClientModel.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfClientModel.cs @@ -15,6 +15,7 @@ namespace Castle.Facilities.WcfIntegration { using System; + using System.Collections.Generic; /// /// Contract for all WCF client models. @@ -30,5 +31,10 @@ namespace Castle.Facilities.WcfIntegration /// Gets the endpoint of the service. /// IWcfEndpoint Endpoint { get; } + + /// + /// Gets the service behaviors. + /// + ICollection Behaviors { get; } } } diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfEndpointVisitor.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfEndpointVisitor.cs index da3f6587a..d21159216 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfEndpointVisitor.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfEndpointVisitor.cs @@ -16,9 +16,9 @@ namespace Castle.Facilities.WcfIntegration { public interface IWcfEndpointVisitor { - void VisitServiceEndpointModel(ServiceEndpointModel model); - void VisitConfigurationEndpointModel(ConfigurationEndpointModel model); - void VisitBindingEndpointModel(BindingEndpointModel model); - void VisitBindingAddressEndpointModel(BindingAddressEndpointModel model); + void VisitServiceEndpoint(ServiceEndpointModel model); + void VisitConfigurationEndpoint(ConfigurationEndpointModel model); + void VisitBindingEndpoint(BindingEndpointModel model); + void VisitBindingAddressEndpoint(BindingAddressEndpointModel model); } } diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfServiceModel.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfServiceModel.cs index 7d3420296..1d87959a5 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfServiceModel.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/IWcfServiceModel.cs @@ -36,5 +36,10 @@ namespace Castle.Facilities.WcfIntegration /// Gets the service endpoints. /// ICollection Endpoints { get; } + + /// + /// Gets the service behaviors. + /// + ICollection Behaviors { get; } } } diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Internal/WcfConstants.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Internal/WcfConstants.cs index 4bfa1d8cf..aa48ef45f 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Internal/WcfConstants.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Internal/WcfConstants.cs @@ -16,6 +16,8 @@ namespace Castle.Facilities.WcfIntegration { internal static class WcfConstants { + public const string BehaviorScopeKey = "scope"; + public const string ServiceModelKey = "wcf.serviceModel"; public const string ServiceHostKey = "wcf.serviceHost"; public const string ServiceHostEnabled = "wcfServiceHost"; diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Internal/WcfUtils.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Internal/WcfUtils.cs index 357fe22d6..cdec13c21 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Internal/WcfUtils.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Internal/WcfUtils.cs @@ -18,6 +18,8 @@ namespace Castle.Facilities.WcfIntegration.Internal using System.Collections; using System.Collections.Generic; using System.ServiceModel; + using Castle.Core; + using Castle.MicroKernel; internal static class WcfUtils { @@ -75,6 +77,25 @@ namespace Castle.Facilities.WcfIntegration.Internal return false; } + public static ICollection FindBehaviors(IKernel kernel, WcfBehaviorScope scope) + { + List handlers = new List(); + foreach (IHandler handler in kernel.GetAssignableHandlers(typeof(T))) + { + ComponentModel model = handler.ComponentModel; + if (model.Configuration != null) + { + string scopeAttrib = model.Configuration.Attributes[WcfConstants.BehaviorScopeKey]; + if (string.IsNullOrEmpty(scopeAttrib) || + scopeAttrib.Equals(scope.ToString(), StringComparison.InvariantCultureIgnoreCase)) + { + handlers.Add(handler); + } + } + } + return handlers; + } + public static bool IsCommunicationObjectReady(ICommunicationObject comm) { switch (comm.State) diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/AbstractServiceHostBuilder.Generic.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/AbstractServiceHostBuilder.Generic.cs new file mode 100644 index 000000000..f5748b3d8 --- /dev/null +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/AbstractServiceHostBuilder.Generic.cs @@ -0,0 +1,103 @@ +// Copyright 2004-2008 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Facilities.WcfIntegration +{ + using System; + using System.ServiceModel; + using Castle.Core; + using Castle.MicroKernel; + using Castle.MicroKernel.Facilities; + + public abstract class AbstractServiceHostBuilder : AbstractServiceHostBuilder, IServiceHostBuilder + where M : IWcfServiceModel + { + protected AbstractServiceHostBuilder(IKernel kernel) + : base(kernel) + { + } + + #region IServiceHostBuilder Members + + public ServiceHost Build(ComponentModel model, M serviceModel, params Uri[] baseAddresses) + { + ValidateServiceModelInternal(model, serviceModel); + ServiceHost serviceHost = CreateServiceHost(model, serviceModel, baseAddresses); + serviceHost.Opening += delegate { OnOpening(serviceHost, serviceModel, model); }; + ConfigureServiceHost(serviceHost, serviceModel); + return serviceHost; + } + + public ServiceHost Build(ComponentModel model, params Uri[] baseAddresses) + { + ServiceHost serviceHost = CreateServiceHost(model, baseAddresses); + serviceHost.Opening += delegate { OnOpening(serviceHost, null, model); }; + return serviceHost; + } + + public ServiceHost Build(Type serviceType, params Uri[] baseAddresses) + { + ServiceHost serviceHost = CreateServiceHost(serviceType, baseAddresses); + serviceHost.Opening += delegate { OnOpening(serviceHost, null, null); }; + return serviceHost; + } + + #endregion + + protected virtual void ConfigureServiceHost(ServiceHost serviceHost, M serviceModel) + { + foreach (IWcfEndpoint endpoint in serviceModel.Endpoints) + { + AddServiceEndpoint(serviceHost, endpoint); + } + } + + private void ValidateServiceModelInternal(ComponentModel model, M serviceModel) + { + ValidateServiceModel(model, serviceModel); + + foreach (IWcfEndpoint endpoint in serviceModel.Endpoints) + { + Type contract = endpoint.Contract; + + if (contract != null) + { + if (!contract.IsInterface) + { + throw new FacilityException("The service endpoint contract " + + contract.FullName + " does not represent an interface."); + } + } + else if (model == null || !model.Service.IsInterface) + { + throw new FacilityException( + "No service endpoint contract can be implied from the component."); + } + else + { + endpoint.Contract = model.Service; + } + } + } + + protected virtual void ValidateServiceModel(ComponentModel model, M serviceModel) + { + } + + protected abstract ServiceHost CreateServiceHost(ComponentModel model, M serviceModel, + params Uri[] baseAddresses); + protected abstract ServiceHost CreateServiceHost(ComponentModel model, Uri[] baseAddresses); + protected abstract ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses); + } +} diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/AbstractServiceHostBuilder.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/AbstractServiceHostBuilder.cs index 6ba43648d..5efa12674 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/AbstractServiceHostBuilder.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/AbstractServiceHostBuilder.cs @@ -20,7 +20,6 @@ namespace Castle.Facilities.WcfIntegration using System.ServiceModel.Description; using Castle.Core; using Castle.MicroKernel; - using Castle.MicroKernel.Facilities; using System.ServiceModel.Channels; public abstract class AbstractServiceHostBuilder : IWcfEndpointVisitor @@ -33,12 +32,19 @@ namespace Castle.Facilities.WcfIntegration { this.kernel = kernel; } - + protected IKernel Kernel { get { return kernel; } } + protected ServiceEndpoint AddServiceEndpoint(ServiceHost serviceHost, IWcfEndpoint endpoint) + { + this.serviceHost = serviceHost; + endpoint.Accept(this); + return serviceEndpoint; + } + protected Uri[] GetEffectiveBaseAddresses(IWcfServiceModel serviceModel, Uri[] defaultBaseAddresses) { List baseAddresses = new List(serviceModel.BaseAddresses); @@ -55,92 +61,70 @@ namespace Castle.Facilities.WcfIntegration return baseAddresses.ToArray(); } - protected ServiceEndpoint AddServiceEndpoint(ServiceHost serviceHost, IWcfEndpoint endpoint) + protected virtual void OnOpening(ServiceHost serviceHost, IWcfServiceModel serviceModel, + ComponentModel model) { - this.serviceHost = serviceHost; - endpoint.Accept(this); - return serviceEndpoint; - } + serviceHost.Description.Behaviors.Add( + new WindsorDependencyInjectionServiceBehavior(kernel, model)); - protected virtual void OnOpening(ServiceHost serviceHost, ComponentModel model) - { - serviceHost.Description.Behaviors.Add(new WindsorDependencyInjectionServiceBehavior(Kernel, model)); + ServiceHostBehaviors behaviors = new ServiceHostBehaviors(serviceHost, kernel) + .Install(new WcfServiceBehaviors()) + .Install(new WcfEndpointBehaviors(WcfBehaviorScope.Services)); - IHandler[] serviceBehaviorHandlers = Kernel.GetAssignableHandlers(typeof(IServiceBehavior)); - foreach (IHandler handler in serviceBehaviorHandlers) + if (serviceModel != null) { - if (handler.ComponentModel.Implementation == typeof(ServiceDebugBehavior)) + foreach (IWcfBehavior behavior in serviceModel.Behaviors) { - serviceHost.Description.Behaviors.Remove(); - } - serviceHost.Description.Behaviors.Add((IServiceBehavior)handler.Resolve(CreationContext.Empty)); - } - - IHandler[] endPointBehaviors = kernel.GetAssignableHandlers(typeof(IEndpointBehavior)); - IHandler[] operationBehaviors = kernel.GetAssignableHandlers(typeof(IOperationBehavior)); - - foreach (ServiceEndpoint endpoint in serviceHost.Description.Endpoints) - { - foreach (IHandler handler in endPointBehaviors) - { - endpoint.Behaviors.Add((IEndpointBehavior)handler.Resolve(CreationContext.Empty)); - } - - foreach (OperationDescription operation in endpoint.Contract.Operations) - { - foreach (IHandler operationHandler in operationBehaviors) - { - operation.Behaviors.Add((IOperationBehavior)operationHandler.Resolve(CreationContext.Empty)); - } + behaviors.Install(behavior); } } } #region IWcfEndpointVisitor Members - void IWcfEndpointVisitor.VisitServiceEndpointModel(ServiceEndpointModel model) + void IWcfEndpointVisitor.VisitServiceEndpoint(ServiceEndpointModel model) { serviceEndpoint = AddServiceEndpoint(serviceHost, model); } - protected virtual ServiceEndpoint AddServiceEndpoint(ServiceHost serviceHost, - ServiceEndpointModel model) + protected virtual ServiceEndpoint AddServiceEndpoint(ServiceHost serviceHost, + ServiceEndpointModel model) { serviceHost.Description.Endpoints.Add(model.ServiceEndpoint); return model.ServiceEndpoint; } - void IWcfEndpointVisitor.VisitConfigurationEndpointModel(ConfigurationEndpointModel model) + void IWcfEndpointVisitor.VisitConfigurationEndpoint(ConfigurationEndpointModel model) { serviceEndpoint = AddServiceEndpoint(serviceHost, model); } protected virtual ServiceEndpoint AddServiceEndpoint(ServiceHost serviceHost, - ConfigurationEndpointModel model) + ConfigurationEndpointModel model) { throw new InvalidOperationException("The ServiceEndpoint for a ServiceHost " + "cannot be created from an endpoint name."); } - void IWcfEndpointVisitor.VisitBindingEndpointModel(BindingEndpointModel model) + void IWcfEndpointVisitor.VisitBindingEndpoint(BindingEndpointModel model) { serviceEndpoint = AddServiceEndpoint(serviceHost, model); } protected virtual ServiceEndpoint AddServiceEndpoint(ServiceHost serviceHost, - BindingEndpointModel model) + BindingEndpointModel model) { Binding binding = model.Binding ?? GetDefaultBinding(serviceHost, string.Empty); return serviceHost.AddServiceEndpoint(model.Contract, binding, string.Empty); } - void IWcfEndpointVisitor.VisitBindingAddressEndpointModel(BindingAddressEndpointModel model) + void IWcfEndpointVisitor.VisitBindingAddressEndpoint(BindingAddressEndpointModel model) { serviceEndpoint = AddServiceEndpoint(serviceHost, model); } protected virtual ServiceEndpoint AddServiceEndpoint(ServiceHost serviceHost, - BindingAddressEndpointModel model) + BindingAddressEndpointModel model) { Binding binding = model.Binding ?? GetDefaultBinding(serviceHost, model.Address); @@ -162,85 +146,4 @@ namespace Castle.Facilities.WcfIntegration #endregion } - - public abstract class AbstractServiceHostBuilder : AbstractServiceHostBuilder, IServiceHostBuilder - where M : IWcfServiceModel - { - protected AbstractServiceHostBuilder(IKernel kernel) - : base(kernel) - { - } - - #region IServiceHostBuilder Members - - public ServiceHost Build(ComponentModel model, M serviceModel, params Uri[] baseAddresses) - { - ValidateServiceModelInternal(model, serviceModel); - ServiceHost serviceHost = CreateServiceHost(model, serviceModel, baseAddresses); - serviceHost.Opening += delegate { OnOpening(serviceHost, model); }; - ConfigureServiceHost(serviceHost, serviceModel); - return serviceHost; - } - - public ServiceHost Build(ComponentModel model, params Uri[] baseAddresses) - { - ServiceHost serviceHost = CreateServiceHost(model, baseAddresses); - serviceHost.Opening += delegate { OnOpening(serviceHost, model); }; - return serviceHost; - } - - public ServiceHost Build(Type serviceType, params Uri[] baseAddresses) - { - ServiceHost serviceHost = CreateServiceHost(serviceType, baseAddresses); - serviceHost.Opening += delegate { OnOpening(serviceHost, null); }; - return serviceHost; - } - - #endregion - - protected virtual void ConfigureServiceHost(ServiceHost serviceHost, M serviceModel) - { - foreach (IWcfEndpoint endpoint in serviceModel.Endpoints) - { - AddServiceEndpoint(serviceHost, endpoint); - } - } - - private void ValidateServiceModelInternal(ComponentModel model, M serviceModel) - { - ValidateServiceModel(model, serviceModel); - - foreach (IWcfEndpoint endpoint in serviceModel.Endpoints) - { - Type contract = endpoint.Contract; - - if (contract != null) - { - if (!contract.IsInterface) - { - throw new FacilityException("The service endpoint contract " + - contract.FullName + " does not represent an interface."); - } - } - else if (model == null || !model.Service.IsInterface) - { - throw new FacilityException( - "No service endpoint contract can be implied from the component."); - } - else - { - endpoint.Contract = model.Service; - } - } - } - - protected virtual void ValidateServiceModel(ComponentModel model, M serviceModel) - { - } - - protected abstract ServiceHost CreateServiceHost(ComponentModel model, M serviceModel, - params Uri[] baseAddresses); - protected abstract ServiceHost CreateServiceHost(ComponentModel model, Uri[] baseAddresses); - protected abstract ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses); - } } diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/ServiceHostBehaviors.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/ServiceHostBehaviors.cs new file mode 100644 index 000000000..8e89c0d28 --- /dev/null +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/ServiceHostBehaviors.cs @@ -0,0 +1,55 @@ +// Copyright 2004-2008 Castle Project - http://www.castleproject.org/ +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace Castle.Facilities.WcfIntegration +{ + using System.ServiceModel; + using System.ServiceModel.Description; + using Castle.MicroKernel; + + internal class ServiceHostBehaviors : IWcfBehaviorVisitor + { + private readonly ServiceHost serviceHost; + private readonly IKernel kernel; + + public ServiceHostBehaviors(ServiceHost serviceHost, IKernel kernel) + { + this.serviceHost = serviceHost; + this.kernel = kernel; + } + + public ServiceHostBehaviors Install(IWcfBehavior behavior) + { + behavior.Accept(this); + return this; + } + + #region IWcfBehaviorVisitor Members + + void IWcfBehaviorVisitor.VisitServiceBehavior(IWcfServiceBehavior behavior) + { + behavior.Install(serviceHost.Description, kernel); + } + + void IWcfBehaviorVisitor.VisitEndpointBehavior(IWcfEndpointBehavior behavior) + { + foreach (ServiceEndpoint endpoint in serviceHost.Description.Endpoints) + { + behavior.Install(endpoint, kernel); + } + } + + #endregion + } +} diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/WcfServiceModel.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/WcfServiceModel.cs index eb4a1cca0..39647e5b2 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/WcfServiceModel.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/Service/WcfServiceModel.cs @@ -21,19 +21,16 @@ namespace Castle.Facilities.WcfIntegration { private bool hosted; private ICollection baseAddresses; - private ICollection endpoints; + private ICollection endpoints; + private ICollection behaviors; + + #region IWcfServiceModel public bool IsHosted { get { return hosted; } } - public WcfServiceModel Hosted() - { - hosted = true; - return this; - } - public ICollection BaseAddresses { get @@ -47,6 +44,39 @@ namespace Castle.Facilities.WcfIntegration set { baseAddresses = value; } } + public ICollection Endpoints + { + get + { + if (endpoints == null) + { + endpoints = new List(); + } + return endpoints; + } + set { endpoints = value; } + } + + public ICollection Behaviors + { + get + { + if (behaviors == null) + { + behaviors = new List(); + } + return behaviors; + } + } + + #endregion + + public WcfServiceModel Hosted() + { + hosted = true; + return this; + } + public WcfServiceModel AddBaseAddresses(params Uri[] baseAddresses) { foreach (Uri baseAddress in baseAddresses) @@ -65,18 +95,6 @@ namespace Castle.Facilities.WcfIntegration return this; } - public ICollection Endpoints - { - get - { - if (endpoints == null) - { - endpoints = new List(); - } - return endpoints; - } - set { endpoints = value; } - } public WcfServiceModel AddEndpoints(params IWcfEndpoint[] endpoints) { @@ -86,6 +104,14 @@ namespace Castle.Facilities.WcfIntegration } return this; } - } -} + public WcfServiceModel AddBehaviors(params object[] behaviors) + { + foreach (object behavior in behaviors) + { + Behaviors.Add(WcfExplcitBehavior.CreateFrom(behavior)); + } + return this; + } + } +} \ No newline at end of file diff --git a/Facilities/Wcf/Castle.Facilities.WcfIntegration/WcfEndpoint.cs b/Facilities/Wcf/Castle.Facilities.WcfIntegration/WcfEndpoint.cs index dea90713d..5d575148b 100644 --- a/Facilities/Wcf/Castle.Facilities.WcfIntegration/WcfEndpoint.cs +++ b/Facilities/Wcf/Castle.Facilities.WcfIntegration/WcfEndpoint.cs @@ -169,7 +169,7 @@ namespace Castle.Facilities.WcfIntegration protected override void Accept(IWcfEndpointVisitor visitor) { - visitor.VisitServiceEndpointModel(this); + visitor.VisitServiceEndpoint(this); } } @@ -194,7 +194,7 @@ namespace Castle.Facilities.WcfIntegration protected override void Accept(IWcfEndpointVisitor visitor) { - visitor.VisitConfigurationEndpointModel(this); + visitor.VisitConfigurationEndpoint(this); } } @@ -246,7 +246,7 @@ namespace Castle.Facilities.WcfIntegration protected override void Accept(IWcfEndpointVisitor visitor) { - visitor.VisitBindingEndpointModel(this); + visitor.VisitBindingEndpoint(this); } } @@ -310,7 +310,7 @@ namespace Castle.Facilities.WcfIntegration protected override void Accept(IWcfEndpointVisitor visitor) { - visitor.VisitBindingAddressEndpointModel(this); + visitor.VisitBindingAddressEndpoint(this); } } -- 2.11.4.GIT