在.Net Core上使用Simple Injector进行Audit.EntityFramework

时间:2018-05-23 14:38:42

标签: c# entity-framework simple-injector audit.net

我目前正在使用.net core 2.0和Audit.EntityFramework审核我的实体的更改。

我已经走了创建自己的CustomProvider的路线,正如下面DataProviders简要说明中所述。

EmployerCustomDataProvider

public class EmployerCustomDataProvider : AuditDataProvider, IEmployerCustomDataProvider {
    private readonly IUnitOfWork _unitOfWork;

    public EmployerCustomDataProvider (IUnitOfWork unitOfWork, IMapper mapper) {
        _unitOfWork = unitOfWork;
    }

    // Async Implementation
    public override async Task<object> InsertEventAsync (AuditEvent auditEvent) {
            // Unique Id For Audit Event
            var Id = Guid.NewGuid ();
            EntityFrameworkEvent auditEntityFrameworkEvent = auditEvent.GetEntityFrameworkEvent ();

            // Need to audit each entry
            List<EventEntry> eventEntries = auditEntityFrameworkEvent.Entries;

            foreach (EventEntry entry in eventEntries) {
                EmployerAuditHistory employerAuditHistory = Mapper.Map<EmployerAuditHistory> (entry);
                this._unitOfWork.EmployerAuditHistoryRepository.Insert (employerAuditHistory);

                await this._unitOfWork.CommitAsync ();

                foreach (EventEntryChange change in entry.Changes) {
                    EmployerAuditHistoryDetail employerAuditHistoryDetail = new EmployerAuditHistoryDetail ();
                    employerAuditHistoryDetail.EmployerAuditHistoryId = employerAuditHistory.EmployerAuditHistoryId;
                    employerAuditHistoryDetail.ColumnName = change.ColumnName;
                    employerAuditHistoryDetail.OriginalValue = change.OriginalValue.ToString ();
                    employerAuditHistoryDetail.NewValue = change.NewValue.ToString ();

                    this._unitOfWork.EmployerAuditHistoryDetailRepository.Insert (employerAuditHistoryDetail);
                }
            }

            return await Task.Run (() => Id);
        }

        ...

根据文档,在以下条件下调用此自定义提供程序。

  

此库拦截对DbContext上的SaveChanges()/ SaveChangesAsync()的调用,以生成包含受影响实体信息的Audit.NET事件。

     

每次调用SaveChanges都会生成一个审核事件,其中包含受保存操作影响的所有实体的信息。

在我的业务层中,我有一个这样的方法,即创建或更新雇主分支。

EmployerBranchService:业务层

public class EmployerBranchService : BaseService, IEmployerBranchService {
private readonly IUnitOfWork _unitOfWork;

public EmployerBranchService (IMapper mapper, IUnitOfWork unitOfWork) : base (mapper) {
    this._unitOfWork = unitOfWork;
}
private async Task<EmployerBranchModel> CreateUpdateEmployerBranch (EmployerBranchModel employerBranchModel) {
    EmployerBranch employerBranch = Mapper.Map (employerBranchModel, await this._unitOfWork.EmployerBranchRepository.GetEmployerBranchById (employerBranchModel.EmployerBranchId.Value));

    if ((employerBranch?.EmployerBranchId ?? 0) == 0)
        this._unitOfWork.EmployerBranchRepository.Insert (employerBranch);
    else
        this._unitOfWork.EmployerBranchRepository.Update (employerBranch);

    await this._unitOfWork.CommitAsync ();

    return Mapper.Map<EmployerBranchModel> (employerBranch);
    }
}

当调用我的工作单元提交时,分支按预期保存,然后我在 EmployerCustomDataProvider InsertEventAsync 方法中登陆。但是,当我在这里调用工作单元时,我会收到以下错误。

  

无法访问已处置的对象。导致此错误的常见原因是   处理从依赖注入解决的上下文   然后尝试在你的其他地方使用相同的上下文实例   应用。如果您正在调用Dispose(),则可能会发生这种情况   上下文,或将上下文包装在using语句中。如果你是   使用依赖注入,你应该让依赖注入   容器负责处理上下文实例。对象名称:   &#39; EmployerContext&#39;

在我看来,问题在于,当业务层工作单元提交它的更改时,上下文就会被处理掉。我不确定如何解决这个问题,因为我尝试以不同的方式注册我的依赖项等。

我已尝试在我的程序方法中注册审核设置。

程序

