I'm trying to inject a some business services in a WCF service. I read this really interessting post: How do I pass values to the constructor on my wcf service?
And I have done the following:
Custom ServiceHost
public class UnityServiceHost : ServiceHost
{
public UnityServiceHost(IUnityContainer container, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
foreach (ContractDescription contractDescription in ImplementedContracts.Values)
{
contractDescription.Behaviors.Add(new UnityInstanceProvider(serviceType, container));
}
}
}
Custom Instance Provider
public class UnityInstanceProvider : IInstanceProvider, IContractBehavior
{
private readonly Type m_serviceType;
private readonly IUnityContainer m_container;
public UnityInstanceProvider(Type serviceType, IUnityContainer container)
{
m_serviceType = serviceType;
m_container = container;
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
return GetInstance(instanceContext);
}
public object GetInstance(InstanceContext instanceContext)
{
return m_container.Resolve(m_serviceType);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
(instance as IDisposable)?.Dispose();
}
public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime) { }
public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
{
dispatchRuntime.InstanceProvider = this;
}
public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) { }
}
The service behavior that I've is looking like this:
[ServiceBehavior]
public class MyService : IMyService
{
public ServerInformationService(ISomeDependency coreManager)
{
//...
}
}
But I don't get into the GetInstance, and when I run the code, I get this:
The service type provided could not be loaded as a service because it
does not have a default (parameter-less) constructor. To fix the
problem, add a default constructor to the type, or pass an instance of
the type to the host.
What have I done wrong? It look like my instance provider isn't even used
I finally found the solution. I was applying my InstanceProvider to Contact and not to services.
Here is my final (Working) solution:
public class UnityServiceHost : ServiceHost
{
public UnityServiceHost(IUnityContainer container, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
if (container == null)
{
throw new ArgumentNullException(nameof(container));
}
Description.Behaviors.Add(new UnityInstanceProvider(serviceType, container));
}
}
And the behavior+instance provider:
public class UnityInstanceProvider : IInstanceProvider, IServiceBehavior
{
private readonly Type m_serviceType;
private readonly IUnityContainer m_container;
public UnityInstanceProvider(Type serviceType, IUnityContainer container)
{
m_serviceType = serviceType;
m_container = container;
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher cd = (ChannelDispatcher)channelDispatcherBase;
foreach (EndpointDispatcher ed in cd.Endpoints)
{
if (!ed.IsSystemEndpoint)
{
ed.DispatchRuntime.InstanceProvider = this;
}
}
}
}
public object GetInstance(InstanceContext instanceContext)
{
return m_container.Resolve(m_serviceType);
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
return GetInstance(instanceContext);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
(instance as IDisposable)?.Dispose();
}
}
It works because I'm self-hosting the service(new UnityServiceHost(...) ...., if it was on IIS, I could not create the behavior that way
Related
I have this situation: I have WCF service. I'm handling all exceptions by MyErrorHandler with implemented interface IErrorHandler. There whole working code is below.
What I want to do, but have no idea how: I want to inject an object (for example ILogger) into MyErrorHandler class. It basically means I have to inject an object here: [GlobalErrorHandlerBehaviour(typeof(MyErrorHandler))]. Could you please help me solve this problem?
[ServiceContract]
public interface ITestService
{
[OperationContract]
int GetTest();
}
[GlobalErrorHandlerBehaviour(typeof(MyErrorHandler))]
public class TestService : ITestService
{
public TestService(ILogger logger)
{
// Here, I'm already injecting logger.
// It's not imported for my question so I removed it for now
}
public int GetTest()
{
throw new Exception("Test");
}
}
// This is attribute added to TestService class
// How can I inject (via constructor) ILogger, or any other class??
public class GlobalErrorHandlerBehaviourAttribute : Attribute, IServiceBehavior
{
private readonly Type errorHandlerType;
public GlobalErrorHandlerBehaviourAttribute(Type errorHandlerType)
{
this.errorHandlerType = errorHandlerType;
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
IErrorHandler handler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);
foreach(ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
if (channelDispatcher != null)
{
channelDispatcher.ErrorHandlers.Add(handler);
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
public class MyErrorHandler : IErrorHandler
{
//--------------------------------------------------//
// I MUST INJECT ILOGGER HERE (or any other object) //
//--------------------------------------------------//
public bool HandleError(Exception error)
{
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
FaultException fe = new FaultException();
MessageFault message = fe.CreateMessageFault();
fault = Message.CreateMessage(version, message, null);
}
}
Btw. I want to use DI and inject something in IErrorHandler I don't want to use private static readonly method with logger.
This question is related to yours. Basically, you don’t need GlobalErrorHandlerBehaviourAttribute. You can add behaviour to your service manually. What you have to do is to create your ServiceHost. In this answer I explained more explicitly how to do it.
Here is the working code of host application, that has injected ILogger into IErrorHandler:
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace ConsoleHost
{
class Program
{
static void Main(string[] args)
{
var logger = new DummyLogger();
var errorHandler = new TestErrorHandler(logger);
ServiceHost host = new TestServiceHost(errorHandler, typeof(TestService), new Uri("net.tcp://localhost:8002"));
host.Open();
Console.WriteLine("Press enter to exit");
Console.ReadKey();
}
}
[ServiceContract]
public interface ITestService
{
[OperationContract]
string Test(int input);
}
public class TestService : ITestService
{
public string Test(int input)
{
throw new Exception("Test exception!");
}
}
public class TestErrorHandler : IErrorHandler
{
private ILogger Logger { get; }
public TestErrorHandler(ILogger logger)
{
Logger = logger;
}
public bool HandleError(Exception error)
{
Logger.Log(error.Message);
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
FaultException fe = new FaultException();
MessageFault message = fe.CreateMessageFault();
fault = Message.CreateMessage(version, message, null);
}
}
public class TestServiceHost : ServiceHost
{
private readonly IErrorHandler errorHandler;
public TestServiceHost(IErrorHandler errorHandler, Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
this.errorHandler = errorHandler;
}
protected override void OnOpening()
{
Description.Behaviors.Add(new ErrorHandlerBehaviour(errorHandler));
base.OnOpening();
}
class ErrorHandlerBehaviour : IServiceBehavior, IErrorHandler
{
private readonly IErrorHandler errorHandler;
public ErrorHandlerBehaviour(IErrorHandler errorHandler)
{
this.errorHandler = errorHandler;
}
bool IErrorHandler.HandleError(Exception error)
{
return errorHandler.HandleError(error);
}
void IErrorHandler.ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
errorHandler.ProvideFault(error, version, ref fault);
}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
channelDispatcher.ErrorHandlers.Add(this);
}
}
void IServiceBehavior.AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
void IServiceBehavior.Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
}
// Dummy logger
public interface ILogger
{
void Log(string input);
}
public class DummyLogger : ILogger
{
public void Log(string input) => Console.WriteLine(input);
}
}
Config:
<system.serviceModel>
<services>
<service name="ConsoleHost.TestService">
<endpoint address="net.tcp://localhost:8002/TestService"
binding="netTcpBinding"
contract="ConsoleHost.ITestService" />
</service>
</services>
</system.serviceModel>
This is interesting question but setting up DI container is not that straight forward in WCF.
You have perform following setup:
Create a custom Instance provider
Create a custom service host
If its not self-hosting then a custom ServiceHostFactory setup.
See the complete code sample on MSDN for how to setup DI in WCF. Once DI is setup you just need to change the ErrorHandler implementation to use ILogger via constructor injection:
public class MyErrorHandler : IErrorHandler
{
private ILogger logger;
public MyErrorHandler(ILogger logger)
{
this.logger = logger;
}
}
Here's an additional source for more options of setting up InstanceProvider with another type of DI.
I have made a custom error handler on the service side:
public class GlobalErrorHandler : Attribute, IErrorHandler, IServiceBehavior
{
public void AddBindingParameters(
ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase,
Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
IErrorHandler errorHandler = new GlobalErrorHandler();
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
if (channelDispatcher != null)
{
channelDispatcher.ErrorHandlers.Add(errorHandler);
}
}
}
public bool HandleError(Exception error)
{
Trace.TraceError(error.ToString());
if (error is FaultException)
return false; // Let WCF do normal processing
else
return true; // Fault message is already generated
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
if (error is FaultException)
{
// Let WCF do normal processing
}
else
{
// Generate fault message manually
MessageFault messageFault = MessageFault.CreateFault(
new FaultCode("Sender"), new FaultReason(error.Message),
error, new NetDataContractSerializer());
fault = Message.CreateMessage(version, messageFault, null);
}
}
}
public class ErrorHandlerElement : BehaviorExtensionElement
{
protected override object CreateBehavior()
{
return new GlobalErrorHandler();
}
public override Type BehaviorType
{
get { return typeof (GlobalErrorHandler); }
}
}
I have defined a custom message inspector on the client side :
public class MessageInspector : IClientMessageInspector
{
public void AfterReceiveReply(ref Message reply, object correlationState)
{
if (reply.IsFault)
{
//do some processing
}
}
public object BeforeSendRequest(ref Message request, System.ServiceModel.IClientChannel channel)
{
return null;
}
}
I have a custom behaviour which wire ups the message inspector :
public class NewtonsoftJsonBehavior : WebHttpBehavior
{
public override void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MessageInspector());
}
}
and this behaviour is applied programatically through a factory :
public class JsonWebServiceHostFactory : WebServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
var host = base.CreateServiceHost(serviceType, baseAddresses);
//return host;
//ServiceEndpoint ep = host.AddServiceEndpoint(serviceType, new WebHttpBinding(), "");
//host.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior { HelpEnabled = true });
//return host;
WebHttpBinding webBinding = new WebHttpBinding();
host.AddServiceEndpoint(serviceType, webBinding, "").Behaviors.Add(new NewtonsoftJsonBehavior());
return host;
}
}
However when I debug and I generate a faultexception in the service, the globalerrorhandler gets called , but the debugger never steps into the message inspector.
Any idea why?
To create a Message Inspector on WCF service side, use an implementation of IDispatchMessageInspector instead of: IClientMessageInspector.
An example:
Service:
EndpointAddress endpoint = new EndpointAddress("http://localhost:9001/Message");
WebServiceHost svcWebHost = new WebServiceHost(typeof(Service.Message), endpoint.Uri);
CustomServiceBehavior serviceBehavior = new CustomServiceBehavior();
svcWebHost.Description.Behaviors.Add(serviceBehavior);
Binding webHttpBinding = new WebHttpBinding();
ServiceEndpoint serviceEndpoint = svcWebHost.AddServiceEndpoint(typeof(Service.IMessage), webHttpBinding, endpoint.Uri);
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
svcWebHost.Description.Behaviors.Add(smb);
ServiceDebugBehavior sdb = svcWebHost.Description.Behaviors.Find<ServiceDebugBehavior>();
sdb.IncludeExceptionDetailInFaults = true;
svcWebHost.Open();
Service Contract
[ServiceContract]
public interface IMessage
{
[OperationContract]
[WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
Model.TestResponse Test();
}
Service Implementation
public class Message : IMessage
{
public Model.TestResponse Test()
{
return new Model.TestResponse() { success = true, message = "OK!" };
}
}
CustomServiceBehavior implements IServiceBehavior:
public class CustomServiceBehavior : IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
CustomEndpointBehavior endpointBehavior = new CustomEndpointBehavior();
foreach (var endpoint in serviceDescription.Endpoints)
endpoint.EndpointBehaviors.Add(endpointBehavior);
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
}
CustomEndpointBehavior implements IEndpointBehavior
public class CustomEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
var inspector = new CustomDispatchMessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
CustomDispatchMessageInspector implements IDispatchMessageInspector
public class CustomDispatchMessageInspector : IDispatchMessageInspector
{
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
var httpResponse = ((HttpResponseMessageProperty)reply.Properties["httpResponse"]);
httpResponse.Headers.Add("user-agent", "My Browser");
}
}
This example is a WCF Self Hosted without configuration file (Configuring WCF Services in Code) that return a Json and send a custom header in HTTP Response (user-agent:My Browser).
To test this code:
Create a Windows Console Application
Insert the code (each
block in one Class)
Run the applcation
Using browser open url:
http://localhost:9001/Message/Test
The response is a Json:
{"message":"OK!","success":true}
You can inspect the Response and
see the custom header: "user-agent:My Browser"
You only put your message inspector on the client side using ApplyClientBehavior. There is another method for the service side:
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
if (endpointDispatcher != null)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MessageInspector());
}
}
I am currently trying to create a WCF service and then host it from a commandLine application. During hosting of the service am trying to initialize it with an instance of an object called MyProxy. All calls to the service should delegate to MyProxy.
I have created a service and made calls. But I am not able to initialize the MyProxy instance in the service. It is always null. So when any calls to the service is made, I am not able to delegate it to the proxy.
I have been trying to get this work since last two days. Am lost now, not sure what is happening. Kindly help.
public class MasOperationsService : IMasOperations
{
//This MyProxy instance should be used to delegate all calls to service.
public MyProxy myProxyInstance;
public MasOperationsService()
{
myProxyInstance = null;
}
public MasOperationsService(MyProxy proxy)
{
myProxyInstance = proxy;
}
public CoAuthorSearchResult ExtractCoAuthorsFromAuthor(long authorCellId, uint levelsToExtract)
{
//The service will delegate the call to MyProxy.
//myProxyInstance is always null
return myProxyInstance.GetProxyData(...);
}
}
public class MyInstanceProvider : IInstanceProvider
{
public object GetInstance(InstanceContext instanceContext, Message message)
{
MyProxy name = message.Headers.GetHeader<MyProxy>("Name", "http://my.namespace");
if (name != null)
{
return new MasOperationsService(name);
}
return null;
}
public object GetInstance(InstanceContext instanceContext)
{
return new MasOperationsService(null);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
}
}
public class MyServiceBehavior : IServiceBehavior
{
MyInstanceProvider myProvider = new MyInstanceProvider();
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { }
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.InstanceProvider = this.myProvider;
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
}
The service is launched using,
class MyServiceLauncher
{
ServiceHost host;
IMasOperations proxy;
ChannelFactory<IMasOperations> factory;
public void StartService(MyProxy proxyInstance)
{
string baseAddress = "http://localhost:8730/Design_Time_Addresses/MASService/Service1";
host = new ServiceHost(typeof(MasOperationsService), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(IMasOperations), GetBinding(), "");
host.Description.Behaviors.Add(new MyServiceBehavior());
host.Open();
Console.WriteLine("Host opened");
factory = new ChannelFactory<IMasOperations>(GetBinding(), new EndpointAddress(baseAddress));
proxy = factory.CreateChannel();
using (OperationContextScope scope = new OperationContextScope((IContextChannel)proxy))
{
OperationContext.Current.OutgoingMessageHeaders.Add(MessageHeader.CreateHeader("Name", "http://my.namespace", proxyInstance));
}
}
public void ShutDownService()
{
((IClientChannel)proxy).Close();
factory.Close();
host.Close();
}
static Binding GetBinding()
{
BasicHttpBinding result = new BasicHttpBinding();
return result;
}
}
I also put a Debugger.Launch() almost everywhere, just to see it being initialized (Both constructor of Service and in IInstanceProvider). It dosent get fired.
Here are the missing types. Also in the service, there is a call
return myProxyInstance.GetProxyData(...);
removing the dots compiles the application.
[ServiceContract]
public interface IMasOperations
{
[OperationContract]
CoAuthorSearchResult ExtractCoAuthorsFromAuthor(long AuthorCellId, uint LevelsToExtract);
}
public class CoAuthorSearchResult
{ }
public class MyProxy
{
public CoAuthorSearchResult GetProxyData()
{
return new CoAuthorSearchResult();
}
}
#kobac
asked for a piece of code showing where GetInstance is being called. I am not sure how and why I need to do this.
Currently I just create an object of the service class - MasOperationsClient at the client and call the method ExtractCoAuthorsFromAuthor().
How would I switch the implementation of the service contract at runtime?
Say I have:
[ServiceContract]
public interface IService {
[OperationContract]
DoWork();
}
public class ServiceA : IService {
public string DoWork() {
// ....
}
}
public class ServiceB : IService {
public string DoWork() {
// ....
}
}
I'd like to be able to switch the implementation that is being used from say a config file or a value in a database between the two. Would it also be possible to do this while the WCF service is hot?
You need to write a servicebehavior by implementing IServiceBehavior, and initialize the service instance using an instance provider. The following initializes a new service instance, you may implement a different logic:
public class XInstanceProviderServiceBehavior : Attribute, IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var item in serviceHostBase.ChannelDispatchers)
{
var dispatcher = item as ChannelDispatcher;
if (dispatcher != null)
{
dispatcher.Endpoints.ToList().ForEach(endpoint =>
{
endpoint.DispatchRuntime.InstanceProvider = new XInstanceProvider(serviceDescription.ServiceType);
});
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
}
And have your instance provider class implement IInstanceProvider and return related instance in GetInstance method.
public XInstanceProvider :IInstanceProvider
{
...
public object GetInstance(InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
{
return new ServiceX();
}
}
Then all you need is to add servicebehaviour to service; something like
[XInstanceProviderServiceBehavior()]
public class MyService : IMyService
I have a custom behavior in which I implement "IParameterInspector" to be able to use BeforeCall and AfterCall. I'm currently using these methods to make some verifications before the call execute on my WCF service.
Here's my Attribute:
[AttributeUsage(AttributeTargets.Class)]
public class SendReceiveBehaviorAttribute : Attribute, IServiceBehavior
{
public SendReceiveBehaviorAttribute()
{
}
public void ApplyDispatchBehavior(ServiceDescription desc, ServiceHostBase host)
{
foreach (ChannelDispatcher cDispatcher in host.ChannelDispatchers)
{
foreach (EndpointDispatcher eDispatcher in cDispatcher.Endpoints)
{
foreach (DispatchOperation op in eDispatcher.DispatchRuntime.Operations)
{
op.ParameterInspectors.Add(MyInspector);
}
}
}
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
And my inspector:
internal class MyInspector: IParameterInspector
{
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
}
public object BeforeCall(string operationName, object[] inputs)
{
// Make some verifications and cancel if it fails.
return null;
}
}
EDIT
What would be the best way to abort my call if my verification fails?
Throwing exception is the only way - as far as I am aware - to abort.