Autofac和后台流程

时间:2017-06-15 13:32:51

标签: c# autofac

我正在使用WebApi 2并且需要在后台启动进程。我需要它来做它并不影响当前的请求。

所以经过一些挖掘后我发现我可以使用

public void Save(Order model) => Task.Run(() => postmanService.Update(model));

我想调试它以确保它正常工作,所以我将其更改为:

public void Save(Order model) => await postmanService.Update(model).ConfigureAwait(false);

但是当我运行这个时,我收到了这个错误:

  

“ObjectContext实例已被释放,不能再用于需要连接的操作。”

我不确定为什么会这样,因为我的 DatabaseContext 是这样注册的:

builder.RegisterType<DatabaseContext>().As<DbContext>().InstancePerLifetimeScope();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
builder.RegisterType<CollectionManagerProvider>().As<ICollectionManagerProvider>().InstancePerRequest();
builder.RegisterType<PostmanService>().As<IPostmanService>();

PostmanService 是将数据保存到数据库的内容,它看起来像这样:

public class PostmanService : Service<Postman>, IPostmanService
{
    public PostmanService(IUnitOfWork unitOfWork) : base(unitOfWork)
    {}

    /// <summary>
    /// Save or update a message
    /// </summary>
    /// <param name="model"></param>
    public void Save(Postman model)
    {
        if (model.Id == 0)
            Repository.Create(model);
        else
            Repository.Update(model);
    }

    /////////--------- Removed for brevity ---------/////////
}

存储库看起来像这样:

public class Repository<T> : IRepository<T> where T : class
{

    // Create our private properties
    private readonly DbContext _context;
    private readonly DbSet<T> _dbEntitySet;

    /// <summary>
    /// Default constructor
    /// </summary>
    /// <param name="context">The database context</param>
    public Repository(DbContext context)
    {
        // Assign our context and entity set
        _context = context ?? throw new ArgumentNullException("context");
        _dbEntitySet = context.Set<T>();
    }

    /// <summary>
    /// Creates an entity
    /// </summary>
    /// <param name="model"></param>
    public void Create(T model) => _dbEntitySet.Add(model);

    /// <summary>
    /// Updates an entity
    /// </summary>
    /// <param name="model"></param>
    public void Update(T model) => _context.Entry<T>(model).State = EntityState.Modified;

    /////////--------- Removed for brevity ---------/////////
}

最后,工作单元看起来像这样:

public class UnitOfWork : IUnitOfWork
{
    private readonly Dictionary<Type, object> _repositories;

    // Public properties
    public DbContext Context { get; }

    /// <summary>
    /// Default constructor
    /// </summary>
    public UnitOfWork(DbContext context)
    {
        Context = context;
        _repositories = new Dictionary<Type, object>();
    }

    /// <summary>
    /// Gets the entity repository
    /// </summary>
    /// <typeparam name="TEntity">The entity model</typeparam>
    /// <returns></returns>
    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {

        // If our repositories have a matching repository, return it
        if (_repositories.Keys.Contains(typeof(TEntity)))
            return _repositories[typeof(TEntity)] as IRepository<TEntity>;

        // Create a new repository for our entity
        var repository = new Repository<TEntity>(Context);

        // Add to our list of repositories
        _repositories.Add(typeof(TEntity), repository);

        // Return our repository
        return repository;
    }

    /// <summary>
    /// Saves the database changes asynchronously
    /// </summary>
    /// <returns></returns>
    public async Task SaveChangesAsync()
    {
        try
        {

            // Save the changes to the database
            await Context.SaveChangesAsync();
        }
        catch (DbEntityValidationException ex) {

            // Retrieve the error messages as a list of strings.
            var errorMessages = ex.EntityValidationErrors.SelectMany(x => x.ValidationErrors).Select(x => x.ErrorMessage);

            // Join the list to a single string.
            var fullErrorMessage = string.Join("; ", errorMessages);

            // Combine the original exception message with the new one.
            var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);

            // Throw a new DbEntityValidationException with the improved exception message.
            throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
        }
    }
}

我不确定问题是否与 CollectionManagerProvider 以及如何注册(因为我已将其注册为 InstancePerRequest ,并且技术上该方法是针对不同的主题。

有人可以帮我这个吗?

1 个答案:

答案 0 :(得分:0)

一种选择是使用Owned - http://docs.autofac.org/en/latest/advanced/owned-instances.html,并自行负责处理。

public Repository(Owned<DbContext> context)
public PostmanService(Owned<IUnitOfWork> unitOfWork)

等等

或:

builder.RegisterType<DatabaseContext>().As<DbContext>().Inst‌​ancePerLifetimeScope‌​().ExternallyOwned()‌​;
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope().ExternallyOwned()‌​;

等等

请参阅:

http://docs.autofac.org/en/latest/advanced/owned-instances.html http://docs.autofac.org/en/latest/lifetime/disposal.html