How can I extend WCF in the Callback direction? - wcf

I can attach an IParameterInspector using behaviors to each operation in the ClientRuntime and also to each operation in the DispatchRuntime on the service side. But it seems this only works from client to service.
I also want to be able to attach an IParameterInspector in the callbacks from service to client on both sides of the wire as above but I can't find any extensibility points to do this.
Any ideas?

This is a little obscure and does not appear to be all that well documented but you can customise both ends using standard WCF behavior capabilities.
On the client, this attribute would make it happen.
public class InspectorBehaviorAttribute : Attribute, IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
foreach (var item in clientRuntime.CallbackDispatchRuntime.Operations)
{
item.ParameterInspectors.Add(ParameterInspector.Instance);
}
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
Simply apply this attribute on the class that implements your callback interface.
On the server, it gets a little trickier. You need to hook up via the ApplyDispatchBehavior. In this case I have done it through a service behavior but the principal applies to OperationBehaviors and EndpointBehaviors as well.
public class InspectorBehaviorAttribute : Attribute, IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (var item in serviceHostBase.ChannelDispatchers.OfType<ChannelDispatcher>())
{
foreach (var ep in item.Endpoints)
{
foreach (var op in ep.DispatchRuntime.CallbackClientRuntime.Operations)
{
op.ParameterInspectors.Add(ParameterInspector.Instance);
}
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
}
Again, simply apply this attribute to your service implementation to have your parameter inspector utilised for all callback operations.
While these examples demonstrate hooking up IParameterInspector implementations, the same approach for all other WCF extension points can be used to customise callback channels at both the client and server.

Related

WCF One method to execute before every service method's call

I am looking for a way to execute specific method, at the server side, on every request method's call.
This is for security validations but not only.
This is NOT duplicated with this question since we mean to completely different things and. I addition, all the relevant answers there have unavailable links so it's impossible to get to the right answer.
(Sorry I haven't attached any code here, there is no code to specify in this issue).
The best solution is to create WCF custom behavior.
Here is how you do this by several simple steps:
Client Side:
public class FillHeaderDataBehaviourExtension : BehaviorExtensionElement, IEndpointBehavior
{
#region BehaviorExtensionElement Implementation
public override Type BehaviorType
{
get
{
return typeof(FillHeaderDataBehaviourExtension);
}
}
protected override object CreateBehavior()
{
return this;
}
#endregion
#region IServiceBehaviour Implementation
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.ClientMessageInspectors.Add(new MessageInspector());
}
#endregion
}
public class MessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
MessageHeader header = MessageHeader.CreateHeader("HeaderData", String.Empty, HeaderDataVM.GetInstance().GetBaseInstance());
request.Headers.Add(header); // There is no need for checking if exist before adding. Every request has it's own headers.
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
}
}
Server Side:
public class ExtractHeadersBehaviourExtension : BehaviorExtensionElement, IServiceBehavior
{
#region BehaviorExtensionElement Implementation
public override Type BehaviorType
{
get
{
return typeof(ExtractHeadersBehaviourExtension);
}
}
protected override object CreateBehavior()
{
return this;
}
#endregion
#region IServiceBehavior Implementation
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++)
{
ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher;
if (channelDispatcher != null)
{
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
{
MessageInspector inspector = new MessageInspector();
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector);
}
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
#endregion
}
public class MessageInspector : IDispatchMessageInspector
{
public void BeforeSendReply(ref Message reply, object correlationState)
{
}
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
HeaderData headerData = request.Headers.GetHeader<HeaderData>("HeaderData", String.Empty);
if(headerData != null)
{
OperationContext.Current.IncomingMessageProperties.Add("HeaderData", headerData);
}
return null;
}
}
And finally, don't forget to configure it in the app.config files (client & server side) as follows:
<behaviors>
<endpointBehaviors>
<behavior name="NewBehavior">
<fillHeaderDataBehaviourExtension/>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
You can also add these lines via the WCF config editor. To do so, look at this answer.
EDIT: You might get an error in the app config after adding these lines of configuration code:
Don't worry about this, your application will run fine. It causes because the GAC (Global Assembly Cache) folder doesn't contain this behavior (since it is a custom behavior). You can fix it by adding this behavior manually to your GAC folder on your computer.
However, this error might prevent you from updating service reference. If you try to, you'll get this error message:
So just comment out this line (<extractHeadersBehaviourExtension/>) (in client & server side) when you update your service reference.
Sources: How to add behavior on a specific endpoint? &
Adding Custom Message Headers to a WCF Service