  public class Program
{

    public static void Main(string[] args)
    {
        IWebHost host = BuildWebHost(args);
        SeedDatabase(host);
        SetupAudit(host);
        host.Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();

    //Seed database methods in .net core need to be done in the Program method:
    //https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/intro
    public static void SeedDatabase(IWebHost host)
    {
        using (var scope = host.Services.CreateScope())
        {
            var services = scope.ServiceProvider;
            try
            {
                EmployerContext context = services.GetRequiredService<EmployerContext>();
                DbInitializer.Seed(context);
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred while seeding the database.");
            }
        }
    }

    public static void SetupAudit(IWebHost host)
    {
        var _container = DependencyInjectionConfig.Container;

        using (AsyncScopedLifestyle.BeginScope(_container))
        {
            AuditConfiguration.SetupAuditConfiguration(_container);
        }
    }
}

DependencyInjectionConfig

public class DependencyInjectionConfig
{
    private static Container _container;

    public static Container Container
    {
        get
        {
            if (_container == null)
            {
                _container = new Container();
                _container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
            }

            return _container;
        }
    }

    public static void InitializeContainer(IApplicationBuilder app)
    {
        Container.RegisterMvcControllers(app);
        Container.RegisterMvcViewComponents(app);
        Container.CrossWire<EmployerContext>(app);

        Container.Register<ITypeService, TypeService>(Lifestyle.Scoped);
        Container.Register<IEmployerService, EmployerService>(Lifestyle.Scoped);
        Container.Register<IEmployerPersonContactService, EmployerPersonContactService>(Lifestyle.Scoped);
        Container.Register<IEmployerBranchService, EmployerBranchService>(Lifestyle.Scoped);
        Container.Register<IEmployerSearchService, EmployerSearchService>(Lifestyle.Scoped);
        Container.Register<INoteService, NoteService>(Lifestyle.Scoped);

        Container.Register<IBaseModelUsernameResolver, BaseModelUsernameResolver>(Lifestyle.Scoped);

        Container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
        Container.Register<IEmployerNoteTypeRepository, EmployerNoteTypeRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerDocumentTypeRepository, EmployerDocumentTypeRepository>(Lifestyle.Scoped);
        Container.Register<IPrivatePayrollRepository, PrivatePayrollRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerRepository, EmployerRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerContactDetailsRepository, EmployerContactDetailsRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerAddressRepository, EmployerAddressRepository>(Lifestyle.Scoped);
        Container.Register<IUserRepository, UserRepository>(Lifestyle.Scoped);
        Container.Register<ISearchRepository, SearchRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerBranchRepository, EmployerBranchRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerBranchContactDetailsRepository, EmployerBranchContactDetailsRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerBranchAddressRepository, EmployerBranchAddressRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerPersonContactRepository, EmployerPersonContactRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerBranchSummaryRepository, EmployerBranchSummaryRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerAuditHistoryRepository, EmployerAuditHistoryRepository>(Lifestyle.Scoped);
        Container.Register<INoteRepository, NoteRepository>(Lifestyle.Scoped);
        Container.Register<IEmployerAuditHistoryDetailRepository, EmployerAuditHistoryDetailRepository>(Lifestyle.Scoped); 

        Container.Register<IEmployerCustomDataProvider, EmployerCustomDataProvider>(Lifestyle.Scoped);

        Container.AutoCrossWireAspNetComponents(app);
        Container.Verify();
    }

    public static void Register<TService, TImplementation>() where TService : class where TImplementation : class, TService
    {
        Container.Register<TService, TImplementation>();
    }
}

AuditConfiguration

