Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
656 views
in Technique[技术] by (71.8m points)

c# - 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.

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.

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. We are using Linq2SQl and we have two different databases to work with based on the view.

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

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.

Any idea on how to achieve decoupling in this situation

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
 > 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

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...