Singleton DBContext for a Per-Call WCF Service using castle

I am trying find a proper way of injecting an EF6 DbContext into my WCF service but I kind of struggle to find a proper working example. Does anyone know of a good demonstration of a per-call WCF service and Entity framework? I use Castle for the injection however any other IOC container is welcomed. If you are against using Singleton dbcontext [Massive DB] please show me a working example with the least performance hit.
This worked for me:
Create a concrete context interface:
public class CustomersContext :DbContext, ICustomerContext
Then register in the container as singleton
container.Register(Component.For<ICustomerContext>().ImplementedBy<CustomersContext>());
Then you should register it as a WCF service and provide your own Instance Provider
like this:
First add some attributes to your interface:
[InstanceProviderBehavior(typeof (ICustomerContext))]
[DataContract]
public class CustomersContext :DbContext, ICustomerContext
Then, write the InstanceProviderBehavior attribute:
public class InstanceProviderBehaviorAttribute : Attribute, IServiceBehavior
{
private readonly Type _type;
public InstanceProviderBehaviorAttribute(Type type)
{
_type = type;
}
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 (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
if (!ed.IsSystemEndpoint)
{
ed.DispatchRuntime.InstanceProvider = new WindsorServiceInstanceProvider(_type);
}
}
}
}
}
Note that you tell the WCF to use the WindsorServiceInstanceProvider.
Here it is:
public class WindsorServiceInstanceProvider : IInstanceProvider
{
public static IWindsorContainer Container;
private readonly Type _type;
public WindsorServiceInstanceProvider(Type type)
{
_type = type;
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
return Container.Resolve(_type);
}
public object GetInstance(InstanceContext instanceContext)
{
return this.GetInstance(instanceContext, null);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
Container.Release(instance);
}
}
Please note the static object named Container, this is pretty ugly, but I didnt find any other way to pass my container instance into the InstanceProvider
Thats it. now, when some client will ask for ICustomerContext from your WCF service, it will resolve it from your container.
More about WCF Instance Provider here

WCF & Ninject - Getting Ninject Kernel Into An IDispatchMessageInspector Instance