 public static class AuditConfiguration
{
    public static void SetupAuditConfiguration(SimpleInjector.Container container)
    {
        Configuration.Setup()
            .UseCustomProvider((AuditDataProvider)container.GetInstance<IEmployerCustomDataProvider>())
            .WithCreationPolicy(EventCreationPolicy.InsertOnEnd);

        Audit.EntityFramework.Configuration.Setup()
                    .ForContext<EmployerContext>(config => config
                        .IncludeEntityObjects()
                        .AuditEventType("{context}:{database}"))
                    .UseOptOut();
    }
}

的UnitOfWork

 public class UnitOfWork : IUnitOfWork
{
    private readonly EmployerContext _context;
    private readonly IEmployerRepository _employerRepository;
    private readonly IEmployerContactDetailsRepository _employerContactDetailsRepository;
    private readonly IEmployerAddressRepository _employerAddressRepository;
    private readonly IEmployerPersonContactRepository _employerPersonContactRepository;
    private readonly IEmployerBranchRepository _employerBranchRepository;
    private readonly IEmployerBranchContactDetailsRepository _employerBranchContactDetailsRepository;
    private readonly IEmployerBranchAddressRepository _employerBranchAddressRepository;

    private readonly IEmployerDocumentTypeRepository _employerDocumentTypeRepository;
    private readonly IEmployerNoteTypeRepository _employerNoteTypeRepository;
    private readonly IPrivatePayrollRepository _privatePayrollRepository;
    private readonly IEmployerBranchSummaryRepository _employerBranchSummaryRepository;
    private readonly INoteRepository _employerBranchNoteRepository;
    private readonly ISearchRepository _searchRepository;
    private readonly IEmployerAuditHistoryRepository _employerAuditHistoryRepository;
    private readonly IEmployerAuditHistoryDetailRepository _employerAuditHistoryDetailRepository;

    public IEmployerRepository EmployerRepository => this._employerRepository;
    public IEmployerContactDetailsRepository EmployerContactDetailsRepository => this._employerContactDetailsRepository;
    public IEmployerAddressRepository EmployerAddressRepository => this._employerAddressRepository;
    public IEmployerPersonContactRepository EmployerPersonContactRepository => this._employerPersonContactRepository;
    public IEmployerBranchRepository EmployerBranchRepository => this._employerBranchRepository;
    public IEmployerBranchContactDetailsRepository EmployerBranchContactDetailsRepository => this._employerBranchContactDetailsRepository;
    public IEmployerBranchAddressRepository EmployerBranchAddressRepository => this._employerBranchAddressRepository;
    public IEmployerDocumentTypeRepository EmployerDocumentTypeRepository { get => this._employerDocumentTypeRepository; }
    public IEmployerNoteTypeRepository EmployerNoteTypeRepository { get => this._employerNoteTypeRepository; }
    public IPrivatePayrollRepository PrivatePayrollRepository { get => this._privatePayrollRepository; }
    public IEmployerBranchSummaryRepository EmployerBranchSummaryRepository { get => this._employerBranchSummaryRepository; }
    public INoteRepository EmployerBranchNoteRepository { get => this._employerBranchNoteRepository; }
    public ISearchRepository SearchRepository { get => this._searchRepository; }
    public IEmployerAuditHistoryRepository EmployerAuditHistoryRepository { get => this._employerAuditHistoryRepository; }
    public IEmployerAuditHistoryDetailRepository EmployerAuditHistoryDetailRepository { get => this._employerAuditHistoryDetailRepository; }

    public UnitOfWork(EmployerContext context,
        IEmployerRepository employerRepository,
        IEmployerContactDetailsRepository employerContactDetailsRepository,
        IEmployerAddressRepository employerAddressRepository,
        IEmployerPersonContactRepository employerBranchPersonRepository,
        IEmployerBranchRepository employerBranchRepository,
        IEmployerBranchContactDetailsRepository employerBranchContactDetailsRepository,
        IEmployerBranchAddressRepository employerBranchAddressRepository,
        IEmployerDocumentTypeRepository employerDocumentTypeRepository,
        IEmployerNoteTypeRepository employerNoteTypeRepository,
        IPrivatePayrollRepository privatePayrollRepository,
        IEmployerBranchSummaryRepository employerBranchSummaryRepository,
        INoteRepository EmployerBranchNoteRepository,
        ISearchRepository SearchRepository,
        IEmployerAuditHistoryRepository EmployerAuditHistoryRepository,
        IEmployerAuditHistoryDetailRepository EmployerAuditHistoryDetailRepository)
    {
        this._employerRepository = employerRepository;
        this._employerContactDetailsRepository = employerContactDetailsRepository;
        this._employerAddressRepository = employerAddressRepository;
        this._employerPersonContactRepository = employerBranchPersonRepository;
        this._employerBranchRepository = employerBranchRepository;
        this._employerBranchContactDetailsRepository = employerBranchContactDetailsRepository;
        this._employerBranchAddressRepository = employerBranchAddressRepository;

        this._employerDocumentTypeRepository = employerDocumentTypeRepository;
        this._employerNoteTypeRepository = employerNoteTypeRepository;
        this._privatePayrollRepository = privatePayrollRepository;
        this._employerBranchSummaryRepository = employerBranchSummaryRepository;
        this._employerBranchNoteRepository = EmployerBranchNoteRepository;
        this._searchRepository = SearchRepository;
        this._employerAuditHistoryRepository = EmployerAuditHistoryRepository;
        this._employerAuditHistoryDetailRepository = EmployerAuditHistoryDetailRepository;

        this._context = context;
    }

    public void Commit()
    {
        try
        {
            this._context.SaveChanges();
        }
        catch (Exception)
        {
            throw;
        }
    }

    public async Task CommitAsync()
    {
        try
        {
            await this._context.SaveChangesAsync();
        }
        catch (Exception e)
        {
            throw;
        }
    }

    private bool disposed = false;

    protected virtual void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            if (disposing)
            {
                this._context.Dispose();
            }
        }
        this.disposed = true;
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

EmployerBranchRepository

 public class EmployerBranchRepository : RepositoryBase<EmployerBranch>, IEmployerBranchRepository
{
    public EmployerBranchRepository(EmployerContext context) : base(context)
    {

    }

    public async Task<EmployerBranch> GetEmployerBranchById(int employerBranchId)
    {
        return await base.FindAsync(e => e.IsActive && e.EmployerBranchId == employerBranchId);
    }

    public async Task<IList<EmployerBranch>> GetEmployerBranchesByEmployerId(int employerId)
    {
        return await base.FindAll(e => e.IsActive && e.EmployerId == employerId).ToListAsync();
    }
}

RepositoryBase

  public abstract class RepositoryBase<TEntity> : RepositoryReadOnlyBase<TEntity>, IRepository<TEntity> where TEntity : class
{
    /// <summary>
    /// Initializes a new instance of the <see cref="RepositoryBase{TEntity}"/> class.
    /// </summary>
    /// <param name="unitOfWork">The unit of work.</param>
    /// <exception cref="NullReferenceException">Unit Of Work cannot be null</exception>
    public RepositoryBase(EmployerContext context) : base(context)
    {

    }

    /// <summary>
    /// Inserts the specified entity.
    /// </summary>
    /// <param name="entity">The entity.</param>
    public void Insert(TEntity entity)
    {
        this._dbSet.Add(entity);
    }

    /// <summary>
    /// Updates the specified entity.
    /// </summary>
    /// <param name="entity">The entity.</param>
    public void Update(TEntity entity)
    {
        this._dbSet.Attach(entity);
        this._dbContext.Entry(entity).State = EntityState.Modified;

        PropertyEntry InsertedUserId = this._dbContext.Entry(entity).Property("InsertedUserId");
        if (InsertedUserId != null)
            InsertedUserId.IsModified = false;
        PropertyEntry InsertedDate = this._dbContext.Entry(entity).Property("InsertedDate");
        if (InsertedDate != null)
            InsertedDate.IsModified = false;
    }
}

RepositoryReadOnlyBase

public class RepositoryReadOnlyBase<TEntity> : IRepositoryReadOnly<TEntity> where TEntity : class
{
    public readonly DbSet<TEntity> _dbSet;
    public readonly EmployerContext _dbContext;

