Implementing IDisposable for WCF service client - Am I doing this right? - vb.net

I want to safely dispose my WCF client, but I'm not sure if I am implementing IDisposable in the right spot.
I added code to implement IDisposable in the service client inside the Reference.vb file that was created when I added the WCF service as a service reference:
Partial Public Class Service1Client
Inherits System.ServiceModel.ClientBase(Of DataConversionService.IService1)
Implements DataConversionService.IService1, IDisposable
Public Sub New()
MyBase.New
End Sub
'skipping constructors with multiple parameters...
Public Sub Dispose() Implements IDisposable.Dispose
Try
If State <> CommunicationState.Faulted Then
Close()
End If
Finally
If State <> CommunicationState.Closed Then
Abort()
End If
End Try
End Sub
Did I add this in the right spot? When debugging, I wasn't able to hit my breakpoint in the Dispose sub.
Any help is appreciated!

You were close. Firstly, you shouldn't change that Reference.vb file since it will be overwritten when the service definition gets updated and changing that file is not a good practice.
What you can do instead is using Proxy Pattern. The Proxy will be used to call the methods in services and manage the connection state etc. I will write in C# since I don't know VB but you'll get the idea. I will simplify this as much as I can.
The interface of Proxy class might look like this:
public interface IProxy
{
/// <summary>
/// Execute call to service method
/// </summary>
/// <typeparam name="TBusiness">Service interface</typeparam>
/// <typeparam name="TResult">Service method return type</typeparam>
/// <param name="call">Service method</param>
/// <returns>Returns what service method returns</returns>
TResult Execute<TBusiness, TResult>(Func<TBusiness, TResult> call) where TBusiness : class;
/// <summary>
/// Execute call to void service method
/// </summary>
/// <typeparam name="TBusiness">Service Interface</typeparam>
/// <param name="call">Service method</param>
void Execute<TBusiness>(Action<TBusiness> call) where TBusiness : class;
}
As you see, there are two methods in this interface. One of them will be used to call a service method which has a return type, the other one will be used for void methods in the service. You can put non-generic version of these methods to the interface too.
The implementation might be like this:
public class ServiceProxy : IProxy
{
protected void ExecuteCall<TContract>(Action<TContract> code) where TContract : class
{
var contractChannel = default(TContract);
try
{
//Create an instance of service client and call the method
contractChannel = Activator.CreateInstance<TContract>();
code(contractChannel);
((ICommunicationObject)contractChannel).Close();
}
catch (FaultException)
{
((ICommunicationObject)contractChannel).Abort();
}
catch (CommunicationException)
{
((ICommunicationObject)contractChannel).Abort();
}
catch (TimeoutException)
{
((ICommunicationObject)contractChannel).Abort();
}
}
public TResult Execute<TContract, TResult>(Func<TContract, TResult> call) where TContract : class
{
return ExecuteCall(call);
}
public void Execute<TContract>(Action<TContract> call) where TContract : class
{
ExecuteCall(call);
}
}
Then, you can use it like this:
var proxy = new ServiceProxy();
proxy.Execute<Service1Client>(a => a.MethodInTheService());
What's great about this approach and how you can make it perfect is:
You might not want to create the proxy as new ServiceProxy() but inject IProxy as ServiceProxy and use it as WCF client for now but if it changes to Web API in the future e.g., implement and inject WebApiProxy then.
You can use contract interfaces to call the proxy methods.
You can do whatever you want in the proxy class like caching the channels, getting the service endpoints from the database etc.

You don't need to dispose the client. In fact, if you dig deep into the code of ClientBase you'll see how it already implements IDisposable and when it gets disposed it just calls Close() - which has error handling paths to abort if something goes wrong.
Having said this, I would use a pattern similar to the below to close your client channel (you may need to cast to IChannel on Close and Abort):
try
{
client.Close();
}
catch
{
client.Abort();
}

Related

Autofac.Multitenant in an aspnet core application does not seem to resolve tenant scoped dependencies correctly

I'm in the process of upgrading a Multitenant dotnet core solution which utilises the Autofac.Multitenant framework. I'm not having a lot of luck getting tenancy resolution working correctly. I've created a simple demonstration of the problem here: https://github.com/SaltyDH/AutofacMultitenancy1
This repo demonstrates registering a InstancePerTenant scoped dependency TestMultitenancyContext which is resolved in the Home Controller. Due to issues with using IHttpContextAccessor, I'm using a custom RequestMiddleware class to capture the current HttpContext object so that I can perform logic on the current HttpContext request object in the MultitenantIdentificationStrategy.
Finally, TestFixture provides a simple xUnit test which, at least on my machine returns "tenant1" for both tenants.
Is there something I've missed here or is this just not currently working?
UPDATE 10/6/2017: We released Autofac.AspNetCore.Multitenant to wrap up the solution to this in a more easy to consume package. I'll leave the original answer/explanation here for posterity, but if you're hitting this you can go grab that package and move on.
I think you're running into a timing issue.
If you pop open the debugger on the HttpContext in the middleware you can see that there's a RequestServicesFeature object on a property called ServiceProvidersFeature. That's what's responsible for creating the per-request scope. The scope gets created the first time it's accessed.
It appears that the order goes roughly like this:
The WebHostBuilder adds a startup filter to enable request services to be added to the pipeline.
The startup filter, AutoRequestServicesStartupFilter, adds middleware to the very beginning of the pipeline to trigger the creation of request services.
The middleware that gets added, RequestServicesContainerMiddleware, basically just invokes the RequestServices property from the ServiceProvidersFeature to trigger creation of the per-request lifetime scope. However, in its constructor is where it gets the IServiceScopeFactory that it uses to create the request scope, which isn't so great because it'll be created from the root container before a tenant can be established.
All that yields a situation where the per-request scope has already been determined to be for the default tenant and you can't really change it.
To work around this, you need to set up request services yourself such that they account for multitenancy.
It sounds worse than it is.
First, we need a reference to the application container. We need the ability to resolve something from application-level services rather than request services. I did that by adding a static property to your Startup class and keeping the container there.
public static IContainer ApplicationContainer { get; private set; }
Next, we're going to change your middleware to look more like the RequestServicesContainerMiddleware. You need to set the HttpContext first so your tenant ID strategy works. After that, you can get an IServiceScopeFactory and follow the same pattern they do in RequestServicesContainerMiddleware.
public class RequestMiddleware
{
private static readonly AsyncLocal<HttpContext> _context = new AsyncLocal<HttpContext>();
private readonly RequestDelegate _next;
public RequestMiddleware(RequestDelegate next)
{
this._next = next;
}
public static HttpContext Context => _context.Value;
public async Task Invoke(HttpContext context)
{
_context.Value = context;
var existingFeature = context.Features.Get<IServiceProvidersFeature>();
using (var feature = new RequestServicesFeature(Startup.ApplicationContainer.Resolve<IServiceScopeFactory>()))
{
try
{
context.Features.Set<IServiceProvidersFeature>(feature);
await this._next.Invoke(context);
}
finally
{
context.Features.Set(existingFeature);
_context.Value = null;
}
}
}
}
Now you need a startup filter to get your middleware in there. You need a startup filter because otherwise the RequestServicesContainerMiddleware will run too early in the pipeline and things will already start resolving from the wrong tenant scope.
public class RequestStartupFilter : IStartupFilter
{
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return builder =>
{
builder.UseMiddleware<RequestMiddleware>();
next(builder);
};
}
}
Add the startup filter to the very start of the services collection. You need your startup filter to run before AutoRequestServicesStartupFilter.
The ConfigureServices ends up looking like this:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Insert(0, new ServiceDescriptor(typeof(IStartupFilter), typeof(RequestStartupFilter), ServiceLifetime.Transient));
services.AddMvc();
var builder = new ContainerBuilder();
builder.RegisterType<TestMultitenancyContext>().InstancePerTenant();
builder.Populate(services);
var container = new MultitenantContainer(new MultitenantIdentificationStrategy(), builder.Build());
ApplicationContainer = container;
return new AutofacServiceProvider(container);
}
Note the Insert call in there to jam your service registration at the top, before their startup filter.
The new order of operations will be:
At app startup...
Your startup filter will add your custom request services middleware to the pipeline.
The AutoRequestServicesStartupFilter will add the RequestServicesContainerMiddleware to the pipeline.
During a request...
Your custom request middleware will set up request services based on the inbound request information.
The RequestServicesContainerMiddleware will see that request services are already set up and will do nothing.
When services are resolved, the request service scope will already be the tenant scope as set up by your custom request middleware and the correct thing will show up.
I tested this locally by switching the tenant ID to come from querystring rather than host name (so I didn't have to set up hosts file entries and all that jazz) and I was able to switch tenant by switching querystring parameters.
Now, you may be able to simplify this a bit. For example, you may be able to get away without a startup filter by doing something directly to the web host builder in the Program class. You may be able to register your startup filter right with the ContainerBuilder before calling builder.Populate and skip that Insert call. You may be able to store the IServiceProvider in the Startup class property if you don't like having Autofac spread through the system. You may be able to get away without a static container property if you create the middleware instance and pass the container in as a constructor parameter yourself. Unfortunately, I already spent a loooot of time trying to figure out the workaround so I'm going to have to leave "optimize it" as an exercise for the reader.
Again, sorry this wasn't clear. I've filed an issue on your behalf to get the docs updated and maybe figure out a better way to do this that's a little more straightforward.
I have an alternate solution, related to work I've done on a pending PR on the Autofac DI extension. The solution there can't be used exactly, because it depends on classes that are (rightly) internal. It can be adapted by providing shims that reproduce the functionality in those classes. Since they are compact, this doesn't require the addition of a lot of code. Until the functionality is fixed, this is the solution I'm using.
The other aspect of the solution is to eschew the custom middleware and instead make the ITenantIdentificationStrategy a service that can take any dependency required to do what it needs to.
Fixing the DI
The "DI" side of the problem is that the Autofac DI extension uses resolution to supply IServiceProvider and IServiceScopeFactory implementations. This is possible, because under the hood these are IComponentContext and ILifetimeScope (which are themselves different interfaces for the same thing). In most cases this works fine, but ASP.NET Core proceeds by resolving a singleton IServiceScopeFactory very early in the application cycle. In a multi-tenant scenario this resolution will return the ILifetimeScope for either the first tenant requested, or for the "default" tenant, and that will be the root scope (as far as MS DI is concerned) for the application lifetime. (See the PR for further discussion.)
The classes below implement an alternate behavior: instead of resolving the DI interfaces, it builds (news-up) the initially-requested ones from the IContainer directly. With the initial IServiceScopeFactory based directly on IContainer, further scope requests will resolve correctly.
public class ContainerServiceProvider : IServiceProvider, ISupportRequiredService
{
private readonly IContainer container;
public ContainerServiceProvider(IContainer container)
{
this.container = container;
}
public object GetRequiredService(Type serviceType)
{
if (TryGetContainer(serviceType, out object containerSvc)) return containerSvc;
else return container.Resolve(serviceType);
}
public object GetService(Type serviceType)
{
if (TryGetContainer(serviceType, out object containerSvc)) return containerSvc;
else return container.ResolveOptional(serviceType);
}
bool TryGetContainer(Type serviceType, out object containerSvc)
{
if (serviceType == typeof(IServiceProvider)) { containerSvc = this; return true; }
if (serviceType == typeof(IServiceScopeFactory)) { containerSvc = new ContainerServiceScopeFactory(container); return true; }
else { containerSvc = null; return false; }
}
}
// uses IContainer, but could use copy of AutofacServiceScopeFactory
internal class ContainerServiceScopeFactory : IServiceScopeFactory
{
private IContainer container;
public ContainerServiceScopeFactory(IContainer container)
{
this.container = container;
}
public IServiceScope CreateScope()
{
return new BecauseAutofacsIsInternalServiceScope(container.BeginLifetimeScope());
}
}
// direct copy of AutofacServiceScope
internal class BecauseAutofacsIsInternalServiceScope : IServiceScope
{
private readonly ILifetimeScope _lifetimeScope;
/// <summary>
/// Initializes a new instance of the <see cref="AutofacServiceScope"/> class.
/// </summary>
/// <param name="lifetimeScope">
/// The lifetime scope from which services should be resolved for this service scope.
/// </param>
public BecauseAutofacsIsInternalServiceScope(ILifetimeScope lifetimeScope)
{
this._lifetimeScope = lifetimeScope;
this.ServiceProvider = this._lifetimeScope.Resolve<IServiceProvider>();
}
/// <summary>
/// Gets an <see cref="IServiceProvider" /> corresponding to this service scope.
/// </summary>
/// <value>
/// An <see cref="IServiceProvider" /> that can be used to resolve dependencies from the scope.
/// </value>
public IServiceProvider ServiceProvider { get; }
/// <summary>
/// Disposes of the lifetime scope and resolved disposable services.
/// </summary>
public void Dispose()
{
this._lifetimeScope.Dispose();
}
}
Fixing Identification Strategy
As for making the identification-strategy a service, I would rework your implementation like so:
public class MultitenantIdentificationStrategy : ITenantIdentificationStrategy
{
public const string DefaultTenantId = null;
private readonly IHttpContextAccessor contextaccessor;
public MultitenantTenantIdentificationStrategy(IHttpContextAccessor contextaccessor)
{
this.contextaccessor = contextaccessor;
}
public bool TryIdentifyTenant(out object tenantId)
{
var context = contextaccessor.HttpContext;
// after this is unchanged
.
.
}
.
.
}
Use in Startup.ConfigureServices
This shows the fragment of how these last few pieces are registered and fed to MS DI for ASP.NET.
. . .
builder.RegisterType<MultitenantIdentificationStrategy>().AsImplementedInterfaces(); // tenant identification
// register do Autofac DI integration
builder.Populate(services);
var underlyingcontainer = builder.Build();
ApplicationContainer = new MultitenantContainer(underlyingcontainer.Resolve<ITenantIdentificationStrategy>(), underlyingContainer);
return new ContainerServiceProvider(ApplicationContainer);
If you find this solution workable, please give a thumbs up to DI PR 10--or PR 11, if after reviewing you think that is the better/more elegant solution. Either will save having to add the "shim" code above.

Create a custom Http method

Is it possible to create our own HTTP method by just overriding the HttpMethodAttribute class and specify our own supportedMethods ?
In fact, depending on the case, we need to return the View as complete view with the _Layout, and sometimes we just need to return the PartialView of this view. So my idea is to put an custom attribute, like [HttpPartial] and so the client will tell, depending on the methods used in the request, if it wants the complete view (GET method) or the partial view (PARTIAL method).
Yes, that's possible for APIs. You can look at how the HttpGetAttribute is implemented, and roll your own for a custom method, replacing "get" with "foo":
/// <summary>
/// Identifies an action that supports the HTTP FOO method.
/// </summary>
public class HttpFooAttribute : HttpMethodAttribute
{
private static readonly IEnumerable<string> _supportedMethods = new[] { "FOO" };
/// <summary>
/// Creates a new <see cref="HttpFooAttribute"/>.
/// </summary>
public HttpFooAttribute()
: base(_supportedMethods)
{
}
/// <summary>
/// Creates a new <see cref="HttpFooAttribute"/> with the given route template.
/// </summary>
/// <param name="template">The route template. May not be null.</param>
public HttpFooAttribute(string template)
: base(_supportedMethods, template)
{
if (template == null)
{
throw new ArgumentNullException(nameof(template));
}
}
}
Then apply it to your API action methods:
[Route("Bar")]
public class BarApiController : Controller
{
[HttpFoo("/"]
public IActionResult Foo()
{
return Ok("Foo");
}
}
Now you can request FOO https://your-api:44312/bar/.
This is less useful for actions returning views, as any HTML-rendering user agent only lets the user initiate GET or POST requests through hyperlinks and forms.
You could send more methods through an XMLHttpRequest or fetch(), but it'll require more documentation and client customization.
Don't break or hamper the web, don't invent new HTTP methods for your application logic. Simply use a query string parameter or send it in your body: &renderAsPartial=true, { "renderAsPartial": true }.
See the IANA's Hypertext Transfer Protocol (HTTP) Method Registry for existing methods and see RCF 7231 section 8.1 for how to register new HTTP methods.

How to inject dependencis into WCF Attribute with Simple Injector

I have a bunch of WCF services that works with REST and SOAP. I have created an WCF attribute who checks if the current httpcontext exists, if exists it use cookie authentication, other way it use custom WCF authentication.
My attribute looks like this:
Public Class AuthRequired
Inherits Attribute
Implements IOperationBehavior, IParameterInspector
Public Sub AddBindingParameters(operationDescription As OperationDescription, bindingParameters As Channels.BindingParameterCollection) Implements IOperationBehavior.AddBindingParameters
End Sub
Public Sub ApplyClientBehavior(operationDescription As OperationDescription, clientOperation As ClientOperation) Implements IOperationBehavior.ApplyClientBehavior
End Sub
Public Sub ApplyDispatchBehavior(operationDescription As OperationDescription, dispatchOperation As DispatchOperation) Implements IOperationBehavior.ApplyDispatchBehavior
dispatchOperation.ParameterInspectors.Add(Me)
End Sub
Public Sub Validate(operationDescription As OperationDescription) Implements IOperationBehavior.Validate
End Sub
Public Sub AfterCall(operationName As String, outputs() As Object, returnValue As Object, correlationState As Object) Implements IParameterInspector.AfterCall
End Sub
Public Function BeforeCall(operationName As String, inputs() As Object) As Object Implements IParameterInspector.BeforeCall
' IDS is the custom authentication service.
If IDS.Usuario Is Nothing Then
If HttpContext.Current Is Nothing Then
Throw New SecurityException("Las credenciales no son válidas para esta operación o no fueron provistas.")
Else
Throw New WebFaultException(Of String)("ACCESO DENEGADO. REVISE SUS CREDENCIALES.", Net.HttpStatusCode.Forbidden)
End If
End If
End Function
End Class
So, my question is how can I inject dependencies into this attribute using Simple Injector? I google for a while but the only thing I found was for Ninject, or inject filters on WebAPI.
Cheers!
You can't do constructor injection into attributes, because it is the CLR who is in control over the creation of attributes; not the DI library. Although you could initialize/build-up attributes after they have been created and inject dependencies using property injection, this is very risky for the following reasons:
Many frameworks cache attributes, which make them effectively singletons. This will cause Captive Dependencies in cases the dependencies themselves aren't singletons themselves.
It will be hard to impossible to let the container verify object graphs that start from the attributes, which might cause a false sense of security when verifying and diagnosing the container's configuration.
Instead, a much better approach is to either make attributes either passive or humble objects.
With a humble object, you extract all logic out of the attribute into its own service. The only code that will be left in the attribute is a call to your container or Service Locator to resolve that service and you call the method. This might look like this (excuse my C#):
public class AuthRequiredAttribute : Attribute, IOperationBehavior
{
public object BeforeCall(string operationName, object[] inputs) {
var checker = Global.Container.GetInstance<IAuthorizationChecker>();
checker.Check();
}
}
// Attribute's logic abstracted to a new service. This service can be
// registered, verified, diagnosed, and tested.
public class AuthorizationChecker : IAuthorizationChecker
{
private readonly IDS authenticationService;
public AuthorizationChecker(IDS authenticationService) {
this.authenticationService = authenticationService;
}
public void Check() {
if (this.authenticationService.Usuario == null) {
if (HttpContext.Current == null) {
throw new SecurityException();
} else {
throw new WebFaultException<string>();
}
}
}
}
This requires you to expose the container in a way that your attributes can resolve the services they need. Advantage of this is that it is easy implemented, quite clean. Downside is that that you have to fall back to the Service Locator anti-pattern to get this working, and you have to make sure that your service is registered, because the container won't warn about this and this will, therefore, fail at runtime instead of during application startup of inside an integration test that calls container.Verify().
The second option is using passive attributes. This is especially useful when you have multiple of these attributes. This article describes the basic idea behind passive attributes and gives an example how to implement this in Web API. WCF has different interception points, so applying this to WCF requires a different implementation, but the concept stays the same.

WCF service with multiple implementations of dependency

I have a WCF service that will be called from a various clients.
Internally the WCF service uses an ISomething. There are multiple implementations of this interface and I need some clients to use one implementation and other clients to use a different implementation.
In addition, I am using Unity and an IoC container. I would typically set up a custom factory to allow the wcf service itself to be resolved along with its dependency graph, but if I have multiple implementations of a dependency, I do not think I can go with this approach and would have to resort to resolving the ISomething within the service (effectively using Unity as a service locator) which is not ideal.
So I need to work out
(1) how to specify which implementation of ISomething a client needs (eg. use a header, pass implementation string in each method, host multiple endpoints etc.)
(2) how Unity fits in?
One option is to write a Decorator that performs the selection for you:
public class RoutingSomething : ISomething
{
private readonly ISomeContext ctx;
private readonly ISomething s1;
private readonly ISomething s2;
private readonly ISomething s3;
public RoutingSomething(ISomeContext ctx)
{
this.ctx = ctx;
// An even better design would be to inject these too
this.s1 = new BarSomething();
this.s2 = new BazSomething();
this.s3 = new QuxSomething();
}
// Assuming ISomething has a Foo method:
public void Foo()
{
if(this.ctx.Bar())
{
this.s1.Foo();
return;
}
if(this.ctx.Baz())
{
this.s2.Foo();
return;
}
if(this.ctx.Qux())
{
this.s3.Foo();
return;
}
}
}
You could generalize this so that ISomeContext is simply an Abstract Factory of ISomething. This then begins to turn into the general solution to varying dependencies based on run-time context.
You can now register RoutingSomething in Unity in addition to your other components. When the container resolves the service, it'll inject an instance of RoutingSomething into it.

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