I've currently rigged up Ninject into a WCF application (using ninject.extensions.wcf), and the basics are working fine. However, I've added a custom IDispatchMessageInspector and IServiceBehavior in order to authenticate each service call (by check the database against some credentials), but I'm not entirely sure how to get Ninject working within the IDispatchMessageInspector.
The code I have so far is:
public class MyServiceInspector: IDispatchMessageInspector
{
#region Methods
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
// TODO: Get credentials from request here, and hit database.
return null;
}
public void BeforeSendReply(ref Message reply, object correlationState)
{
// Do nothing
}
#endregion
}
The IServiceBehavior which initiates this is as follows:
public class MyServiceBehaviour : Attribute, IServiceBehavior
{
#region Methods
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
// Do nothing
}
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
// Loop through channels and endpoints
foreach (ChannelDispatcher cDispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher eDispatcher in cDispatcher.Endpoints)
{
// Add credentials inspector
eDispatcher.DispatchRuntime.MessageInspectors.Add(new MyServiceInspector());
}
}
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
// Do nothing
}
#endregion
}
I've scoured the internet looking for examples, but I can't seem to find anything. Is this even possible?
I know this answer is very late, but hopefully it helps other people coming across this issue.
I had the same problem today.. I needed a message inspector with injected dependencies. They added a NinjectBehaviorExtensionElement class to Ninjext.Extensions.WCF from version 3.2. So here's how i injected dependencies in my Message Inspector:
The Message Inspector:
public class MyMessageInspector : IDispatchMessageInspector
{
public MyMessageInspector(IInjectedDependency injectedDependency)
{
}
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
}
The Behavior:
public class MyMessageInspectionBehavior : IEndpointBehavior
{
private readonly IDispatchMessageInspector _messageInspector;
public MyMessageInspectionBehavior(IDispatchMessageInspector messageInspector)
{
_messageInspector = messageInspector;
}
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(_messageInspector);
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
The Ninject Binding:
this.Bind<IDispatchMessageInspector>()
.To<MyMessageInspector>()
.WhenInjectedInto<IEndpointBehavior>();
The last step is the Configuration:
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="MyCustomMessageInspector"
type="Ninject.Extensions.Wcf.BaseNinjectBehaviorExtensionElement+NinjectBehaviorExtensionElement`1[[MyNamespace.MyMessageInspectionBehavior, MyAssemblyName]], Ninject.Extensions.Wcf" />
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior>
<MyCustomMessageInspector />
</behavior>
</endpointBehaviors>
I have parked this for now, as there doesn't seem to be any solution. I am simply connecting to my context directly with a view to improving it in the future.

How To Make WCF routing service log message to SQL server

I'm trying to use Routing Service (http://msdn.microsoft.com/en-us/library/ee517422.aspx) to route the data from clients to other end points. I have multiple clients and the end point which is called from routing service is located at a third party.
I also need to Log every transaction passed through routing service into SQL Database.
The problem is I can't write custom code in routing service as it's working from configuration files. Given that I can't write custom code in these classes, how can I achieve this?
1) create a class library and sign it with strong key.
2)create RoutingServiceBehavior class this class will implement IServiceBehavior, IDispatchMessageInspector interfaces, the code for message interception will be in this class:
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace Services.RoutingServiceBehavior
{
public class RoutingServiceBehavior : IServiceBehavior, IDispatchMessageInspector
{
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
{
// This is your envelop
string s = request.ToString();
return null;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
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)
{
foreach (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(this);
}
}
}
public void Validate(ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
}
}
3) Create RoutingServiceBehaviorElement class, this class will implement BehaviorExtensionElement interface:
using System;
using System.ServiceModel.Configuration;
namespace Services.RoutingServiceBehavior
{
public class RoutingServiceBehaviorElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(RoutingServiceBehavior); }
}
protected override object CreateBehavior()
{
return new RoutingServiceBehavior();
}
}
}
4)Build your project.
5)Add your assembly to GAC.
6)Open machine.config and add the name of your assembly under <behaviorExtensions> it shall look like that:
<add name="RoutingServiceBehavior" type="Services.RoutingServiceBehavior.RoutingServiceBehaviorElement, Services.RoutingServiceBehavior, Version=1.0.0.0, Culture=neutral" />
7) add the name of your service behavior in your wcf service under <serviceDebug>
<RoutingServiceBehavior/>
8)Make sure that the assembly dlls are included in your WCF service.

WCF Same IParameterInspector for all operations on a service

I have implemented a custom IParameterInspector and I want to have it execute for every single operation on my service.
My understanding is that IParameterInspector implementations can only be used with IOperationBehavior implementations, and that intern IOperationBehavior implementation can only be used to decorate individual operations using an attribute.
Does anyone know if there is a way I can register my IParameterInspector at a service level so that it can execute for all operations in the service?
Thanks to this and subsequenbtly this, I found what I was looking for.
IParameterInspector does not need to be at the IOperationBehavior level. They can be at the IServiceBehavior level. In the service level ApplyDispatchBehavior method you need to loop through all its operations and assign the inspector behaviour.
My class in full...
[AttributeUsage(AttributeTargets.Class)]
public class ServiceLevelParameterInspectorAttribute : Attribute, IParameterInspector, IServiceBehavior
{
public object BeforeCall(string operationName, object[] inputs)
{
// Inspect the parameters.
return null;
}
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
}
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 (ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
if (channelDispatcher == null)
{
continue;
}
foreach(var endPoint in channelDispatcher.Endpoints)
{
if (endPoint == null)
{
continue;
}
foreach(var opertaion in endPoint.DispatchRuntime.Operations)
{
opertaion.ParameterInspectors.Add(this);
}
}
}
}
}