Created
March 17, 2013 17:02
-
-
Save vwxyzh/5182489 to your computer and use it in GitHub Desktop.
Wcf and CallContext
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Runtime.Remoting.Messaging; | |
using System.Runtime.Serialization; | |
using System.ServiceModel; | |
using System.ServiceModel.Channels; | |
using System.ServiceModel.Description; | |
using System.ServiceModel.Dispatcher; | |
namespace WcfContextTest | |
{ | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
const string address = "net.tcp://127.0.0.1:1234/"; | |
ServiceHost host = new ServiceHost(typeof(TestImpl)); | |
host.AddServiceEndpoint(typeof(ITest), new NetTcpBinding(), address); | |
host.Open(); | |
var cf = new ChannelFactory<ITest>(new NetTcpBinding(), new EndpointAddress(address)); | |
foreach (var op in cf.Endpoint.Contract.Operations) | |
op.OperationBehaviors.Add(new ContextInjectBehavior()); | |
var c = cf.CreateChannel(); | |
Console.WriteLine("Without context:"); | |
Console.WriteLine("Response is: {0}", c.Test(new TestReq { Id = 1 }).Name); | |
Console.WriteLine("Context is: {0}", CallContext.LogicalGetData("WcfContext") ?? "(null)"); | |
Console.WriteLine("With context: Hello"); | |
CallContext.LogicalSetData("WcfContext", "Hello"); | |
Console.WriteLine("Response is: {0}", c.Test(new TestReq { Id = 1 }).Name); | |
Console.WriteLine("Context is: {0}", CallContext.LogicalGetData("WcfContext") ?? "(null)"); | |
((ICommunicationObject)c).Close(); | |
host.Close(); | |
} | |
} | |
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] | |
public sealed class ContextInjectAttribute : Attribute, IServiceBehavior | |
{ | |
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { } | |
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) | |
{ | |
foreach (var ep in serviceDescription.Endpoints) | |
foreach (var op in ep.Contract.Operations) | |
op.OperationBehaviors.Add(new ContextInjectBehavior()); | |
} | |
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } | |
} | |
public sealed class ContextInjectBehavior : IOperationBehavior | |
{ | |
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { } | |
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) | |
{ | |
clientOperation.Formatter = new MyClientMessageFormatter(clientOperation.Formatter); | |
} | |
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) | |
{ | |
dispatchOperation.Formatter = new MyDispatchMessageFormatter(dispatchOperation.Formatter); | |
} | |
public void Validate(OperationDescription operationDescription) { } | |
} | |
public class MyDispatchMessageFormatter : IDispatchMessageFormatter | |
{ | |
private readonly IDispatchMessageFormatter m_inner; | |
public MyDispatchMessageFormatter(IDispatchMessageFormatter inner) | |
{ | |
m_inner = inner; | |
} | |
public void DeserializeRequest(Message message, object[] parameters) | |
{ | |
int index = message.Headers.FindHeader("context", "urn:context"); | |
if (index != -1) | |
{ | |
var reader = message.Headers.GetReaderAtHeader(index); | |
CallContext.LogicalSetData("WcfContext", reader.ReadString()); | |
} | |
m_inner.DeserializeRequest(message, parameters); | |
} | |
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result) | |
{ | |
var msg = m_inner.SerializeReply(messageVersion, parameters, result); | |
var context = CallContext.LogicalGetData("WcfContext") as string; | |
if (context != null) | |
{ | |
msg.Headers.Add(MessageHeader.CreateHeader("context", "urn:context", context, false)); | |
CallContext.FreeNamedDataSlot("WcfContext"); | |
} | |
return msg; | |
} | |
} | |
public class MyClientMessageFormatter : IClientMessageFormatter | |
{ | |
private readonly IClientMessageFormatter m_inner; | |
public MyClientMessageFormatter(IClientMessageFormatter inner) | |
{ | |
m_inner = inner; | |
} | |
public object DeserializeReply(Message message, object[] parameters) | |
{ | |
var result = m_inner.DeserializeReply(message, parameters); | |
int index = message.Headers.FindHeader("context", "urn:context"); | |
if (index != -1) | |
{ | |
var reader = message.Headers.GetReaderAtHeader(index); | |
CallContext.LogicalSetData("WcfContext", reader.ReadString()); | |
} | |
return result; | |
} | |
public Message SerializeRequest(MessageVersion messageVersion, object[] parameters) | |
{ | |
var msg = m_inner.SerializeRequest(messageVersion, parameters); | |
var context = CallContext.LogicalGetData("WcfContext") as string; | |
if (context != null) | |
msg.Headers.Add(MessageHeader.CreateHeader("context", "urn:context", context, false)); | |
return msg; | |
} | |
} | |
[ServiceContract] | |
public interface ITest | |
{ | |
[OperationContract] | |
TestResp Test(TestReq req); | |
} | |
[DataContract] | |
public class TestReq | |
{ | |
[DataMember] | |
public int Id { get; set; } | |
} | |
[DataContract] | |
public class TestResp | |
{ | |
[DataMember] | |
public string Name { get; set; } | |
} | |
[ContextInject] | |
public class TestImpl | |
: ITest | |
{ | |
public TestResp Test(TestReq req) | |
{ | |
var context = CallContext.LogicalGetData("WcfContext") as string; | |
var result = new TestResp { Name = context + req.Id.ToString() }; | |
if (context != null) | |
{ | |
context = "great!"; | |
CallContext.LogicalSetData("WcfContext", context); | |
} | |
return result; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment