2
\$\begingroup\$

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 } 
\$\endgroup\$
2
  • \$\begingroup\$I have used similar solution but for Autofac. Section _uow.BeginTransaction seems to work good.\$\endgroup\$
    – Afshar
    CommentedMay 28, 2016 at 8:24
  • \$\begingroup\$Yes, Also it's working well with Unity. As of now I didn't found any bug\$\endgroup\$
    – Mukesh
    CommentedMay 28, 2016 at 8:49

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.