How can I implement unit of work pattern in a WCF service with Autofac?
Injecting the same instance per call (or in Autofac terms LifetimeScope) of the unit of work interface into my services and repositories is easy using Autofac's wcf integration - what I am after is a way to commit the unit of work changes on return of WCF service call obviously ONLY if there has not been any exceptions.
I have seen Using a Custom Endpoint Behavior with WCF and Autofac which is basically how I started out but that does not deal with exceptions.
Currently what I have is an IOperationInvoker that starts the unit of work in the Invoke and commits it only if there has not been any exceptions. The problem with this approach is that I need to resolve my unit of work instance inside the Invoke method which gives me a different instance than the one injected into my services and repositories using AutofacInstanceProvider.
Bradley Boveinis found a solution to this problem. We have not thoroughly tested it but it seems to work:
public class UnitOfWorkAwareOperationInvoker : IOperationInvoker
{
private readonly IOperationInvoker _baseInvoker;
public UnitOfWorkAwareOperationInvoker(IOperationInvoker baseInvoker)
{
_baseInvoker = baseInvoker;
}
public object[] AllocateInputs()
{
return _baseInvoker.AllocateInputs();
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
var result = _baseInvoker.Invoke(instance, inputs, out outputs);
var context = OperationContext.Current.InstanceContext.Extensions.Find<AutofacInstanceContext>();
try
{
context.Resolve<IUnitOfWork>().Save();
}
catch (Exception ex)
{
var message = Message.CreateMessage(MessageVersion.Default, string.Empty);
new ElmahErrorHandler().ProvideFault(ex, null, ref message);
throw;
}
return result;
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
return _baseInvoker.InvokeBegin(instance, inputs, callback, state);
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
return _baseInvoker.InvokeEnd(instance, out outputs, result);
}
public bool IsSynchronous
{
get { return _baseInvoker.IsSynchronous; }
}
}
The key is in the following line:
OperationContext.Current.InstanceContext.Extensions.Find<AutofacInstanceContext>();
This grabs the UoW out of the ambient/current/contextual LifetimeScope.
Related
I have WebGet, and WebInvoke attributes describing my contract, but what is the best method of handling invalid URI's? Right now, if a user passes an URI that does not match my current operations, they get an "Endpoint not found." message. I want to pass back a more descriptive message.
For example, my URI template looks like:
/Stuff/{ID}/subStuff
but say they type
/Stuff/{ID}/OtherStuff
There is no such thing as OtherStuff, and I do not have a template for that.
Is there a way to cover all non mapped URI's with a single contract?
Thanks!
If you want to catch all the unhandled requests at a global level in WCF REST then you have to create a custom WebHttpBehavior and custom IOperationInvoker as described in this post.
If you want to return a custom error text with custom status code(404) you can also look into the WebOperationContext.OutgoingResponse property as described here.
While I did follow the links mark provided, and they did give a hint of what I needed. The answers that were linked did not actually answer my original question.
I was able to follow the steps, and I wanted to list my steps to solve this problem on this question as well.
To create my own response to any URI that was not mapped to a method in my contract I created the following:
A custom ServiceHostFactory
Behavior that I mapped to my end points within the custom ServiceHostFactory
a dispatcher that would handle all unmapped uri's that were provided to the service.
Below are the full definitions of the object's I created:
using System.ServiceModel;
using System.ServiceModel.Activation;
namespace your.namespace.here
{
public class CustomServiceHostFactory : WebServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
ServiceHost host = base.CreateServiceHost(serviceType, baseAddresses);
//note: these endpoints will not exist yet, if you are relying on the svc system to generate your endpoints for you
// calling host.AddDefaultEndpoints provides you the endpoints you need to add the behavior we need.
var endpoints = host.AddDefaultEndpoints();
foreach (var endpoint in endpoints)
{
endpoint.Behaviors.Add(new WcfUnkownUriBehavior());
}
return host;
}
}
}
As you can see above, we are adding a new behavior: WcfUnknownUriBehavior. This new custom behavior's soul duty is to replace the UnknownDispatcher. below is that implementation:
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.ServiceModel.Web;
namespace your.namespace.here
{
public class UnknownUriDispatcher : IOperationInvoker
{
public object[] AllocateInputs()
{
//no inputs are really going to come in,
//but we want to provide an array anyways
return new object[1];
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
var responeObject = new YourResponseObject()
{
Message = "Invalid Uri",
Code = "Error",
};
Message result = Message.CreateMessage(MessageVersion.None, null, responeObject);
WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
outputs = new object[1]{responeObject};
return result;
}
public System.IAsyncResult InvokeBegin(object instance, object[] inputs, System.AsyncCallback callback, object state)
{
throw new System.NotImplementedException();
}
public object InvokeEnd(object instance, out object[] outputs, System.IAsyncResult result)
{
throw new System.NotImplementedException();
}
public bool IsSynchronous
{
get { return true; }
}
}
}
Once you have these objects specified, you can now use the new factory within your svc's "markup":
<%# ServiceHost Language="C#" Debug="true" Service="your.service.namespace.here" CodeBehind="myservice.svc.cs"
Factory="your.namespace.here.CustomServiceHostFactory" %>
And that should be it. as long as your object "YourResponseObject" can be serialized, it's serialized representation will be sent back to the client.
Instantiating an unregistered service with known services (injecting them via ctr).
I want to avoid container pollution.
Here is another way to resolve unregistered concrete types from container. Note that all autofac constructor finding and selecting logic, all registration event handlers remain in force.
First, you define this method:
public static object ResolveUnregistered(this IComponentContext context, Type serviceType, IEnumerable<Parameter> parameters)
{
var scope = context.Resolve<ILifetimeScope>();
using (var innerScope = scope.BeginLifetimeScope(b => b.RegisterType(serviceType)))
{
IComponentRegistration reg;
innerScope.ComponentRegistry.TryGetRegistration(new TypedService(serviceType), out reg);
return context.ResolveComponent(reg, parameters);
}
}
The idea is that you get component registration from derived context and resolve it in the current context.
Then you can create some handy overloads:
public static object ResolveUnregistered(this IComponentContext context, Type serviceType)
{
return ResolveUnregistered(context, serviceType, Enumerable.Empty<Parameter>());
}
public static object ResolveUnregistered(this IComponentContext context, Type serviceType, params Parameter[] parameters)
{
return ResolveUnregistered(context, serviceType, (IEnumerable<Parameter>)parameters);
}
public static TService ResolveUnregistered<TService>(this IComponentContext context)
{
return (TService)ResolveUnregistered(context, typeof(TService), Enumerable.Empty<Parameter>());
}
public static TService ResolveUnregistered<TService>(this IComponentContext context, params Parameter[] parameters)
{
return (TService)ResolveUnregistered(context, typeof(TService), (IEnumerable<Parameter>)parameters);
}
I found a solution that required some custom code. Somethings are specific to my app, but I think you can get the picture.
Resolve(parameter.ParameterType) would be a call to your container.
public object ResolveUnregistered(Type type)
{
var constructors = type.GetConstructors();
foreach (var constructor in constructors)
{
try
{
var parameters = constructor.GetParameters();
var parameterInstances = new List<object>();
foreach (var parameter in parameters)
{
var service = Resolve(parameter.ParameterType);
if (service == null) throw new NopException("Unkown dependency");
parameterInstances.Add(service);
}
return Activator.CreateInstance(type, parameterInstances.ToArray());
}
catch (NopException)
{
}
}
throw new NopException("No contructor was found that had all the dependencies satisfied.");
}
Here is a way to resolve an unregistered type with know constructor (ctor) properties. This is based on a previous great post: https://stackoverflow.com/a/6994144/2641447.
In this solution, it is absolutely great that constructor finding and selecting logic is handled by Autofac.
The comment is referred to dispose issues what I have solved with the 'ExternallyOwned()' wich configure the component so that instances are never disposed by the container.
I think that an improvement of the solution may be the following:
public static object ResolveUnregistered(this IComponentContext context, Type serviceType, IEnumerable<Parameter> parameters)
{
var scope = context.Resolve<ILifetimeScope>();
using (var innerScope = scope.BeginLifetimeScope(b => b.RegisterType(serviceType).ExternallyOwned()))
return innerScope.Resolve(serviceType, parameters);
}
The usings:
using Autofac;
using Autofac.Core;
using System;
using System.Collections.Generic;
Has anyone been able to communicate using WCF on Windows Phone Series 7 emulator?
I've been trying for the past two days and it's just happening for me. I can get a normal Silverlight control to work in both Silverlight 3 and Silverlight 4, but not the phone version. Here are two versions that I've tried:
Version 1 - Using Async Pattern
BasicHttpBinding basicHttpBinding = new BasicHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress("http://localhost/wcf/Authentication.svc");
Wcf.IAuthentication auth1 = new ChannelFactory<Wcf.IAuthentication>(basicHttpBinding, endpointAddress).CreateChannel(endpointAddress);
AsyncCallback callback = (result) =>
{
Action<string> write = (str) =>
{
this.Dispatcher.BeginInvoke(delegate
{
//Display something
});
};
try
{
Wcf.IAuthentication auth = result.AsyncState as Wcf.IAuthentication;
Wcf.AuthenticationResponse response = auth.EndLogin(result);
write(response.Success.ToString());
}
catch (Exception ex)
{
write(ex.Message);
System.Diagnostics.Debug.WriteLine(ex.Message);
}
};
auth1.BeginLogin("user0", "test0", callback, auth1);
This version breaks on this line:
Wcf.IAuthentication auth1 = new ChannelFactory<Wcf.IAuthentication>(basicHttpBinding, endpointAddress).CreateChannel(endpointAddress);
Throwing System.NotSupportedException. The exception is not very descriptive and the callstack is equally not very helpful:
at System.ServiceModel.DiagnosticUtility.ExceptionUtility.BuildMessage(Exception x)
at System.ServiceModel.DiagnosticUtility.ExceptionUtility.LogException(Exception x)
at System.ServiceModel.DiagnosticUtility.ExceptionUtility.ThrowHelperError(Exception e)
at System.ServiceModel.ChannelFactory`1.CreateChannel(EndpointAddress address)
at WindowsPhoneApplication2.MainPage.DoLogin()
....
Version 2 - Blocking WCF call
Here is the version that doesn't use the async pattern.
[System.ServiceModel.ServiceContract]
public interface IAuthentication
{
[System.ServiceModel.OperationContract]
AuthenticationResponse Login(string user, string password);
}
public class WcfClientBase<TChannel> : System.ServiceModel.ClientBase<TChannel> where TChannel : class {
public WcfClientBase(string name, bool streaming)
: base(GetBinding(streaming), GetEndpoint(name)) {
ClientCredentials.UserName.UserName = WcfConfig.UserName;
ClientCredentials.UserName.Password = WcfConfig.Password;
}
public WcfClientBase(string name) : this(name, false) {}
private static System.ServiceModel.Channels.Binding GetBinding(bool streaming) {
System.ServiceModel.BasicHttpBinding binding = new System.ServiceModel.BasicHttpBinding();
binding.MaxReceivedMessageSize = 1073741824;
if(streaming) {
//binding.TransferMode = System.ServiceModel.TransferMode.Streamed;
}
/*if(XXXURLXXX.StartsWith("https")) {
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
}*/
return binding;
}
private static System.ServiceModel.EndpointAddress GetEndpoint(string name) {
return new System.ServiceModel.EndpointAddress(WcfConfig.Endpoint + name + ".svc");
}
protected override TChannel CreateChannel()
{
throw new System.NotImplementedException();
}
}
auth.Login("test0", "password0");
This version crashes in System.ServiceModel.ClientBase<TChannel> constructor. The call stack is a bit different:
at System.Reflection.MethodInfo.get_ReturnParameter()
at System.ServiceModel.Description.ServiceReflector.HasNoDisposableParameters(MethodInfo methodInfo)
at System.ServiceModel.Description.TypeLoader.CreateOperationDescription(ContractDescription contractDescription, MethodInfo methodInfo, MessageDirection direction, ContractReflectionInfo reflectionInfo, ContractDescription declaringContract)
at System.ServiceModel.Description.TypeLoader.CreateOperationDescriptions(ContractDescription contractDescription, ContractReflectionInfo reflectionInfo, Type contractToGetMethodsFrom, ContractDescription declaringContract, MessageDirection direction)
at System.ServiceModel.Description.TypeLoader.CreateContractDescription(ServiceContractAttribute contractAttr, Type contractType, Type serviceType, ContractReflectionInfo& reflectionInfo, Object serviceImplementation)
at System.ServiceModel.Description.TypeLoader.LoadContractDescriptionHelper(Type contractType, Type serviceType, Object serviceImplementation)
at System.ServiceModel.Description.TypeLoader.LoadContractDescription(Type contractType)
at System.ServiceModel.ChannelFactory1.CreateDescription()
at System.ServiceModel.ChannelFactory.InitializeEndpoint(Binding binding, EndpointAddress address)
at System.ServiceModel.ChannelFactory1..ctor(Binding binding, EndpointAddress remoteAddress)
at System.ServiceModel.ClientBase1..ctor(Binding binding, EndpointAddress remoteAddress)
at Wcf.WcfClientBase1..ctor(String name, Boolean streaming)
at Wcf.WcfClientBase`1..ctor(String name)
at Wcf.AuthenticationClient..ctor()
at WindowsPhoneApplication2.MainPage.DoLogin()
...
Any ideas?
As scottmarlowe pointed out, the automagicly generated service refrence just works. I have set upon the mission to work out just why the bloody hell it works and the manual version doesn't.
I found the culprit and it is ChannelFactory. For some reason new ChannelFactory<T>().CreateChannel() just throws an exception. The only solution I found is to provide your own implementation of the channel. This involves:
Override ClientBase. (optional).
Override ClientBase.CreateChannel. (optional).
Subclass ChannelBase with a specific implementation of your WCF interface
Now, ClientBase already provides an instance of the channel factory thru ChannelFactory property. If you simply call CreateChannel off that you would get the same exception. You need to instantiate a channel that you define in step 3 from within CreateChannel.
This is the basic wireframe of how it all looks put together.
[DataContractAttribute]
public partial class AuthenticationResponse {
[DataMemberAttribute]
public bool Success {
get; set;
}
[System.ServiceModel.ServiceContract]
public interface IAuthentication
{
[System.ServiceModel.OperationContract(AsyncPattern = true)]
IAsyncResult BeginLogin(string user, string password, AsyncCallback callback, object state);
AuthenticationResponse EndLogin(IAsyncResult result);
}
public class AuthenticationClient : ClientBase<IAuthentication>, IAuthentication {
public AuthenticationClient(System.ServiceModel.Channels.Binding b, EndpointAddress ea):base(b,ea)
{
}
public IAsyncResult BeginLogin(string user, string password, AsyncCallback callback, object asyncState)
{
return base.Channel.BeginLogin(user, password, callback, asyncState);
}
public AuthenticationResponse EndLogin(IAsyncResult result)
{
return Channel.EndLogin(result: result);
}
protected override IAuthentication CreateChannel()
{
return new AuthenticationChannel(this);
}
private class AuthenticationChannel : ChannelBase<IAuthentication>, IAuthentication
{
public AuthenticationChannel(System.ServiceModel.ClientBase<IAuthentication> client)
: base(client)
{
}
public System.IAsyncResult BeginLogin(string user, string password, System.AsyncCallback callback, object asyncState)
{
object[] _args = new object[2];
_args[0] = user;
_args[1] = password;
System.IAsyncResult _result = base.BeginInvoke("Login", _args, callback, asyncState);
return _result;
}
public AuthenticationResponse EndLogin(System.IAsyncResult result)
{
object[] _args = new object[0];
AuthenticationResponse _result = ((AuthenticationResponse)(base.EndInvoke("Login", _args, result)));
return _result;
}
}
}
TLDR; If you want to use your own WCF code on WP7 you need to create your own channel class and not rely on ChannelFactory.
Dynamic proxy creation using ChannelFactory.CreateChannel() is not supported on Windows Phone. This is documented here - http://msdn.microsoft.com/en-us/library/ff426930(VS.96).aspx
Consuming a service using the 'Add service reference' mechanism in a async pattern would be the correct way to do.
I put a blog post together on this very subject: http://blogs.msdn.com/b/andypennell/archive/2010/09/20/using-wcf-on-windows-phone-7-walk-through.aspx
I haven't had any problems, but I went the "add service reference..." route which I had to do via "VS2010 Express for Windows Phone" b/c VS2010 RC doesn't yet support that feature for WP7 development. The Express version comes with the WP7 Developer's install.
I'm looking for a way to log both requests and responses in a WCF REST service. The WCF REST starter kit comes with a RequestInterceptor class which can be used to intercept requests, but there does not seem to be an equivalent for responses. Ideally, I'd like to be able to intercept a response just before it's sent over the wire, e.g. when the underlying service method returns. Any suggestions?
Notice that if you want to intercept the raw message, and not the parameters, you can inject your implementation of IDispatchMessageInspector instead of the IParameterInspector extension point that Dani suggests.
There is a technic in WCF:
you create InstrumentedOperationAttribute that derives from Attribute, IOperationBehavior.
Inside you implement:
public void ApplyDispatchBehavior(
OperationDescription operationDescription,
DispatchOperation dispatchOperation
)
{
dispatchOperation.ParameterInspectors.Add(
new ServerPI()
);
}
and the ServerPI() class is what does the magic:
you do everything you need in beforecall and aftercall methods:
class ServerPI : IParameterInspector
{
public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
{
Guid result = (Guid)correlationState;
// ...
}
public object BeforeCall(string operationName, object[] inputs)
{
string parameter1 = inputs[0] as string;
return Guid.NewGuid();
}
}
When using svcutil.exe, I noticed this switch, /tcv:Version35. The docs says this:
Version35: Use /tcv:Version35 if you
are generating code for clients that
use .NET Framework 3.5. By using this
value, the SvcUtil.exe tool generates
code that references functionality in
.NET Framework 3.5 and previous
versions. When using /tcv:Version35
with the /async switch, both
event-based and
callback/delegate-based asynchronous
methods are generated. In addition,
support for LINQ-enabled DataSets and
DateTimeOffset is enabled.
What is the difference between event-based and callback/delegate based async models?
EDIT: Is one way newer/better? I only get the BeginXXX and EndXXX methods when I don't use the /tcv:Version35 switch. Silverlight uses XXXAsync which tells me I should use the event-based (XXXAsync) methods and use this switch.
Let's define a WCF service like this:
namespace StackOverflow
{
[ServiceContract]
public interface ITest
{
[OperationContract]
string GetName();
}
public class Test : ITest
{
public string GetName()
{
return "Joel Spolsky";
}
}
}
If you run svcutil on this, you'll get the following client definition:
public partial class TestClient : System.ServiceModel.ClientBase<ITest>, ITest
{
// Other details elided...
public string GetData(int value)
{
return base.Channel.GetData(value);
}
}
If you run svcutil again using the /async flag, you'll get the following client definition:
public partial class TestClient : System.ServiceModel.ClientBase<ITest>, ITest
{
// Other details elided...
public event System.EventHandler<GetDataCompletedEventArgs> GetDataCompleted;
public string GetData(int value)
{
return base.Channel.GetData(value);
}
[EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
public System.IAsyncResult BeginGetData(int value, System.AsyncCallback callback, object asyncState)
{
return base.Channel.BeginGetData(value, callback, asyncState);
}
[EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
public string EndGetData(System.IAsyncResult result)
{
return base.Channel.EndGetData(result);
}
public void GetDataAsync(int value, object userState)
{
if ((this.onBeginGetDataDelegate == null))
{
this.onBeginGetDataDelegate = new BeginOperationDelegate(this.OnBeginGetData);
}
if ((this.onEndGetDataDelegate == null))
{
this.onEndGetDataDelegate = new EndOperationDelegate(this.OnEndGetData);
}
if ((this.onGetDataCompletedDelegate == null))
{
this.onGetDataCompletedDelegate = new System.Threading.SendOrPostCallback(this.OnGetDataCompleted);
}
base.InvokeAsync(this.onBeginGetDataDelegate, new object[] {value}, this.onEndGetDataDelegate, this.onGetDataCompletedDelegate, userState);
}
}
So the /async flag simply provides a means for you to interact with your service asynchronously instead of the default synchronous-only behavior.
The GetDataAsync() method invokes the GetData() method asynchronously and notifies you when it is complete via the GetDataCompleted event.
The BeginGetData() and EndGetData() methods use the asynchronous behavior of delegates to invoke the GetData() method asynchronously. This is analogous to the BeginInvoke() and EndInvoke() methods on the System.Windows.Forms.Control class or the BeginRead() and EndRead() methods on the System.IO.Stream class.