WCF service - initialization issue - c#

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().

Related

How can WCF service detect client disconnection

I have the following complete program (which can be copy-pasted-built-and-run. you might have to add a few references). The objective of the program is for the service to detect (e.g. receive a SocketException or IOException of some form or as attempted in the code via some event handling) that a connected client (tested/test from web-browser) has disconnected before the response has been fully delivered (see return statements in method Talk(string animal)). To reproduce the issue, there is a configurable parameter (see new AnimalTalkService(3)) which dictates how long the service will take to respond to a given request. And within this time frame, i can close the browser in order to raise the client-disconnection event (see method ClientDisconnected() in class ClientConnectionTracker). I am unable to get any exceptions thrown into the implementation of the service or get the Closed and Faulted events triggered. Would someone have an idea on how to go about to (implement) get the desired effect?
// Code:
using System;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Web;
using System.Threading;
namespace TestClientDisconnect
{
class ClientConnectionTracker : IChannelInitializer
{
public void Initialize(IClientChannel channel)
{
channel.Closed += ClientDisconnected;
channel.Faulted += ClientDisconnected;
}
private void ClientDisconnected(object sender, EventArgs e)
{
Console.WriteLine("Client Disconnected");
throw new NotImplementedException();
}
}
class ClientConnectionTrackerEndpointBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
endpointDispatcher.ChannelDispatcher.ChannelInitializers.Add(new ClientConnectionTracker());
}
public void Validate(ServiceEndpoint endpoint)
{
}
}
[ServiceContract]
interface IAnimalTalkService
{
[OperationContract]
[WebInvoke(UriTemplate = "/{animal}", Method = "GET")]
string Talk(string animal);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
class AnimalTalkService : IAnimalTalkService
{
private int delayInSeconds;
public AnimalTalkService(int delayInSeconds = 0)
{
this.delayInSeconds = delayInSeconds;
}
public string Talk(string animal)
{
Console.WriteLine("Creating sentence for animal {0} ...", animal);
if (delayInSeconds > 0)
{
// Simulate heavy duty work:
Thread.Sleep(1000 * delayInSeconds);
}
switch(animal.ToLower())
{
case "sheep":
return "baa";
case "dog":
return "woof";
case "cat":
return "miao";
default:
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.NotFound;
return null;
}
}
}
class Program
{
static void Main(string[] args)
{
AnimalTalkService serviceInstance = new AnimalTalkService(3);
Uri address = new Uri("http://127.0.0.1:1234/");
WebServiceHost host = new WebServiceHost(serviceInstance, address);
WebHttpBinding binding = new WebHttpBinding();
ServiceEndpoint endPoint = host.AddServiceEndpoint(typeof(IAnimalTalkService), binding, "");
endPoint.EndpointBehaviors.Add(new WebHttpBehavior() { DefaultOutgoingResponseFormat = WebMessageFormat.Json });
endPoint.EndpointBehaviors.Add(new ClientConnectionTrackerEndpointBehavior());
host.Open();
Console.WriteLine("Service is running at {0}. Press Enter key to exit", host.BaseAddresses[0]);
Console.ReadLine();
}
}
}
Thanks in advance.
The word "disconnection" implies a session, isn't it?
The best way, in my opinion, to have methods, that explicitly creates and terminates the session using an explicit session id (here I used an arbitrary type):
[ServiceContract]
public interface IWebService
{
[OperationContract]
SessionId BeginNewSession();
[OperationContract]
void DoSomething(SessionId id, ...);
[OperationContract]
void EndSession(SessionId id);
}
This is certainly recommended for HTTP protocol, which doesn't support transport-level sessions.
In this case you can write another class, that will housekeep outdated sessions which haven't been closed.
In case you use a binding that supports transport-level sessions, there is another option - to set up session-bound service instance management (and use corresponding binding), implement IDisposable interface in the service class and place the related code inside Dispose() method:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class TheService : IService, IDisposable
{
...
public void Dispose()
{
// code of session termination
...
}
}
Finally you can combine both options by marking the explicit session-terminating method with [OperationContract(IsTerminating = true)] attribute:
[ServiceContract(..., SessionMode=SessionMode.Required)]
public interface IService
{
[OperationContract(IsTerminating = true)]
void Close();
...
}

How to inject object into WCF's IErrorHandler?

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.

Type casting issue in C# and wcf header in .NET

I am now developing a WCF service using visual studio 2013 . My service contains a custom header field must be passed. Field name is "lisenseKey" I developed it. WCF service is working fine. Now I am about to call my service to test. I added a service reference to client project. Now I am calling like this:
MyService.Myservice proxy = new MyService.Myservice();
proxy.LisenseKey = "xxxxxx";
Label1.Text = proxy.GetMessage(TextBox1.Text);
When I assign license key value like this, it is showing error with red underline that:
"Cannot implicitly convert type string to MyService.MyService.string"
How can I type cast in this condition? Or is there any way to pass header? And I do not know how to use "MessageHeader".
Here is my service code . I am just trying to consume "GetMessage" method .
[ServiceContract]
public interface IMyservice
{
[OperationContract]
void DoWork();
[OperationContract]
string GetMessage(string name);
}
public class MyServiceMessageInspector:System.ServiceModel.Dispatcher.IDispatchMessageInspector
{
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request,System.ServiceModel.IClientChannel channel,
System.ServiceModel.InstanceContext instanceContext)
{
if(request.Headers.FindHeader("LisenseKey","")==-1)
{
throw new FaultException("Lisense Key Was Not Provided");
}
var lisenseKey = request.Headers.GetHeader<string>("LisenseKey", "");
if (string.IsNullOrEmpty(lisenseKey))
{
throw new FaultException("Lisnse key is not valid");
}
if(lisenseKey!="12345x")
{
throw new FaultException("Lisense key is not valid");
}
return instanceContext;
}
public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply,object correlationState)
{
}
}
public class MyServiceMessageInspectorBehaviour:Attribute,System.ServiceModel.Description.IServiceBehavior
{
public void AddBindingParameters(System.ServiceModel.Description.ServiceDescription serviceDescription,
System.ServiceModel.ServiceHostBase serviceHostBase,
System.Collections.ObjectModel.Collection<System.ServiceModel.Description.ServiceEndpoint> endpoints,
System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(System.ServiceModel.Description.ServiceDescription serviceDescription,
System.ServiceModel.ServiceHostBase serviceHostBase)
{
foreach(ChannelDispatcher channelDispatcher in serviceHostBase.ChannelDispatchers)
{
foreach(var endpointDispatcher in channelDispatcher.Endpoints)
{
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new MyServiceMessageInspector());
}
}
}
public void Validate(System.ServiceModel.Description.ServiceDescription serviceDescription,System.ServiceModel.ServiceHostBase serviceHostBase)
{
}
}

wcf :custom message inspector does not get wired up

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());
}
}

Switch service contract implementation at runtime in WCF

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

Categories

Resources