where is the right place to add IOperationBehavior programmatically - wcf

how can i add IOperationBehavior programmatically when running on iis ?
not on custom wcf host.
thanks
Ali TAKAVCI

You could attach it as an attribute:
public class CustomInspectorAttribute : Attribute, IOperationBehavior, IParameterInspector
{
#region IOperationBehavior Members
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
// Attribute could be used on client side
clientOperation.ParameterInspectors.Add(this);
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
// Attribute could be used on server side
dispatchOperation.ParameterInspectors.Add(this);
}
public void Validate(OperationDescription operationDescription)
{
}
#endregion
#region IParameterInspector Members
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
// Do something with returned values from operation
}
public object BeforeCall(string operationName, object[] inputs)
{
// Do something with incoming parameters before invoking actual operation
return null;
}
#endregion
}
And attach the attribute to an operation
[ServiceContract]
public interface ICustomServiceContract
{
[CustomInspector]
[OperationContract]
void MyOperation();
}

You need to build a custom service host, then set your .svc file to use it. In the custom service host you can do whatever you like to the service before it starts, including setting behaviours. Because you want to use operation behaviours you should do it in the OnOpening() method - as the service factory applies resets the operation behaviours after endpoint behaviours are configured. You will be able to iterate through the endpoints and the operations in OnOpening.

Related

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

How do you implement a base method that should be called for all the methods?

