我在使用依賴注入方面還很陌生,我認(rèn)為我必須忽略一些非常簡單的事情.
我有一個(gè)Web API項(xiàng)目,在這里注冊(cè)通用存儲(chǔ)庫.存儲(chǔ)庫在其構(gòu)造函數(shù)中將dbContext作為參數(shù).
我發(fā)現(xiàn)很奇怪的行為是,我可以對(duì)服務(wù)進(jìn)行一次成功調(diào)用,但是隨后的任何調(diào)用都告訴我dbcontext已被處置.我確實(shí)有一個(gè)using語句,但這應(yīng)該不是問題,因?yàn)镈I應(yīng)該為每個(gè)Web請(qǐng)求創(chuàng)建依賴項(xiàng)的新實(shí)例(盡管我可能錯(cuò)了).
這是我的通用存儲(chǔ)庫:
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);
}
}
這是我的通用存儲(chǔ)庫接口:
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(非常標(biāo)準(zhǔn)):
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();
}
}
最后,這是給我?guī)砺闊┑目刂破鞯囊徊糠郑?/p>
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對(duì)象周圍的using語句行為不符合預(yù)期.在我進(jìn)行第一個(gè)服務(wù)調(diào)用后,_catRepo被處理掉了.在隨后的調(diào)用中,我希望實(shí)例化一個(gè)新的_catRepo.但是,情況并非如此,因?yàn)槲矣龅降腻e(cuò)誤是關(guān)于dbcontext被處置的.
我試圖將LifeTimeManager更改為其他可用的功能,但這無濟(jì)于事.
我也開始沿著另一條路線走,通用存儲(chǔ)庫將采用第二個(gè)通用類,并從中實(shí)例化其自己的dbcontext.但是,當(dāng)我這樣做時(shí),Unity找不到控制器的單參數(shù)構(gòu)造函數(shù).
我想,根據(jù)下面的評(píng)論,我真正需要的是一種基于每個(gè)請(qǐng)求實(shí)例化DbContext的方法.我不知道該怎么做.
任何提示將不勝感激. 解決方法: 讓我們來看看您的注冊(cè):
container.RegisterType<IGenericRepository<Cat>, GenericRepository<Cat>>(
new HierarchicalLifetimeManager(),
new InjectionConstructor(new AnimalEntities()));
container.RegisterType<IGenericRepository<Dog>, GenericRepository<Dog>>(
new HierarchicalLifetimeManager(),
new InjectionConstructor(new AnimalEntities()));
您將在啟動(dòng)時(shí)創(chuàng)建兩個(gè)AnimalEntities實(shí)例,但是這些實(shí)例在整個(gè)應(yīng)用程序期間將被重用.這是一個(gè)terrible idea.您可能打算擁有one DbContext per request,但是InjectionConstructor包裝的實(shí)例是一個(gè)常量.
您應(yīng)該將配置更改為以下內(nèi)容:
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()));
這要簡單得多,現(xiàn)在AnimalEntities也已注冊(cè)為“作用域”.
這樣做的好處是,一旦作用域(Web請(qǐng)求)結(jié)束,Unity現(xiàn)在將處置AnimalEntities.這樣可以避免您必須對(duì)AnimalEntities的使用者實(shí)施IDisposable,如here和here所述. 來源:https://www./content-4-521101.html
|