Unity Configuration
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<ITrackoApiDbContext, TrackoApiDbContext>(new PerRequestLifetimeManager());
container.RegisterType<IUnitOfWorkAsync, UnitOfWork>(new PerRequestLifetimeManager());
//Call External Unity Configuration Library as Rest of the Unity Configuration is kept outside of WebApi Project
new TrackoApi.Unity.Configure(container);
}
Statup.cs for Owin
public void Configuration(IAppBuilder app)
{
var config=new HttpConfiguration();
var resolver = new UnityHierarchicalDependencyResolver(UnityConfig.GetConfiguredContainer());
config.DependencyResolver = resolver;
app.UseStageMarker(PipelineStage.MapHandler);
WebApiConfig.Register(config);
}
BatchServer.cs
public class BatchServer : HttpServer
{
private readonly HttpConfiguration _config;
public BatchServer(HttpConfiguration configuration)
: base(configuration)
{
_config = configuration;
}
protected override void Initialize()
{
var firstInPipeline = _config.MessageHandlers.FirstOrDefault();
if (firstInPipeline != null && firstInPipeline.InnerHandler != null)
{
InnerHandler = firstInPipeline;
}
else
{
base.Initialize();
}
}
}
ODataBatchHandlerSingleTransaction.cs
public class ODataBatchHandlerSingleTransaction : DefaultODataBatchHandler
{
private readonly IUnityContainer _unity;
private IUnitOfWorkAsync _uow;
public ODataBatchHandlerSingleTransaction(HttpServer httpServer) : base(httpServer)
{
Server = httpServer;
var uhdr = (UnityHierarchicalDependencyResolver)Server.Configuration.DependencyResolver;
_unity= ((IUnityContainer)uhdr.GetService(typeof(IUnityContainer)));
}
public HttpServer Server { get; private set; }
public override async Task<IList<ODataBatchResponseItem>> ExecuteRequestMessagesAsync(
IEnumerable<ODataBatchRequestItem> requests, CancellationToken cancellationToken)
{
if (requests == null)
{
throw new ArgumentNullException(nameof(requests));
}
//return base.ExecuteRequestMessagesAsync(requests, cancellationToken);
IList<ODataBatchResponseItem> responses = new List<ODataBatchResponseItem>();
try
{
foreach (ODataBatchRequestItem request in requests)
{
var operation = request as OperationRequestItem;
if (operation != null)
{
responses.Add(await operation.SendRequestAsync(Invoker, cancellationToken));
}
else
{
await ExecuteChangeSet((ChangeSetRequestItem)request, responses, cancellationToken);
}
}
}
catch
{
foreach (ODataBatchResponseItem response in responses)
{
response?.Dispose();
}
throw;
}
return responses;
}
private async Task ExecuteChangeSet(ChangeSetRequestItem changeSet, IList<ODataBatchResponseItem> responses,
CancellationToken cancellationToken)
{
_uow = _unity.Resolve<IUnitOfWorkAsync>();
using (_uow)
{
_uow.BeginTransaction(IsolationLevel.Serializable);
foreach (HttpRequestMessage request in changeSet.Requests)
{
request.SetContext(_uow);
}
var changeSetResponse = (ChangeSetResponseItem)await changeSet.SendRequestAsync(Invoker, cancellationToken);
responses.Add(changeSetResponse);
if (changeSetResponse.Responses.All(x => x.IsSuccessStatusCode))
{
_uow.Commit();
}
else
{
_uow.Rollback();
}
}
}
}
HttpRequestMessageExtensions.cs An extrension class to set and get Owin Context to and from HttpRequest
public static class HttpRequestMessageExtensions
{
private const string DbContext = "Batch_DbContext";
public static void SetContext(this HttpRequestMessage request, IUnitOfWorkAsync context)
{
try
{
request.Properties[DbContext] = context;
}
catch (Exception)
{
throw;
}
}
public static IUnitOfWorkAsync GetContext(this HttpRequestMessage request)
{
try
{
object trackoApiContext;
if (request.Properties.TryGetValue(DbContext, out trackoApiContext))
{
return (IUnitOfWorkAsync)trackoApiContext;
}
var uhdr = (UnityHierarchicalDependencyResolver)request.GetConfiguration().DependencyResolver;
var _uow = ((IUnityContainer)uhdr.GetService(typeof(IUnityContainer))).Resolve<IUnitOfWorkAsync>();
SetContext(request, _uow);
//request.RegisterForDispose(unity);
return _uow;
}
catch (Exception)
{
throw;
}
}
}
WebApiConfig.cs Attach Batch Handler to GlobalConfiguration
ODataBatchHandler odataBatchHandler = new ODataBatchHandlerSingleTransaction(new BatchServer(config));
config.MapODataServiceRoute("ODataRoute", "odata", Configure.GetEdnModel(), defaultHandler: odataBatchHandler);
Consuming it Controller
await Request.GetContext().SaveChangesAsync();
UnitOfWork.cs
public class UnitOfWork : IUnitOfWorkAsync
{
#region Private Fields
private ITrackoApiDbContext _dataContext;
private bool _disposed;
private ObjectContext _objectContext;
private DbTransaction _transaction;
private Dictionary<string, dynamic> _repositories;
#endregion Private Fields
#region Constuctor/Dispose
public UnitOfWork(ITrackoApiDbContext dataContext)
{
_dataContext = dataContext;
//_objectContext=_dataContext as ObjectContext;
_objectContext = ((IObjectContextAdapter)_dataContext).ObjectContext;
var db = _dataContext as DbContext;
_repositories = new Dictionary<string, dynamic>();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
// free other managed objects that implement
// IDisposable only
try
{
if (_objectContext != null && _objectContext.Connection.State == ConnectionState.Open)
{
_objectContext.Connection.Close();
}
}
catch (ObjectDisposedException)
{
// do nothing, the objectContext has already been disposed
}
if (_dataContext != null)
{
_dataContext.Dispose();
_dataContext = null;
}
}
// release any unmanaged objects
// set the object references to null
_disposed = true;
}
#endregion Constuctor/Dispose
public int SaveChanges()
{
return _dataContext.SaveChanges();
}
public IRepository<TEntity> Repository<TEntity>() where TEntity : class
{
return RepositoryAsync<TEntity>();
}
public Task<int> SaveChangesAsync()
{
return _dataContext.SaveChangesAsync();
}
public Task<int> SaveChangesAsync(CancellationToken cancellationToken)
{
return _dataContext.SaveChangesAsync(cancellationToken);
}
public IRepositoryAsync<TEntity> RepositoryAsync<TEntity>() where TEntity : class
{
//if (ServiceLocator.IsLocationProviderSet)
//{
// return ServiceLocator.Current.GetInstance<IRepositoryAsync<TEntity>>();
//}
if (_repositories == null)
{
_repositories = new Dictionary<string, dynamic>();
}
var type = typeof(TEntity).Name;
if (_repositories.ContainsKey(type))
{
return (IRepositoryAsync<TEntity>)_repositories[type];
}
var repositoryType = typeof(Repository<>);
_repositories.Add(type, Activator.CreateInstance(repositoryType.MakeGenericType(typeof(TEntity)), _dataContext, this));
return _repositories[type];
}
#region Unit of Work Transactions
public void BeginTransaction(IsolationLevel isolationLevel = IsolationLevel.Unspecified)
{
//_objectContext = ((IObjectContextAdapter) _dataContext).ObjectContext;
if (_objectContext.Connection.State != ConnectionState.Open)
{
_objectContext.Connection.Open();
}
_transaction = _objectContext.Connection.BeginTransaction(isolationLevel);
}
public bool Commit()
{
_transaction.Commit();
return true;
}
public void Rollback()
{
_transaction.Rollback();
_dataContext.SyncObjectsStatePostCommit();
}
#endregion
}
Autofac
. Section_uow.BeginTransaction
seems to work good. – afsharm May 28 at 8:24