Dependency injection when using UnitOfWork pattern - inversion-of-control

I'm trying to get my head around an existing system that is built upon the UnitOfWork pattern. There are a lot of repositories that all takes an IUnitOfWork in its constructor, so that the service layers can perform multiple repository calls and then choose when to commit the changes.
The current service code may look something like this:
using (var uow = UnitOfWork.Start())
{
var orderRepository = new OrderRepository(uow);
var productRepository = new ProductRepository(uow);
orderRepository.DoSomething();
productRepository.DoSomethingElse();
uow.Persist();
}
How can I introduce true dependency injection in the service layer and still keep the UnitOfWork pattern?

I would use factory pattern. Inject factory in constructor and rewrite:
using (var uow = this.unitOfWorkFactory.Create().Start())
{
var orderRepository = new OrderRepository(uow);
var productRepository = new ProductRepository(uow);
orderRepository.DoSomething();
productRepository.DoSomethingElse();
uow.Persist();
}
Best regards

Related

Template10 MVVM IoC Inject ViewModel into Shell View

I'm looking for the best way to inject a ViewModel into a Shell view.
I'm using Autofac (but I can adopt code from other IoC containers if sample is available). I have got the other VMs injecting correctly - but the method that resolves the VM using ResoleForPage method of the App class.
I'm fairly new to UWP developement and any help is greatly appreciated!
Passing a ViewModel to the Shell is indeed simpler than passing it to the other pages, because the Shell is the only page that is created explicitly by us: so, it should be enough to add a parameter to the constructor of the Shell of type ShellViewModel:
public Shell()
{
Instance = this;
this.InitializeComponent();
}
public Shell(INavigationService navService, ShellViewModel model) : this()
{
navigationMenu.NavigationService = navService;
navigationMenu.RefreshStyles(App.Current.RequestedTheme, true);
this.DataContext = model;
}
then expose the DataContext in a strongly typed way, as with any other pages (useful mainly if you use x:Bind bindings in xaml):
public ShellViewModel ViewModel => DataContext as ShellViewModel;
And now you just have to pass an instance of your ViewModel class, pulling it from your IoC container, when you create the Shell. In the latest Template 10 template for VS2017, it should be in the CreateRootElement method of the App class:
public override UIElement CreateRootElement(IActivatedEventArgs e)
{
var service = NavigationServiceFactory(BackButton.Attach, ExistingContent.Include);
return new Template10.Controls.ModalDialog
{
DisableBackButtonWhenModal = true,
Content = new Shell(service, new ShellViewModel()),
};
}
of course replacing new ShellViewModel() with the code to pull it from Autofac.

How to structure a service that needs multiple repositories?

I have a Service that uses 2 repositories and I wanna make unit tests. So for testing I need to have the constructor take interfaces instead of the repository class directly, so I can mock the repositories. But then I can't set their DbContext to the same which will lead to other problems.
Here's the code:
public class RolePrivilegeService : IRolePrivilegeService
{
private readonly RoleReadWriteRepository _roleRepo;
private readonly PrivilegeReadRepository _privilegeRead;
public RolePrivilegeService(RoleReadWriteRepository roleWrite,
PrivilegeReadRepository privilegeRead)
{
_roleRepo = roleWrite;
_privilegeRead = privilegeRead;
_roleRepo.Db = _privilegeRead.Db;
}
public async Task<int> AssignPrivilege(string roleId, string privilegeId, string companyId)
{
var role = await _roleRepo.FindRole(companyId, roleId);
if(role == null) throw new RoleNotFoundException();
var privilege = await _privilegeRead.Find(privilegeId);
if(privilege == null) throw new PrivilegeNotFoundException();
role.AssignPrivilege(privilege);
return await _roleRepo.UpdateRole(role);
}
}
The interfaces and entities are in one project and the service and repositories are in another project.
I guess from the beginning it's not the best solution to give to the service the responsibility to manage the unicity of the context.
Some possible solution (my favorite is the third one)
1) Use interfaces instead and inject DBContext (Define your strategy here, one DBContext by request if you are in api or whatever...)
2) You can anyway mock a concrete class with NSubstitute or others
3) Improve your design with having one Repository to have a better abstraction of the needed entity (Using an aggregate which is a better abstraction of your transactional boundaries)

Unit testing With Entity Framework 7, Test fails sometimes?

