通用控制器不执行UnitOfWork方法Complete()

时间:2018-09-17 19:47:33

标签: c# asp.net-mvc

在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);
    }
}

1 个答案:

答案 0 :(得分:1)

基于症状,最可能的问题原因是 DbContext 的不同实例被注入到UoW和存储库类中(可能是由于某些DI错误配置)。经过评论讨论后,结果证明我很幸运。 :)

但是,作为旁注,我要指出的是EF的DbContext本身实现了UoW和存储库。在大多数情况下,通过EF实现这些模式只是不必要的过度复杂化,是一种抽象。我不建议没有充分的理由。