I have a Product Service. On each call to Service, I want to call a method. In this case, I am logging. I am looking for a way, not to write the using statement in each method. But I still want the Logging to happen on each call. How do I do this?
public class ProductService : IProductService
{
public IList<Product> GetProductsByBrand(int BrandID)
{
using (new Logging())
{
// Get a list of products By Brand
}
return new List<Product>();
}
public IList<Product> Search(string ProductName)
{
using (new Logging())
{
// Search
}
return new List<Product>();
}
public static string OrderProducts(IList<Order> Orders, Payment paymentDetials)
{
string AuthCode;
using (new Logging())
{
// Order and get the AuthCode
}
AuthCode = "";
return AuthCode;
}
}
Have you heard of AOP (Aspect Oriented Programming)? It's a way of implementing cross cutting concerns as reusable Aspects that wrap around the target type and perform additional processing before or after the method that they are wrapping.
http://en.wikipedia.org/wiki/Decorator_pattern
Within a WCF environment this is typically done by applying "Behaviors" to your service class. In this case I would suggest the IOperationBehavior interface using an attribute that implements IParameterInspector in order to look at the parameters before they are passed the service instance is created and called. Here is a link to a useful article that goes into more depth regarding your options for extending the wcf message pipeline.
http://msdn.microsoft.com/en-us/magazine/cc163302.aspx
//Attribute class
public class LogOperationBehavior : Attribute, IOperationBehavior, IParameterInspector {
public void AddBindingParameters(OperationDescription operationDescription, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) {
return;
}
public void ApplyClientBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.ClientOperation clientOperation) {
//clientOperation.ParameterInspectors.Add(new ClientParameterInspector());
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, System.ServiceModel.Dispatcher.DispatchOperation dispatchOperation) {
dispatchOperation.ParameterInspectors.Add(this);
}
public void Validate(OperationDescription operationDescription) {
return;
}
#region IParameterInspector Members
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) {
//perform logging after
}
public object BeforeCall(string operationName, object[] inputs) {
//perform logging before
return null;
}
#endregion
}
public class BusinessOperation : IBusinessOperation {
//Apply to your service via an attribute
[LogOperationBehavior]
public DivideResponse DivideTwoNumbers(DivideRequest dr) {
return new DivideResponse() {
Answer = dr.Numerator/ dr.Demoninator2,
};
}
Have you considered creating a logging proxy? It would look something like this:
public class LoggingProductService : IProductService
{
private readonly IProductService _core;
public LoggingProductService(IProductService core)
{
_core = core;
}
public IList<Product> GetProductsByBrand(int BrandID)
{
Log("Getting products for brand " + BrandId);
return _core.GetProductsByBrand(BrandId);
}
//other IProductService methods here, all logging and delegating to _core
private void Log(string message)
{
using (var log = new Logging())
{
log.Write(message);
}
}
}
Of course, I don't entirely understand your Logging interface, so fill in the appropriate guesses with correct code. You also may not want to create and Dispose a Logging that often, I don't know.
You can create a dynamic proxy. See this article for instructions. http://www.drdobbs.com/windows/184405378

After Enable IDispatchMessageFormatter I see nullable parameters in service

after add my formatter to operation behavior :
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
ServerMessageFormatter Formatter = new ServerMessageFormatter();
dispatchOperation.Formatter = Formatter;
}
In Formatter I have empty Deserialize method cause I want to use default behavior
public void DeserializeRequest(System.ServiceModel.Channels.Message message, object[] parameters)
{}
but In Serialize
public System.ServiceModel.Channels.Message SerializeReply(System.ServiceModel.Channels.MessageVersion messageVersion, object[] parameters, object result)
{
//some code
}
Problem is that after enable this class, parameters in service method always was show as null, but in IDispatchMessageInspector class I see that parameters is send properly. I don't know why it's happening, I only add this message formatter code , it is possible that empty class for Deserialize causes this ?
When we are implementing IDispatchMessageFormatter interface usually we are not thinking that method DeserializeRequest is something important as it is not returning any data. This is misleading as method needs to do something.
The easiest way to make parameters correctly passed is to use base DispatchMessageFormatter. Add it to the constructor.
public class ResponseJsonFormatter : IDispatchMessageFormatter
{
IDispatchMessageFormatter basicDispatchMessageFormatter;
OperationDescription Operation;
public ResponseJsonFormatter(OperationDescription operation, IDispatchMessageFormatter inner)
{
this.Operation = operation;
this.basicDispatchMessageFormatter = inner;
}
public void DeserializeRequest(Message message, object[] parameters)
{
basicDispatchMessageFormatter.DeserializeRequest(message, parameters);
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
string json=Newtonsoft.Json.JsonConvert.SerializeObject(result);
byte[] bytes = Encoding.UTF8.GetBytes(json);
Message replyMessage = Message.CreateMessage(messageVersion, Operation.Messages[1].Action, new RawDataWriter(bytes));
replyMessage.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));
return replyMessage;
}
}
And initiate it in the behavior:
public class ClientJsonDateFormatterBehavior : IOperationBehavior
{
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{
// throw new NotImplementedException();
}
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{
}
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.Formatter = new ResponseJsonFormatter(operationDescription, dispatchOperation.Formatter);
}
public void Validate(OperationDescription operationDescription)
{
// throw new NotImplementedException();
}
}
You can check the working example here in the github branch DateTimeFormatterWithParams
There is no default behavior if you do not provide your own logic on DeserializeRequest. You need to either reference the existing formatter and delegate manually in your ServerMessageFormater or provide your own logic.

How can I extend WCF in the Callback direction?

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.

WCF shared IClientMessageInspector instance across multiple clients

