在ASP.NET MVC中,我为基本模型的CRUD操作创建了通用控制器。
我正在将通用存储库接口以及工作单元接口传递给控制器。我使用Ninject注入对实现的依赖。
存储库注入有效,例如,索引操作有效且View正确显示,但是当程序到达_unitOfWork.Complete()时,什么也没有发生,并且DB也没有更新。
当我将通用存储库和工作单元注入标准非通用控制器中时,它们也可以工作。
我在做什么错了?
GenericController.cs
public class GenericController<TEntity> : Controller
where TEntity : class
{
private readonly IGenericRepository<TEntity> _repository;
private readonly IUnitOfWork _unitOfWork;
protected GenericController(IGenericRepository<TEntity> repository, IUnitOfWork unitOfWork)
{
_repository = repository;
_unitOfWork = unitOfWork;
}
// GET: FileTypes
public ActionResult Index()
{
return View(_repository.GetAll());
}
// GET: FileTypes/Create
public ActionResult Create()
{
return View();
}
// POST: FileTypes/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name")] TEntity entity)
{
if (ModelState.IsValid)
{
_repository.Add(entity);
_unitOfWork.Complete();
return RedirectToAction("Index");
}
return View(entity);
}
// GET: FileTypes/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var entity = _repository.GetById(id);
if (entity == null)
return HttpNotFound();
return View(entity);
}
// POST: FileTypes/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "Id,Name")] TEntity entity)
{
if (ModelState.IsValid)
{
_repository.Edit(entity);
_unitOfWork.Complete();
return RedirectToAction("Index");
}
return View(entity);
}
// POST: FileTypes/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = RoleName.Admin + ", " + RoleName.SuperAdmin)]
public ActionResult Delete(int id)
{
try
{
_repository.Remove(_repository.GetById(id));
_unitOfWork.Complete();
return RedirectToAction("Index");
}
catch (Exception)
{
return new HttpStatusCodeResult(500);
}
}
}
示例派生控制器:
DisengagementReasonsController.cs
[Authorize(Roles = RoleName.SuperAdmin)]
public class DisengagementReasonsController : GenericController<DisengagementReason>
{
public DisengagementReasonsController(IGenericRepository<DisengagementReason> repository, IUnitOfWork unitOfWork)
: base(repository, unitOfWork)
{
}
}
IUnitOfWork.cs
public interface IUnitOfWork
{
void Complete();
}
UnitOfWork.cs
public class UnitOfWork : IUnitOfWork
{
private readonly MyAppDbContext _context;
public UnitOfWork(MyAppDbContext context)
{
_context = context;
}
public void Complete()
{
_context.SaveChanges();
}
}
Ninject.Web.Common
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
kernel.Bind(x =>
{
x.FromThisAssembly()
.SelectAllClasses()
.BindDefaultInterface();
});
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
}
}
GenericRepository.cs
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
private readonly MyAppDbContext _context;
private readonly DbSet<TEntity> _dbSet;
public GenericRepository(MyAppDbContext context)
{
_context = context;
_dbSet = context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> GetAll()
{
return _dbSet.ToList();
}
public virtual TEntity GetById(object id)
{
return _dbSet.Find(id);
}
public virtual void Add(TEntity entity)
{
_dbSet.Add(entity);
}
public virtual void Edit(TEntity entityToUpdate)
{
_dbSet.Attach(entityToUpdate);
_context.Entry(entityToUpdate).State = EntityState.Modified;
}
public virtual void Remove(object id)
{
var entityToDelete = _dbSet.Find(id);
Remove(entityToDelete);
}
public virtual void Remove(TEntity entityToDelete)
{
if (_context.Entry(entityToDelete).State == EntityState.Detached)
{
_dbSet.Attach(entityToDelete);
}
_dbSet.Remove(entityToDelete);
}
}
答案 0 :(得分:1)
基于症状,最可能的问题原因是 DbContext 的不同实例被注入到UoW和存储库类中(可能是由于某些DI错误配置)。经过评论讨论后,结果证明我很幸运。 :)
但是,作为旁注,我要指出的是EF的DbContext本身实现了UoW和存储库。在大多数情况下,通过EF实现这些模式只是不必要的过度复杂化,是一种抽象。我不建议没有充分的理由。