Using a Custom Endpoint Behavior with WCF and Autofac
Asked Answered
G

1

6

I'm trying to implement a UoW like shown here: https://blog.iannelson.uk/wcf-global-exception-handling/

But I can't for the life of me figure out how to wire it up with Autofac. I have absolutely no idea where to start.

I've got WCF working fine with Autofac from using http://autofac.readthedocs.org/en/latest/integration/wcf.html

But to inject or add the IEndpointBehavior? No idea...

If there's a better way to implement a UoW I would like to hear.

Edit:

For now I've just done:

builder.RegisterType(typeof (UnitOfWork))
    .As(typeof (IUnitOfWork))
    .InstancePerLifetimeScope()
    .OnRelease(x =>
    {
        Trace.WriteLine("Comitted of UoW");
        ((IUnitOfWork) x).Commit();
        // OnRelease inhibits the default Autofac Auto-Dispose behavior so explicitly chain to it
        x.Dispose(); 
    });

Though I don't know if this is an acceptable way of doing it, seems like a hack :(

Edit2:

Doesn't seem like it's possible to run a UoW in WCF :/

Edit 3:

I've posted my solution here: http://www.philliphaydon.com/2011/11/06/unit-of-work-with-wcf-and-autofac/

Glycerinate answered 3/11, 2011 at 3:21 Comment(5)
+1, I'm also using WCF and Autofac, so good question :) It looks like your code always commits, so I'm wondering: how do you handle situations where you don't want to commit the work?Pitchy
@adrift - When Commit is called, it checks to see if the transaction is null or was rolled back. If it's not null and not rolled back, then it commits. If that makes sense. It's a hack to try get this to work until I find a better solution.Glycerinate
@adrift - I think I've solved the problem. I need to implement what's in my head and give it a good test but I will let you know my solution when it's done. If you want me to email you the solution directly (in-case you forget about this question) you can ping me at [blog (at) philliphaydon (dot) com]Glycerinate
@Phil: Move your solution to an answer to show other SO visitor that you've found a working solutionHyla
related: #7990418Moustache
I
3

I have found a solution to this problem, where the unit of work only will be committed if no errors is thrown.

Register the unit of work as InstancePerLifetimeScope in Autofac

    builder.RegisterType(typeof (UnitOfWork))
    .As(typeof (IUnitOfWork)).InstancePerLifetimeScope();

Then i have created a combined EndpointBehavior and a ErrorHandler.

public class UnitOfWorkEndpointBehavior : BehaviorExtensionElement, IEndpointBehavior
{
    public void Validate(ServiceEndpoint endpoint)
    {
    }

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        var unitOfWorkInstanceHandler = new UnitOfWorkInstanceHandler();

        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(unitOfWorkInstanceHandler);
        endpointDispatcher.DispatchRuntime.InstanceContextInitializers.Add(unitOfWorkInstanceHandler);
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    protected override object CreateBehavior()
    {
        return new UnitOfWorkEndpointBehavior();
    }

    public override Type BehaviorType
    {
        get { return typeof (UnitOfWorkEndpointBehavior); }
    }
}



public class UnitOfWorkInstanceHandler : IInstanceContextInitializer, IErrorHandler
{
    private bool _doCommit = true;

    public void Initialize(InstanceContext instanceContext, Message message)
    {
        instanceContext.Closing += CommitUnitOfWork;
    }

    void CommitUnitOfWork(object sender, EventArgs e)
    {
        //Only commit if no error has occured
        if (_doCommit)
        {
            //Resolve the UnitOfWork form scope in Autofac
            OperationContext.Current.InstanceContext.Extensions.Find<AutofacInstanceContext>().Resolve<IUnitOfWork>().Commit();
        }
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        _doCommit = false;
    }

    public bool HandleError(Exception error)
    {
        _doCommit = false;
        return false;
    }
}

The registration of the Endpoint Behavior in web.config

<system.serviceModel>
    ...
    <extensions>
      <behaviorExtensions>
        <add name="UnitOfWork" type="Namespace.UnitOfWorkBehavior, Namespace"/>
      </behaviorExtensions>
    </extensions>
      <behaviors>
        <endpointBehaviors>
          <behavior name="">
            <UnitOfWork/>
          </behavior>
        </endpointBehaviors>
    ...
    </behaviors>
    ...
</system.serviceModel>
Ibis answered 23/1, 2013 at 18:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.