    /// <summary>
    /// Initializes a new instance of the <see cref="RepositoryBase{TEntity}"/> class.
    /// </summary>
    /// <param name="unitOfWork">The unit of work.</param>
    /// <exception cref="NullReferenceException">Unit Of Work cannot be null</exception>
    public RepositoryReadOnlyBase(EmployerContext context)
    {
        this._dbContext = context;
        this._dbSet = this._dbContext.Set<TEntity>();
    }

    /// <summary>
    /// Finds all asynchronous.
    /// </summary>
    /// <param name="predicate">The predicate.</param>
    /// <param name="orderBy">The order by.</param>
    /// <returns></returns>
    public IQueryable<TEntity> FindAll(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, params Expression<Func<TEntity, object>>[] includes)
    {
        IQueryable<TEntity> query = this._dbContext.Set<TEntity>();

        if (includes != null)
        {
            query = query = includes.Aggregate(query,
              (current, include) => current.Include(include));
        }

        if (predicate != null)
            query = query.Where(predicate);

        if (orderBy != null)
            query = orderBy(query);

        return query;
    }

    /// <summary>
    /// Finds the asynchronous.
    /// </summary>
    /// <param name="predicate">The predicate.</param>
    /// <param name="orderBy">The order by.</param>
    /// <returns></returns>
    public async Task<TEntity> FindAsync(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, params Expression<Func<TEntity, object>>[] includes)
    {
        return await this.FindAll(predicate, orderBy, includes).FirstOrDefaultAsync();
    }

    public Task<TEntity> FindByIdAsync(int id)
    {
        return this._dbSet.FindAsync(id);
    }
}

我不确定要包含多少详细信息,但可以包含工作单元等的摘录。感谢任何方向/建议

修改 堆栈跟踪

  

at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()      在Microsoft.EntityFrameworkCore.DbContext.Add [TEntity](TEntity实体)      在Microsoft.EntityFrameworkCore.Internal.InternalDbSet 1.Add(TEntity entity) at Employer.API.Data.Repository.RepositoryBase 1.插入(TEntity实体)在C:\ Information Systems \ Micro Services \ Employer.API \ head \ Employer.API.Data \ Repository \ RepositoryBase.cs:第29行      at Employer.API.Business.DataProvider.EmployerCustomDataProvider.d__5.MoveNext()在C:\ Information Systems \ Micro Services \ Employer.API \ head \ Employer.API.Business \ DataProvider \ EmployerCustomDataProvider.cs:第77行   ---从抛出异常的先前位置开始的堆栈跟踪结束---      在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()      在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)      在System.Runtime.CompilerServices.TaskAwaiter 1.GetResult() at Audit.Core.AuditScope.<SaveEventAsync>d__40.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Audit.Core.AuditScope.<SaveAsync>d__34.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Audit.EntityFramework.DbContextHelper.<SaveScopeAsync>d__21.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Audit.EntityFramework.DbContextHelper.<SaveChangesAsync>d__34.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter 1.GetResult()      在Audit.EntityFramework.AuditDbContext.d__36.MoveNext()   ---从抛出异常的先前位置开始的堆栈跟踪结束---      在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()      在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务)      在System.Runtime.CompilerServices.TaskAwaiter 1.GetResult() at Employer.API.Data.UnitOfWork.UnitOfWork.<CommitAsync>d__48.MoveNext() in C:\Information Systems\Micro Services\Employer.API\head\Employer.API.Data\UnitOfWork\UnitOfWork.cs:line 103 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Employer.API.Business.Services.EmployerBranchService.<CreateUpdateEmployerBranch>d__6.MoveNext() in C:\Information Systems\Micro Services\Employer.API\head\Employer.API.Business\Services\EmployerBranchService.cs:line 135 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter 1.GetResult()      at Employer.API.Business.Services.EmployerBranchService.d__5.MoveNext()在C:\ Information Systems \ Micro Services \ Employer.API \ head \ Employer.API.Business \ Services \ EmployerBranchService.cs:第89行

0 个答案:

没有答案