エラーがスローされない場合にのみ作業単位がコミットされるという、この問題の解決策を見つけました。
作業単位を InstancePerLifetimeScope として Autofac に登録する
builder.RegisterType(typeof (UnitOfWork))
.As(typeof (IUnitOfWork)).InstancePerLifetimeScope();
次に、EndpointBehavior と 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;
}
}
web.config での Endpoint Behavior の登録
<system.serviceModel>
...
<extensions>
<behaviorExtensions>
<add name="UnitOfWork" type="Namespace.UnitOfWorkBehavior, Namespace"/>
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior name="">
<UnitOfWork/>
</behavior>
</endpointBehaviors>
...
</behaviors>
...
</system.serviceModel>