在Web Api中实现UnitOfWork 2

时间:2017-07-20 13:10:23

标签: c# asp.net-web-api2

我有基本的 Web Api 2 应用程序,其中包含业务逻辑和数据层。 UnitOfWork 封装 DBContext

我的UnitOfWok:

public class UnitOfWork : IUnitOfWork
{
    public KnowBaseDBContext context { get; set; } = new KnowBaseDBContext();

    public int Save()
    {
        var res = context.SaveChanges();

        return res;
    }

    public void AttachToContext<T>(T obj) where T : class
    {
        var dbset = context.Set<T>();

        dbset.Attach(obj);
    }
    // dispose()
}

我还使用 Unity容器 Unity容器 config 实现了依赖注入 的UnitOfWork

        container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager(),
                                                        new InjectionConstructor());

我想要做的是在 ActionFilter.OnActionExecuted 中调用 UnitOfWork.Save()

public sealed class CommitOnSuccess : System.Web.Http.Filters.ActionFilterAttribute
{
    private IUnitOfWork unitOfWork { get; set; }

    public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
    {    
        if (actionExecutedContext.Exception == null)
        {
            unitOfWork = UnityConfig.GetConfiguredContainer().Resolve<IUnitOfWork>();

            unitOfWork.Save();
        }

        base.OnActionExecuted(actionExecutedContext);
    }
}

但是从我看到的 Unity容器 Action context 中工作(不知道它是如何工作的)所以我无法在 ActionFilter 中获得适当的上下文,因此无法在我的数据库中保存更改。如何以正确的方式 SaveChanges

我如何使用 UbitOfWork (不用担心,会受到反对):

private void UpdateSecondarySkills(Vacancy v, ICollection<int> skills)
{
    var old_secondary_skills = v.TechSkills;
    var ids = old_secondary_skills.Select(c => c.Id).ToList();
    foreach (var skill in old_secondary_skills.ToList())
    {
        if (!skills.Contains(skill.Id))
        {
            v.TechSkills.Remove(skill);
        }
    }
    if (v != null)
    {
        foreach (var skill in skills)
        {
            if (!ids.Contains(skill))
            {
                var existing_skill = new TechSkill { Id = skill };
                unitOfWork.AttachToContext<TechSkill>(existing_skill);
                v.TechSkills.Add(existing_skill);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

修改你的global.asax

添加这些事件处理程序

    protected void Application_BeginRequest() { CurrentContext = new YourDbcontext; }

    protected void Application_EndRequest()
    {
        if (CurrentContext != null)
            CurrentContext .Dispose();
    }

将此属性添加到global.asax

    private const string ContextKey = "current.session";

    public static YourDbContext CurrentContext
    {
        get { return (ISession) HttpContext.Current.Items[ContextKey]; }
        private set { HttpContext.Current.Items[ContextKey] = value; }
    }

现在,您需要设置容器以在解析上下文时调用CurrentContext属性。我不知道Unity是如何做到的。我使用Castle Windsor,你就这样注册了

        container
            .Register(Component.For<DbContext>().UsingFactoryMethod(() => MvcApplication.CurrentContext)
                .LifeStyle
                .PerWebRequest);

您可以这样做

        container.Register(Classes.FromAssemblyContaining<YourDbContext>()
            .BasedOn<DbContext>()
                .LifeStyle
                .PerWebRequest);

但我没试过。

然后只要您通过容器解析ApiControllers,只需在构造函数中传递YouDbContext。

现在,您应该根据每个Web请求按用户解析上下文。

答案 1 :(得分:0)

您是否在项目内的任何位置UnitOfWork使用了DBContext上的数据库内容。如果不是UnitOfWork可能有另一个DBContext,那么它看不到任何更改,因此它不会保存任何

也许你需要看看这个thread