简体   繁体   English

依赖注入

[英]Dependency Injection

We are builing a windows desktop application (not web based) and trying to come up with the best way to implement Repository and UnitOfWork Pattern. 我们正在构建一个Windows桌面应用程序(不是基于Web的),并尝试提出实现Repository和UnitOfWork Pattern的最佳方法。

In a typical Asp.Net Mvc application your repositories are injected with data context, services are injected with repositories and finally controllers are injected with services and all is well if you don't hit any exception, you will commit the changes. 在典型的Asp.Net Mvc应用程序中,您的存储库注入数据上下文,服务注入存储库,最后控制器注入服务,如果您没有遇到任何异常,一切都很好,您将提交更改。

In windows forms/wpf applications it is not advisable to use single datacontext ( Oren has a post on this on MSDN) so we have decided to create data context at the presenter. 在Windows窗体/ wpf应用程序中,建议不要使用单个datacontext( Oren在MSDN上有一个帖子),所以我们决定在演示者处创建数据上下文。 We are using Linq2SQl and we have two different databases to work with based on the view. 我们正在使用Linq2SQl,我们有两个不同的数据库可以根据视图使用。

Currently I have the following implementation 目前我有以下实施方案

public interface IRepository<T> where T : class
    {
        IEnumerable<T> Find(Expression<Func<T, bool>> where);
        T Single(Expression<Func<T, bool>> where);
        ...
     }

public class Repository<T> : IRepository<T> where T : class
    {
        private readonly Table<T> _table;

        public Repository(DataContext dataContext)
        {
            _table = dataContext.GetTable<T>();
        }
   }

public Class TodoService :ITodoService
{
       IRepository<Todo> _todoRepository;
       public TodoService(DataContext dataContext)
       {
           _todoRepository = new Repository<Todo>(dataContext)
       }
       ...
}

} }

// Presenter for the UI // UI的演示者

public class TodoPresenter
{
    public void Save()
    {
       Using (DataContext dataContext = DataContextFactory.GetNewContextForDatabase1())
       {
           ITodoService service = new TodoService(dataContext);
            ...
           service.Save(..);
           dataContext.SubmitChanges();           
       }
    }

} }

I would like decouple the presenter from service and would like to inject TodoService when ITodoService is requested, but I cannot inject data context for two reasons, as I have to decide based on the database or can't even maintain a data context at the application level even if we have only one database being a windows application (many views are open at a time as tabs in the app) and with no data context I cannot create Repository classes and can't inject services. 我想将presenter与服务分离,并希望在请求ITodoService时注入TodoService,但我无法注入数据上下文有两个原因,因为我必须根据数据库做出决定,或者甚至无法在应用程序中维护数据上下文即使我们只有一个数据库是一个Windows应用程序(许多视图一次打开作为应用程序中的选项卡)并且没有数据上下文我无法创建存储库类并且无法注入服务。

Any idea on how to achieve decoupling in this situation 关于如何在这种情况下实现解耦的任何想法

 > I cannot inject data context

but maybe you can inject a factory method that creates the context and the service 但也许您可以注入一个创建上下文和服务的工厂方法

public class TodoPresenter
{
    private Func<DataContext> dataContextFactory;
    private Func<DataContext, ITodoService> serviceFactory;

    // created with new TodoPresenter(DataContextFactory.GetNewContextForDatabase1(), 
    //                   dc => new TodoService(dc, 
    //                              new ToDoRepository(dc => new ToDoRepository(dc))));
    public TodoPresenter(Func<DataContext> dataContextFactory, 
                         Func<DataContext, ITodoService> serviceFactory)
    {
        this.dataContextFactory = dataContextFactory;
        this.serviceFactory = serviceFactory;
    }

    public void Save()
    {
        using (DataContext dataContext = this.dataContextFactory())
        {
            ITodoService service = serviceFactory(dataContext);
            // ...
            //service.Save(..);
            //dataContext.SubmitChanges();           
        }

    }
}

Update 更新

The Service needs a factory to get the repository as well 该服务还需要工厂来获取存储库

public TodoService(DataContext dataContext, 
         Func<DataContext, IRepository<Todo> todoRepository){...}

An integrationtest with Service and presenter looks like this 与Service和演示者的集成测试看起来像这样

  var toDoRepository = new Mock<..>(..);
  var datacontext= new Mock<..>(..);
  var presenter = new TodoPresenter(dc => datacontext, 
                  dc => new TodoService(dc, dc2 => toDoRepository ));

An unitest for presenter starts like this 对于主持人来说,这是一个不合时宜的人

  var TodoService= new Mock<..>(..);
  var datacontext= new Mock<..>(..);
  var presenter = new TodoPresenter(dc => datacontext, 
                  dc => TodoService);

I would wrap the datacontext inside a UnitOfWork. 我将datacontext包装在UnitOfWork中。 And create a unitofwork either per call/session. 并且每个呼叫/会话创建一个单元。

have you tried to create the datacontext in the todoservice? 你试过在todoservice中创建datacontext吗?

public interface IRepository<T> where T : class
{
    IEnumerable<T> Find(Expression<Func<T, bool>> where);
    T Single(Expression<Func<T, bool>> where);
    void Save(T item);
    void SubmitChanges();
}

public class Repository<T> : IRepository<T> where T : class
{
    public void Save(T item)
    {
    }

    public void SubmitChanges()
    {
    }
}

// TodoService will have its local datacontext // TodoService将拥有其本地datacontext

public class TodoService :IDisposable
{
   DataContext dataContext;
   IRepository<Todo> _todoRepository;
   public TodoService()
   {
       dataContext = DataContextFactory.GetNewContextForDatabase1();
       _todoRepository = new Repository<Todo>(dataContext);
   }

   public void Dispose()
   {
       dataContext.Dispose();
   }

   void Save(Todo item)
   {
       _todoRepository.Save(item);
   }

   void SubmitChanges()
   {
       _todoRepository.SubmitChanges();
   }
}

// presenter // 主持人

class TodoPresenter
{
    public void Save()
    {
       using (TodoService service = new TodoService())
       {
           Todo item = null;
           // ...
           service.Save(item);
           service.SubmitChanges();           
       }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM