Will WCF use the same ParameterInspector instance to handle BeforeCall and AfterCall? - wcf

If I create a class that implements IParameterInspector, and insert it into the WCF pipline using a custom ServiceBehavior, will the same instance of the class be used when invoking BeforeCall and AfterCall? In other words, can I establish state about the current invocation during BeforeCall that I can access in AfterCall, and be sure that the response will come to the same instance?
Note _stateValue in the sample code below? Can I depend on a mechanism like this?
class OperationParameterInspector : IParameterInspector
{
public int _stateValue;
public object BeforeCall(string operationName, object[] inputs)
{
_stateValue = (int) inputs[0];
return null;
}
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
int originalInput = _stateValue;
return;
}
}

Passing state related to a particular call is the purpose of the return value from BeforeCall and the correlationState argument of AfterCall. The WCF infrastructure ensures that whatever object you return from BeforeCall is then passed into AfterCall via the correlationState, after the operation has completed.
As your subsequent comment suggests, the problem with using instance state in the inspector object is that instances may be shared between concurrent requests in some scenarios. However, I don't think there are any scenarios where a single operation request would be served by different parameter inspector objects in BeforeCall and AfterCall.

Related

Difference between .Resolve and .Get in Ninject

Just wanted to get some clarrification over the difference between Kernel.Resolve and Kernel.Get in ninject.
Description for Kernel.Get states
gets an instance of the specified service by using the first binding that matches the specified constraints
Description for Kernel.Resolve states
Resolves instances for the specified request. The instances are not actually resolved until a consumer iterates over the enumeration.
In which situations might you use either of these? (Right now I'm using Get exclusively)
Kernel.Get is an extension method (or a set of extension methods to be more precise) which live in ResolutionExtensions.cs.
Kernel.Resolve is a method of IResolutionRoot.cs which is implemented by IKernel.
Only by reading the description of the methods we can recon two things:
ResolutionExtensions.Get<T>(this IResolutionRoot root) only returns the first match, which is resolved when the method is executed.
IResolutionRoot.Resolve(IRequest request) returns an IEnumerable<T>, this enumerable will resolve each match only when enumerated, and there can be more than one match.
Upon closer inspection, ResolutionExtensions.Get<T>(this IResolutionRoot root)'s implementation is:
public static T Get<T>(this IResolutionRoot root, params IParameter[] parameters)
{
return GetResolutionIterator(root, typeof(T), null, parameters, false, true).Cast<T>().Single();
}
And GetResolutionIterator's implementation is
private static IEnumerable<object> GetResolutionIterator(IResolutionRoot root, Type service, Func<IBindingMetadata, bool> constraint, IEnumerable<IParameter> parameters, bool isOptional, bool isUnique)
{
Ensure.ArgumentNotNull(root, "root");
Ensure.ArgumentNotNull(service, "service");
Ensure.ArgumentNotNull(parameters, "parameters");
IRequest request = root.CreateRequest(service, constraint, parameters, isOptional, isUnique);
return root.Resolve(request);
}
Which is essentially a wrapper method to IResolutionRoot.Resolve
So ResolutionExtensions.Get<T>(this IResolutionRoot root) is enumerating IResolutionRoot.Resolve using Enumerable.Single.
Conclusion
Kernel.Get() == Kernel.Resolve().Single()

Bad NLog callsite for a WCF logging behavior

I am writing a logging behavior like in this blog by Pieter de Rycke, but for NLog. I came up with this code:
public class NLogLogger : IParameterInspector
{
private void Log(Type instanceType, string operationName, string msg)
{
NLog.Logger logger = LogManager.GetLogger(
instanceType.FullName, instanceType);
logger.Info(msg, instanceType);
}
public object BeforeCall(string operationName, object[] inputs)
{
// Retrieve the service instance type for the logger then log the call.
OperationContext operationContext = OperationContext.Current;
Type instanceType = operationContext.InstanceContext
.GetServiceInstance().GetType();
Log(instanceType, operationName, "BeforeCall");
return instanceType;
}
public void AfterCall(
string operationName, object[] outputs,
object returnValue, object correlationState
)
{
if (correlationState is Type)
Log(correlationState as Type, operationName, "AfterCall");
}
}
The logging behavior works fine. I injected it into the service Example.MyService using an attribute as described by Pieter. I have this layout in an NLog target:
${longdate} ${callsite} ${level:uppercase=true} ${message}
However the callsite for the operation GetContacts is wrong:
2013-07-11 13:32:53.1379 Common.NLogLogger.Log INFO BeforeCall
2013-07-11 13:32:53.7121 Common.NLogLogger.Log INFO AfterCall
Correct would be this:
2013-07-11 13:32:53.1379 Example.MyService.GetContacts INFO BeforeCall
2013-07-11 13:32:53.7121 Example.MyService.GetContacts INFO AfterCall
What have I tried?
NLog offers a special handling of callsite for logging wrappers or facades, as described in this StackOverflow answer: Pass the class of the callsite to the logging methods.
In fact I did this with logger.Info(msg, instanceType) above in the Log() method. However this does not work because the callsite is not yet in the stack trace when the behavior's BeforeCall() method is running. WCF has not yet even started to run the operation. NLog does not find the callsite in the stack trace and is not capable to unwrap the stack trace.
How can I fake a callsite? Or how can I display the "right" callsite for the logging behavior?
UPDATE:
Thanks to your clarification, I better understand what you are trying to do. You would like the messages logged from the IParameterInspector implementation to reflect a call site of "Example.MyService.GetContacts" where Example.MyService is your service (as indicated by the instanceType parameter) and "GetContacts" is the operation. You could synthesize the call site information manually. You would still use NLog's Logger.Log method and you would still create a LogEventInfo object. Additionally, you can store the "class" and "method" in the LogEventInfo.Properties object. Rather than retrieving a logger (from LogManager) based on the instanceType (i.e. the service), retrieve the logger based on the type of the parameter inspector (NLogLogger in your case). Finally, you can add an additional rule to your NLog.config (and apply it to the NLogLogger type) so that rule has a different logging format. You will manually add a field to the logging format that contains the call site information (that you stored in the LogEventInfo.Properties collection) in the same position as the "real" callsite LayoutRenderer in your other logging rule configurations.
Next I will post a new version of your NLogLogger implementation that does what I described above.
public class NLogLogger : IParameterInspector
{
private static readonly NLog.Logger logger = LogManager.GetCurrentClassLogger();
private void Log(Type instanceType, string operationName, string msg)
{
NLog.Logger serviceLogger = LogManager.GetLogger(
instanceType.FullName, instanceType);
//Create LogEventInfo with the Logger.Name from the logger associated with the service
LogEventInfo le = new LogEventInfo(LogLevel.Info, serviceLogger.Name, msg);
le.Properties.Add("fakecallsite", string.Format("{0}.{1}",instanceType.ToString(),operationName);
//Log the message using the parameter inspector's logger.
logger.Log(typeof(NLogLogger), le);
}
public object BeforeCall(string operationName, object[] inputs)
{
// Retrieve the service instance type for the logger then log the call.
OperationContext operationContext = OperationContext.Current;
Type instanceType = operationContext.InstanceContext
.GetServiceInstance().GetType();
Log(instanceType, operationName, "BeforeCall");
return instanceType;
}
public void AfterCall(
string operationName, object[] outputs,
object returnValue, object correlationState
)
{
if (correlationState is Type)
Log(correlationState, operationName, "AfterCall");
}
}
Your NLog.config will have rules something like this. One rule is specifically for your NLogLogger Parameter Inspector. It logs to "f1" and is a "final" rule, meaning that logging messages from the parameter inspector won't be logged by any other rules. The other rule is for all other loggers. Each logs to a different file target, but both file targets write to the same file (which works, I think). The key is that each file has its own layout.
<logger name="Your.Full.NameSpace.NLogLogger" minlevel="*" writeTo="f1" final="true" />
<logger name="*" minlevel="*" writeTo="f2" />
Your targets and layouts would look something like this. We are defining a variable whose value is the value of the EventPropertiesLayoutRenderer, which is the fake call site that we stored in LogEventInfo.Properties["fakecallsite"].
<variable name="fakecallsite" value="${event-properties:fakecallsite}"/>
<variable name="f1layout" value="${longdate} | ${level} | ${logger} | ${fakecallsite} | ${message}"/>
<variable name="f2layout" value="${longdate} | ${level} | ${logger} | ${callsite} | ${message}"/>
<targets>
<target name="f1" xsi:type="File" layout="${f1layout}" fileName="${basedir}/${shortdate}.log" />
<target name="f2" xsi:type="File" layout="${f2layout}" fileName="${basedir}/${shortdate}.log" />
</targets>
Note that I have not tried this, but I think it should work (or should be close enough that you can get it working). One limitation is that, since we are calculating the fake call site, we cannot use the real callsite LayoutRenderer to manipulate the contents of the fakecallsite field in the output. If this important, it can probably be simulated by storing the class and method separately (in LogEventInfo.Properties) and then setting the "fakecallsite" variable in the NLog.config to contain the class, the method, or both.
END UPDATE
Your wrapper should use the Log method. Also, the type you pass to the NLog Logger.Log method should be the type of your NLog Logger wrapper, not the type of the type of the service instance. You can still use the type of your service instance to retrieve the right Logger instance. It should look something like this:
public class NLogLogger : IParameterInspector
{
private void Log(Type instanceType, string operationName, string msg)
{
NLog.Logger logger = LogManager.GetLogger(
instanceType.FullName, instanceType);
//This is the key to preserving the call site in a wrapper. Create a LogEventInfo
//then use NLog's Logger.Log method to log the message, passing the type of your
//wrapper as the first argument.
LogEventInfo le = new LogEventInfo(LogLevel.Info, logger.Name, msg);
logger.Log(typeof(NLogLogger), le);
}
public object BeforeCall(string operationName, object[] inputs)
{
// Retrieve the service instance type for the logger then log the call.
OperationContext operationContext = OperationContext.Current;
Type instanceType = operationContext.InstanceContext
.GetServiceInstance().GetType();
Log(instanceType, operationName, "BeforeCall");
return instanceType;
}
public void AfterCall(
string operationName, object[] outputs,
object returnValue, object correlationState
)
{
if (correlationState is Type)
Log(correlationState, operationName, "AfterCall");
}
}

Syncing correlationstate between IClientMessageInspector and IParameterInspector

I have a wcf client. According to requirements, I need to record some of the metadata in the request (as well as user data which is not included in the request.) Then, if the request is successful I may have to record response metadata and depending on flags, the full soap request.
I am trying to do this the right way (using IParameterInspector to examine the metadata and IClientMessageInspector to get the Soap), but I have no way of correlating the two Interface requests. I am not sure about thread safety here. This is a stripped down version of where I am at...
public class SoapRequestInfo
{
public string UserId { get; set; }
public Guid Key { get; set; }
//would contain a lot more info
}
public class OperationProfilerParameterInspector : IParameterInspector, IClientMessageInspector
{
//before serialization
public object BeforeCall(string operationName, object[] inputs) //IParameterInspector
{
//Add the operation, record some specific inputs to db
return new SoapRequestInfo
{
UserId = "1234",
Key = new Guid()
};
}
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState) //IParameterInspector
{
var info = correlationState as SoapRequestInfo;
//Do some additional logging - easy enough
}
public object BeforeSendRequest(ref Message request, IClientChannel channel) //IClientMessageInspector
{
//want to correlate this with IParameterInspector
return null;
}
public void AfterReceiveReply(ref Message reply, object correlationState) //IClientMessageInspector
{
//May want to log full soap message depending on after call criteria
}
}
I know I can't use a private variable to hold the Guid. I can't use session, because there can be multiple requests in close succession and can't guarantee the response is correct. So how can I uniquely identify the correlationState between the two interfaces?
You can probably use HttpContext.Items to keep your object if your service is running in ASPNET compatibility mode otherwise you can use TLS (Thread Local Storage), put the data in a slot and fetch/clear later.
May eb you can tro to do this little bit diffrent:
From this post passing correlation token to WCF service?:
If you use message version with WS-Addressing you should have it automatically because each messages will contain its autogenerated ID (guid) and each response will contain ID of the request as well. You can access these headers through OperationContext
If using messages is not fit your requirements, probably you can try to put your own id in the header when you send request, and probably update the response with same id.

WCF: Returning a derived object for a contract with base object (DataContractResolver)

I have have a WCF derived/base contract issue. I have a server interface/contract that returns a BaseThing object:
[OperationContract]
BaseThing Get_base_thing();
The server that implements this has a DerivedThing (derived from BaseThing) and wants to return this as a BaseThing. How to tell WCF that I only want to transport the BaseThing part of DerivedThing?
If in Get_base_thing I just return a reference to a DerivedThing then I get a SerializationException server side.
I think I need to define a DataContractResolver and I looked at the MSDN article Using a Data Contract Resolver but this is not 100% clear (to me a least).
How should my DataContractResolver look to tell WCF to only transport the base part of the derived object I pass it?
Is there some way to do this more simply just with KnownType attribue?
KnownType will not resolve this issue.
It sounds as if you have a serious divergence between the object model you're using at the server and the service contracts you're using. There seems to be 3 possible solutions:
1) Data Contract Resolver as you've identified to make it automatic across all your operations. There are a number of examples out there including this one: http://blogs.msdn.com/b/youssefm/archive/2009/06/05/introducing-a-new-datacontractserializer-feature-the-datacontractresolver.aspx.
2) Align your object model to better match your service contracts. That is, use containment rather than inheritance to manage the BaseThing-DerivedThing relationship. That way you work with DerivedThing at the server and simply return DerivedThing.BaseThing over the wire. If BaseThing needs to get transmitted from client to server, this will also work better.
3) Use explicit conversion using something like AutoMapper so it is obvious in your operations that there is a divergence between the objects being used at the server and those exposed to the outside world.
After posting I also found this SO identical question How to serialize a derived type as base. The unaccepted second answer by marc for me is the easiest way to resolve this issue. That is:
Decorate the derived class with [DataContract(Name="BaseClass")]
Note that this solution means that derived will transport as base for all every case of transport of this object. For me that was not an issue if it is then you need to go the DataContractResolver route.
Some notes on the DataContractResolver route:
1. This enables you to pass the derived as derived on some calls but as base on other - if you need to do that - if not use about Name= approach.
2. I get an exception using the DeserializeAsBaseResolver from the datacontractrsolver article as it stands because the knownTypeResolver returns false. To fix that I ignor the return value of that call and always return true from TryResolveType. That seems to work.
3. I initially thought that because we were serializing as base that I didnt need [DataContract] on the derived class. That was wrong. The object is serialized as the derived object and derserialized as a base object - so you must decorate the derived with [DataContract] but don't mark any fields as [DataMembers] to avoid them being unnecessarily serialize.
4. If you have a command line host and a service host then you need the code to insert the contract resolver in both. I found it useful to put this as a static in my resolver.
5. Note that that the "Get_gateway_data" string in the call to cd.Operations.Find("Get_gateway_data") is the name of the contract method that returns the object concerned. You will need to do this for each call that you want this behaviour.
Final code for this approach:
public class DeserializeAsBaseResolver : DataContractResolver {
public static void Install(ServiceHost service_host) {
// Setup DataContractResolver for GatewayProcessing to GatewayData resolution:
ContractDescription cd = service_host.Description.Endpoints[0].Contract;
OperationDescription myOperationDescription = cd.Operations.Find("Get_gateway_data");
DataContractSerializerOperationBehavior serializerBehavior = myOperationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (serializerBehavior == null) {
serializerBehavior = new DataContractSerializerOperationBehavior(myOperationDescription);
myOperationDescription.Behaviors.Add(serializerBehavior);
}
serializerBehavior.DataContractResolver = new DeserializeAsBaseResolver();
}
public override bool TryResolveType(Type type, Type declaredType,
DataContractResolver knownTypeResolver,
out XmlDictionaryString typeName,
out XmlDictionaryString typeNamespace) {
bool ret = knownTypeResolver.TryResolveType(type, declaredType, null, out typeName, out typeNamespace);
//return ret; // ret = false which causes an exception.
return true;
}
public override Type ResolveName(string typeName, string typeNamespace,
Type declaredType, DataContractResolver knownTypeResolver) {
return knownTypeResolver.ResolveName(typeName, typeNamespace, declaredType, null) ?? declaredType;
}
Host code (service or command line):
using (ServiceHost service_host = new ServiceHost(typeof(GatewayServer))) {
// Setup DataContractResolver for GatewayProcessing to GatewayData resolution:
DeserializeAsBaseResolver.Install(service_host);
// Open the host and start listening for incoming messages.
try { service_host.Open(); }

Decoupling Silverlight client from service reference generated class

I am researching Prism v2 by going thru the quickstarts. And I have created a WCF service with the following signature:
namespace HelloWorld.Silverlight.Web
{
[ServiceContract(Namespace = "http://helloworld.org/messaging")]
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class HelloWorldMessageService
{
private string message = "Hello from WCF";
[OperationContract]
public void UpdateMessage(string message)
{
this.message = message;
}
[OperationContract]
public string GetMessage()
{
return message;
}
}
}
When I add a service reference to this service in my silverlight project it generates an interface and a class:
[System.ServiceModel.ServiceContractAttribute
(Namespace="http://helloworld.org/messaging",
ConfigurationName="Web.Services.HelloWorldMessageService")]
public interface HelloWorldMessageService {
[System.ServiceModel.OperationContractAttribute
(AsyncPattern=true,
Action="http://helloworld.org/messaging/HelloWorldMessageService/UpdateMessage",
ReplyAction="http://helloworld.org/messaging/HelloWorldMessageService/UpdateMessageResponse")]
System.IAsyncResult BeginUpdateMessage(string message, System.AsyncCallback callback, object asyncState);
void EndUpdateMessage(System.IAsyncResult result);
[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://helloworld.org/messaging/HelloWorldMessageService/GetMessage", ReplyAction="http://helloworld.org/messaging/HelloWorldMessageService/GetMessageResponse")]
System.IAsyncResult BeginGetMessage(System.AsyncCallback callback, object asyncState);
string EndGetMessage(System.IAsyncResult result);
}
public partial class HelloWorldMessageServiceClient : System.ServiceModel.ClientBase<HelloWorld.Core.Web.Services.HelloWorldMessageService>, HelloWorld.Core.Web.Services.HelloWorldMessageService {
{
// implementation
}
I'm trying to decouple my application by passing around the interface instead of the concrete class. But I'm having difficulty finding examples of how to do this. When I try and call EndGetMessage and then update my UI I get an exception about updating the UI on the wrong thread. How can I update the UI from a background thread?
I tried but I get UnauthorizedAccessException : Invalid cross-thread access.
string messageresult = _service.EndGetMessage(result);
Application.Current.RootVisual.Dispatcher.BeginInvoke(() => this.Message = messageresult );
The exception is thrown by Application.Current.RootVisual.
Here is something I like doing... The service proxy is generated with an interface
HelloWorldClient : IHelloWorld
But the problem is that IHelloWorld does not include the Async versions of the method. So, I create an async interface:
public interface IHelloWorldAsync : IHelloWorld
{
void HelloWorldAsync(...);
event System.EventHandler<HelloWorldEventRgs> HelloWorldCompleted;
}
Then, you can tell the service proxy to implement the interface via partial:
public partial class HelloWorldClient : IHelloWorldAsync {}
Because the HelloWorldClient does, indeed, implement those async methods, this works.
Then, I can just use IHelloWorldAsync everywhere and tell the UnityContainer to use HelloWorldClient for IHelloWorldAsync interfaces.
Ok, I have been messing with this all day and the solution is really much more simple than that. I originally wanted to call the methods on the interface instead of the concreate class. The interface generated by proxy class generator only includes the BeginXXX and EndXXX methods and I was getting an exception when I called EndXXX.
Well, I just finished reading up on System.Threading.Dispatcher and I finally understand how to use it. Dispatcher is a member of any class that inherits from DispatcherObject, which the UI elements do. The Dispatcher operates on the UI thread, which for most WPF applications there is only 1 UI thread. There are exceptions, but I believe you have to do this explicitly so you'll know if you're doing it. Otherwise, you've only got a single UI thread. So it is safe to store a reference to a Dispatcher for use in non-UI classes.
In my case I'm using Prism and my Presenter needs to update the UI (not directly, but it is firing IPropertyChanged.PropertyChanged events). So what I have done is in my Bootstrapper when I set the shell to Application.Current.RootVisual I also store a reference to the Dispatcher like this:
public class Bootstrapper : UnityBootstrapper
{
protected override IModuleCatalog GetModuleCatalog()
{
// setup module catalog
}
protected override DependencyObject CreateShell()
{
// calling Resolve instead of directly initing allows use of dependency injection
Shell shell = Container.Resolve<Shell>();
Application.Current.RootVisual = shell;
Container.RegisterInstance<Dispatcher>(shell.Dispatcher);
return shell;
}
}
Then my presenter has a ctor which accepts IUnityContainer as an argument (using DI) then I can do the following:
_service.BeginGetMessage(new AsyncCallback(GetMessageAsyncComplete), null);
private void GetMessageAsyncComplete(IAsyncResult result)
{
string output = _service.EndGetMessage(result);
Dispatcher dispatcher = _container.Resolve<Dispatcher>();
dispatcher.BeginInvoke(() => this.Message = output);
}
This is sooooo much simpler. I just didn't understand it before.
Ok, so my real problem was how to decouple my dependency upon the proxy class created by my service reference. I was trying to do that by using the interface generated along with the proxy class. Which could have worked fine, but then I would have also had to reference the project which owned the service reference and so it wouldn't be truly decoupled. So here's what I ended up doing. It's a bit of a hack, but it seems to be working, so far.
First here's my interface definition and an adapter class for the custom event handler args generated with my proxy:
using System.ComponentModel;
namespace HelloWorld.Interfaces.Services
{
public class GetMessageCompletedEventArgsAdapter : System.ComponentModel.AsyncCompletedEventArgs
{
private object[] results;
public GetMessageCompletedEventArgsAdapter(object[] results, System.Exception exception, bool cancelled, object userState) :
base(exception, cancelled, userState)
{
this.results = results;
}
public string Result
{
get
{
base.RaiseExceptionIfNecessary();
return ((string)(this.results[0]));
}
}
}
/// <summary>
/// Create a partial class file for the service reference (reference.cs) that assigns
/// this interface to the class - then you can use this reference instead of the
/// one that isn't working
/// </summary>
public interface IMessageServiceClient
{
event System.EventHandler<GetMessageCompletedEventArgsAdapter> GetMessageCompleted;
event System.EventHandler<AsyncCompletedEventArgs> UpdateMessageCompleted;
void GetMessageAsync();
void GetMessageAsync(object userState);
void UpdateMessageAsync(string message);
void UpdateMessageAsync(string message, object userState);
}
}
Then I just needed to create a partial class which extends the proxy class generated by the service reference:
using System;
using HelloWorld.Interfaces.Services;
using System.Collections.Generic;
namespace HelloWorld.Core.Web.Services
{
public partial class HelloWorldMessageServiceClient : IMessageServiceClient
{
#region IMessageServiceClient Members
private event EventHandler<GetMessageCompletedEventArgsAdapter> handler;
private Dictionary<EventHandler<GetMessageCompletedEventArgsAdapter>, EventHandler<GetMessageCompletedEventArgs>> handlerDictionary
= new Dictionary<EventHandler<GetMessageCompletedEventArgsAdapter>, EventHandler<GetMessageCompletedEventArgs>>();
/// <remarks>
/// This is an adapter event which allows us to apply the IMessageServiceClient
/// interface to our MessageServiceClient. This way we can decouple our modules
/// from the implementation
/// </remarks>
event EventHandler<GetMessageCompletedEventArgsAdapter> IMessageServiceClient.GetMessageCompleted
{
add
{
handler += value;
EventHandler<GetMessageCompletedEventArgs> linkedhandler = new EventHandler<GetMessageCompletedEventArgs>(HelloWorldMessageServiceClient_GetMessageCompleted);
this.GetMessageCompleted += linkedhandler;
handlerDictionary.Add(value, linkedhandler);
}
remove
{
handler -= value;
EventHandler<GetMessageCompletedEventArgs> linkedhandler = handlerDictionary[value];
this.GetMessageCompleted -= linkedhandler;
handlerDictionary.Remove(value);
}
}
void HelloWorldMessageServiceClient_GetMessageCompleted(object sender, GetMessageCompletedEventArgs e)
{
if (this.handler == null)
return;
this.handler(sender, new GetMessageCompletedEventArgsAdapter(new object[] { e.Result }, e.Error, e.Cancelled, e.UserState));
}
#endregion
}
}
This is an explicit implementation of the event handler so I can chain together the events. When user registers for my adapter event, I register for the actual event fired. When the event fires I fire my adapter event. So far this "Works On My Machine".
Passing around the interface (once you have instantiated the client) should be as simply as using HelloWorldMessageService instead of the HelloWorldMessageServiceClient class.
In order to update the UI you need to use the Dispatcher object. This lets you provide a delegate that is invoked in the context of the UI thread. See this blog post for some details.
You can make this much simpler still.
The reason the proxy works and your copy of the contract does not is because WCF generates the proxy with code that "Posts" the callback back on the calling thread rather than making the callback on the thread that is executing when the service call returns.
A much simplified, untested, partial implementation to give you the idea of how WCF proxies work looks something like:
{
var state = new
{
CallingThread = SynchronizationContext.Current,
Callback = yourCallback
EndYourMethod = // assign delegate
};
yourService.BeginYourMethod(yourParams, WcfCallback, state);
}
private void WcfCallback(IAsyncResult asyncResult)
{
// Read the result object data to get state
// Call EndYourMethod and block until the finished
state.Context.Post(state.YourCallback, endYourMethodResultValue);
}
The key is the storing of the syncronizationContext and calling the Post method. This will get the callback to occur on the same thread as Begin was called on. It will always work without involving the Dispatcher object provided you call Begin from your UI thread. If you don't then you are back to square one with using the Dispatcher, but the same problem will occur with a WCF proxy.
This link does a good job of explaining how to do this manually:
http://msdn.microsoft.com/en-us/library/dd744834(VS.95).aspx
Just revisiting old posts left unanswered where I finally found an answer. Here's a post I recently wrote that goes into detail about how I finally handled all this:
http://www.developmentalmadness.com/archive/2009/11/04/mvvm-with-prism-101-ndash-part-6-commands.aspx