打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
在WebApi项目上使用Unity依赖注入时,将处置DbContext

我在使用依赖注入方面还很陌生,我认为我必须忽略一些非常简单的事情.

我有一个Web API项目,在这里注册通用存储库.存储库在其构造函数中将dbContext作为参数.

我发现很奇怪的行为是,我可以对服务进行一次成功调用,但是随后的任何调用都告诉我dbcontext已被处置.我确实有一个using语句,但这应该不是问题,因为DI应该为每个Web请求创建依赖项的新实例(尽管我可能错了).

这是我的通用存储库:

 public class GenericRepository<T> : IGenericRepository<T> where T : class{    internal DbContext _context;    internal DbSet<T> _dbSet;    private bool disposed;    public GenericRepository(DbContext context)    {        _context = context;        _dbSet = _context.Set<T>();    }    /// <summary>    /// This constructor will set the database of the repository     /// to the one indicated by the "database" parameter    /// </summary>    /// <param name="context"></param>    /// <param name="database"></param>           public GenericRepository(string database = null)    {        SetDatabase(database);    }    public void SetDatabase(string database)    {        var dbConnection = _context.Database.Connection;        if (string.IsNullOrEmpty(database) || dbConnection.Database == database)            return;        if (dbConnection.State == ConnectionState.Closed)            dbConnection.Open();        _context.Database.Connection.ChangeDatabase(database);    }    public virtual IQueryable<T> Get()    {        return _dbSet;    }    public virtual T GetById(object id)    {        return _dbSet.Find(id);    }    public virtual void Insert(T entity)    {        _dbSet.Add(entity);    }    public virtual void Delete(object id)    {        T entityToDelete = _dbSet.Find(id);        Delete(entityToDelete);    }    public virtual void Delete(T entityToDelete)    {        if (_context.Entry(entityToDelete).State == EntityState.Detached)        {            _dbSet.Attach(entityToDelete);        }        _dbSet.Remove(entityToDelete);    }    public virtual void Update(T entityToUpdate)    {        _dbSet.Attach(entityToUpdate);        _context.Entry(entityToUpdate).State = EntityState.Modified;    }    public virtual void Save()    {        _context.SaveChanges();    }    public void Dispose()    {        Dispose(true);        GC.SuppressFinalize(this);    }    protected virtual void Dispose(bool disposing)    {        if (disposed)            return;        if (disposing)        {            //free managed objects here            _context.Dispose();        }        //free any unmanaged objects here        disposed = true;    }    ~GenericRepository()    {        Dispose(false);    }}

这是我的通用存储库接口:

 public interface IGenericRepository<T> : IDisposable where T : class{    void SetDatabase(string database);    IQueryable<T> Get();           T GetById(object id);    void Insert(T entity);    void Delete(object id);    void Delete(T entityToDelete);    void Update(T entityToUpdate);    void Save();}

这是我的WebApiConfig:

public static class WebApiConfig{    public static void Register(HttpConfiguration config)    {        // Web API configuration and services        var container = new UnityContainer();        container.RegisterType<IGenericRepository<Cat>, GenericRepository<Cat>>(new HierarchicalLifetimeManager(), new InjectionConstructor(new AnimalEntities()));        container.RegisterType<IGenericRepository<Dog>, GenericRepository<Dog>>(new HierarchicalLifetimeManager(), new InjectionConstructor(new AnimalEntities()));                   config.DependencyResolver = new UnityResolver(container);        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));        // Web API routes        config.MapHttpAttributeRoutes();        config.Routes.MapHttpRoute(            name: "DefaultApi",            routeTemplate: "api/{controller}/{id}",            defaults: new { id = RouteParameter.Optional }        );    }}

这是我的DependencyResolver(非常标准):

public class UnityResolver : IDependencyResolver{    protected IUnityContainer container;    public UnityResolver(IUnityContainer container)    {        this.container = container ?? throw new ArgumentNullException(nameof(container));    }    public object GetService(Type serviceType)    {        try        {            return container.Resolve(serviceType);        }        catch (ResolutionFailedException)        {            return null;        }    }    public IEnumerable<object> GetServices(Type serviceType)    {        try        {            return container.ResolveAll(serviceType);        }        catch (ResolutionFailedException)        {            return new List<object>();        }    }    public IDependencyScope BeginScope()    {        var child = container.CreateChildContainer();        return new UnityResolver(child);    }    public void Dispose()    {        Dispose(true);    }    protected virtual void Dispose(bool disposing)    {        container.Dispose();    }}

最后,这是给我带来麻烦的控制器的一部分:

public class AnimalController : ApiController{    private readonly IGenericRepository<Cat> _catRepo;    private readonly IGenericRepository<Dog> _dogPackRepo;    public AnimalController(IGenericRepository<Cat> catRepository,        IGenericRepository<Dog> dogRepository)    {        _catRepo = catRepository;        _dogRepo = dogRepository;    }    [HttpGet]    public AnimalDetails GetAnimalDetails(int tagId)    {        var animalDetails = new animalDetails();        try        {            var dbName = getAnimalName(tagId);            if (dbName == null)            {                animalDetails.ErrorMessage = $"Could not find animal name for tag Id {tagId}";                return animalDetails;            }        }        catch (Exception ex)        {            //todo: add logging            Console.WriteLine(ex.Message);            animalDetails.ErrorMessage = ex.Message;            return animalDetails;        }        return animalDetails;    }    private string getAnimalName(int tagId)    {        try        {            //todo: fix DI so dbcontext is created on each call to the controller            using (_catRepo)            {                return _catRepo.Get().Where(s => s.TagId == tagId.ToString()).SingleOrDefault();            }        }        catch (Exception e)        {            //todo: add logging            Console.WriteLine(e);            throw;        }    }       }

_catRepo对象周围的using语句行为不符合预期.在我进行第一个服务调用后,_catRepo被处理掉了.在随后的调用中,我希望实例化一个新的_catRepo.但是,情况并非如此,因为我遇到的错误是关于dbcontext被处置的.

我试图将LifeTimeManager更改为其他可用的功能,但这无济于事.

我也开始沿着另一条路线走,通用存储库将采用第二个通用类,并从中实例化其自己的dbcontext.但是,当我这样做时,Unity找不到控制器的单参数构造函数.

我想,根据下面的评论,我真正需要的是一种基于每个请求实例化DbContext的方法.我不知道该怎么做.

任何提示将不胜感激.

解决方法:

让我们来看看您的注册:

container.RegisterType<IGenericRepository<Cat>, GenericRepository<Cat>>(    new HierarchicalLifetimeManager(),     new InjectionConstructor(new AnimalEntities()));container.RegisterType<IGenericRepository<Dog>, GenericRepository<Dog>>(    new HierarchicalLifetimeManager(),     new InjectionConstructor(new AnimalEntities()));

您将在启动时创建两个AnimalEntities实例,但是这些实例在整个应用程序期间将被重用.这是一个terrible idea.您可能打算拥有one DbContext per request,但是InjectionConstructor包装的实例是一个常量.

您应该将配置更改为以下内容:

container.RegisterType<IGenericRepository<Cat>, GenericRepository<Cat>>(    new HierarchicalLifetimeManager());container.RegisterType<IGenericRepository<Dog>, GenericRepository<Dog>>(    new HierarchicalLifetimeManager());// Separate 'scoped' registration for AnimalEntities.container.Register<AnimalEntities>(    new HierarchicalLifetimeManager()    new InjectionFactory(c => new AnimalEntities()));

这要简单得多,现在AnimalEntities也已注册为“作用域”.

这样做的好处是,一旦作用域(Web请求)结束,Unity现在将处置AnimalEntities.这样可以避免您必须对AnimalEntities的使用者实施IDisposable,如herehere所述.

来源:https://www.icode9.com/content-4-521101.html
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
MVC3+EF4.1学习系列(八)
MVC中的Repository模式
EntityFramework 学习之二 —— EF开发模式
(22)ASP.NET Core2.2 EF创建模型(索引、备用键、继承、支持字段)
ASP.NET MVC Bootstrap极速开发框架
MVC中使用Entity Framework 基于方法的查询学习笔记 (二)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服