I have a bunch of test where I use the new UseInMemory function in EF7. When I run them all some of them fail. When I run them single they all pass.
My best guess it is a conflict in EF7 because of the fact that every test runs in its own thread and they all kind of using the same DbContext class.
Here one of my Tests:
[Fact]
public void Index()
{
DbContextOptionsBuilder<DatabaseContext> optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
optionsBuilder.UseInMemoryDatabase();
db = new DatabaseContext(optionsBuilder.Options);
AdminController controller = new AdminController(db);
var result = controller.Index() as ViewResult;
Assert.Equal("Index", result.ViewName);
}
I remake the dbContext object in every test but it seem not to make any different.
Would be greatful for any input. Thanks :)
The problem is, that the memory storage in InMemoryDatabase is registered as Singleton so you actually share the data between DbContexts even you think you don't.
You have to create your DbContexts like this:
public abstract class UnitTestsBase
{
protected static T GetNewDbContext<T>() where T : DbContext
{
var services = new ServiceCollection();
services
.AddEntityFramework()
.AddInMemoryDatabase()
.AddDbContext<T>(options => options.UseInMemoryDatabase());
var serviceProvider = services.BuildServiceProvider();
var dbContext = serviceProvider.GetRequiredService<T>();
dbContext.Database.EnsureDeleted();
return dbContext;
}
}
var newTestDbContext = GetNewDbContext<TestDbContext>()
I also was led to beleive that .UseInMemoryDatabase() has no persistence, but that does not seem to be the case (at least with the latest versions)!
As noted in How can I reset an EF7 InMemory provider between unit tests? you want to do a db.Database.EnsureDeleted() BUT I also noticed that this does NOT reset auto increment ids.

Where to define the repository?

I am learning EF4.1 in conjunction with MVVM and in one of these tutorials they create a MainWindowViewModel with a Repository object that they use in calling another view model (EmployeeListViewModel). Here is the code:
public MainWindowViewModel()
{
IObjectContextAdapter adapter = ((IObjectContextAdapter)new SidekickEntities());
_vmRepository = new GenericRepository(adapter.ObjectContext);
EmployeeListViewModel viewModel = new EmployeeListViewModel(_vmRepository);
this.ViewModels.Add(viewModel);
}
public EmployeeListViewModel(GenericRepository repository)
{
if (repository == null)
{
throw new ArgumentNullException("repository");
}
_employeeRepository = repository;
this.AllEmployees = new ObservableCollection<Employee>(_employeeRepository.GetAll<Employee>());
}
What I am wondering is, why is the repository created in the MainWindowViewModel and then passed into EmployeeListViewModel? Why not just create the repository in EmployeeListViewModel like this:
public MainWindowViewModel()
{
EmployeeListViewModel viewModel = new EmployeeListViewModel();
this.ViewModels.Add(viewModel);
}
public EmployeeListViewModel()
{
IObjectContextAdapter adapter = ((IObjectContextAdapter)new SidekickEntities());
_employeeRepository = new GenericRepository(adapter.ObjectContext);
this.AllEmployees = new ObservableCollection<Employee>(_employeeRepository.GetAll<Employee>());
}
I am pretty new to EF but it seems a little cleaner to create a repository in each separate ViewModel. Wouldn't the repository then be cleaned up when the ViewModel in question is no longer used instead of keeping it around until the closing of MainWindowViewModel or does this create too many repository instances?
The problem you will run into when using a separate Context for each ViewModel is that entities that have links to each other come from different contexts so you will have to manually work this out when trying to update something (see Attaching and Detaching Objects)
This has to do with a pattern called Unit Of Work.
UoW helps you with encapsulating functions that should work together. In your case the ObjectContext implements the UoW pattern and is passed to the repository in the constructor.
You should share your ObjectContext between functions that work together and should be seen as one Unit Of Work.

How to configure MvcMiniProfiler to use Entity Framework with a Domain layout

I would use MVCMiniProfiler with Entity Framework, I saw that I could configure like this to get the object context :
var connectionString = ConfigurationManager.ConnectionStrings["MyDBEntities"].ConnectionString;
var entityConnStr = new EntityConnectionStringBuilder(connectionString);
var connection = new SqlConnection(entityConnStr.ProviderConnectionString);
var profiledConnection = ProfiledDbConnection.Get(connection, MiniProfiler.Current);
var objectContext = ObjectContextUtils.CreateObjectContext<MyModel>(profiledConnection);
The problem is that I have a my domain model in another project of the solution and I can't use this method. I also use dependency injection for my repository:
public MyController(IEntities repository)
{
_repository = repository;
}
I am looking for a way to configure MvcMiniProfiler.