I'm managing a shared auth cookie when making WCF service calls via this methodology outlined under the header "Centralized cookie management" located here: http://megakemp.com/2009/02/06/managing-shared-cookies-in-wcf/
I've set up a custom IClientMessageInspector, IEndpointBehavior, BehaviorExtensionElement, the works. My endpoint behavior adds a message inspector as follows:
public class MyEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
// yuck.. Wish I had an instance of MyClientMessageInspector
// (which has the auth cookie already) so I could just inject that
// instance here instead of creating a new instance
clientRuntime.MessageInspectors.Add(new MyClientMessageInspector());
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
It all works flawlessly, but this solution breaks down when you want to share cookies over multiple clients. Because the ApplyDispatchBehavior() method creates a new instance, any other client wouldn't get that message inspector instance, and thus, the auth ticket.
So then I thought of trying to create a custom constructor where I could inject the instance like so:
MyEndpointBehavior(MyClientMessageInspector msgInspector) { ... }
But, WCF needs parameter-less constructors. Weeding through the internets, WCF has hooks to allow for dependency injection, creating an IInstanceProvider, IServiceBehavior, etc. But I don't think that's what I'm looking for here.
Can anyone help guide me in the right direction?
You need only extend the concept so that you store the cookie outside of the message inspector itself so that all instances of the message inspector share the same storage.
The poor man's way, just to get started, would be to just use a static field instead of an instance field. Obviously if you have multiple threads you'll need to provide concurrency while updating the field. From there you can get even fancier if you extrapolate it out to a cookie container concept and then just make sure you share the same container with all clients. Sharing the container can be done by getting the ChannelParameterCollection for the client channel and adding property to it and then your behavior looks for that property while it's inspecting the mssage and pulling the cookies out of that. That would look a little something like this:
App logic
// Hold onto a static cookie container
public static CookieContainer MyCookieContainer;
// When instantiating the client add the cookie container to the channel parameters
MyClient client = new MyClient();
client.InnerChannel.GetProperty<ChannelParameterCollection>().Add(MyCookieContainer);
Message inspector logic
public void BeforeSendMessage(ref Message, IClientChannel clientChannel)
{
// Find the cookie container for the current channel
CookieContainer cookieContainer = clientChannel.GetProperty<ChannelParameterCollection>().Select(p => p as CookieContainer).Where(cc => cc != null).First();
// ... use the cookie container to set header on outgoing context ...
}
You're correct, IInstanceProvider won't help in your case - it's used for providing service instances only. You don't need a parameterless constructor for your behavior. You need a paramterless constructor for the config element, and this class can use some dependency injection class (see below) to create the appropriate inspector class needed for the behavior.
namespace ConsoleApplication4
{
public class MyEndpointBehavior : IEndpointBehavior
{
IClientMessageInspector inspector;
public MyEndpointBehavior(IClientMessageInspector inspector)
{
this.inspector = inspector;
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(this.inspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
public class MyEndpointBehaviorElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(MyEndpointBehavior); }
}
protected override object CreateBehavior()
{
return new MyEndpointBehavior(ClientInspectorFactory.GetClientInspector());
}
}
public class MyClientInspector : IClientMessageInspector
{
public MyClientInspector()
{
}
public void AfterReceiveReply(ref Message reply, object correlationState)
{
Console.WriteLine("AfterReceiveReply");
}
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
Console.WriteLine("BeforeSendRequest");
return null;
}
}
public static class ClientInspectorFactory
{
static IClientMessageInspector instance;
public static IClientMessageInspector GetClientInspector()
{
if (instance == null)
{
instance = new MyClientInspector();
}
return instance;
}
}
[ServiceContract]
public interface ITest
{
[OperationContract]
int Add(int x, int y);
}
public class Service : ITest
{
public int Add(int x, int y) { return x + y; }
}
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(Service));
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<ITest> factory = new ChannelFactory<ITest>("client1");
ITest proxy = factory.CreateChannel();
Console.WriteLine(proxy.Add(3, 4));
((IClientChannel)proxy).Close();
factory.Close();
factory = new ChannelFactory<ITest>("client2");
proxy = factory.CreateChannel();
Console.WriteLine(proxy.Add(5, 8));
((IClientChannel)proxy).Close();
factory.Close();
host.Close();
}
}
}
I liked the answers provided by #carlosfigueira and #drew, but I ultimately came up with a slightly different approach. I opted to configure my IEndpointBehavior PROGRAMMATICALLY, vs via config. Made things much simpler. I changed my endpoint behavior to store my client message inspector as follows:
public class MyEndpointBehavior : IEndpointBehavior
{
private MyClientMessageInspector_myClientMessageInspector;
public MyClientMessageInspector MyClientMessageInspector
{
get
{
if (_myClientMessageInspector == null)
{
_myClientMessageInspector = new MyClientMessageInspector();
}
return _myClientMessageInspector;
}
}
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(MyClientMessageInspector);
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
Then I simply shared this behavior between clients, as follows:
var behavior = new MyEndpointBehavior();
client1.Endpoint.Behaviors.Add(behavior);
client2.Endpoint.Behaviors.Add(behavior);
Now both clients will share the same auth cookie.