Unit of work + repository + service layer with dependency injection - asp.net-mvc

I am designing a web application and a windows service and want to use the unit of work + repository layer in conjunction with a service layer, and I am having some trouble putting it all together so that the client apps control the transaction of data with the unit of work.
The unit of work has a collection of all repositories enrolled in the transaction along with commit and rollback operations
public interface IUnitOfWork : IDisposable
{
IRepository<T> Repository<T>() where T : class;
void Commit();
void Rollback();
}
The generic repository has operations that will be performed on the data layer for a particular model (table)
public interface IRepository<T> where T : class
{
IEnumerable<T> Get(Expression<Func<T, bool>> filter = null, IList<Expression<Func<T, object>>> includedProperties = null, IList<ISortCriteria<T>> sortCriterias = null);
PaginatedList<T> GetPaged(Expression<Func<T, bool>> filter = null, IList<Expression<Func<T, object>>> includedProperties = null, PagingOptions<T> pagingOptions = null);
T Find(Expression<Func<T, bool>> filter, IList<Expression<Func<T, object>>> includedProperties = null);
void Add(T t);
void Remove(T t);
void Remove(Expression<Func<T, bool>> filter);
}
The concrete implementation of the unit of work uses entity framework under the hood (DbContext) to save the changes to the database, and a new instance of the DbContext class is created per unit of work
public class UnitOfWork : IUnitOfWork
{
private IDictionary<Type, object> _repositories;
private DataContext _dbContext;
private bool _disposed;
public UnitOfWork()
{
_repositories = new Dictionary<Type, object>();
_dbContext = new DataContext();
_disposed = false;
}
The repositories in the unit of work are created upon access if they don't exist in the current unit of work instance. The repository takes the DbContext as a constructor parameter so it can effectively work in the current unit of work
public class Repository<T> : IRepository<T> where T : class
{
private readonly DataContext _dbContext;
private readonly DbSet<T> _dbSet;
#region Ctor
public Repository(DataContext dbContext)
{
_dbContext = dbContext;
_dbSet = _dbContext.Set<T>();
}
#endregion
I also have a service classes that encapsulate business workflow logic and take their dependencies in the constructor.
public class PortfolioRequestService : IPortfolioRequestService
{
private IUnitOfWork _unitOfWork;
private IPortfolioRequestFileParser _fileParser;
private IConfigurationService _configurationService;
private IDocumentStorageService _documentStorageService;
#region Private Constants
private const string PORTFOLIO_REQUEST_VALID_FILE_TYPES = "PortfolioRequestValidFileTypes";
#endregion
#region Ctors
public PortfolioRequestService(IUnitOfWork unitOfWork, IPortfolioRequestFileParser fileParser, IConfigurationService configurationService, IDocumentStorageService documentStorageService)
{
if (unitOfWork == null)
{
throw new ArgumentNullException("unitOfWork");
}
if (fileParser == null)
{
throw new ArgumentNullException("fileParser");
}
if (configurationService == null)
{
throw new ArgumentNullException("configurationService");
}
if (documentStorageService == null)
{
throw new ArgumentNullException("configurationService");
}
_unitOfWork = unitOfWork;
_fileParser = fileParser;
_configurationService = configurationService;
_documentStorageService = documentStorageService;
}
#endregion
The web application is an ASP.NET MVC app, the controller gets its dependencies injected
in the constructor as well. In this case the unit of work and service class are injected. The action performs an operation exposed by the service, such as creating a record in the repository and saving a file to a file server using a DocumentStorageService, and then the unit of work is committed in the controller action.
public class PortfolioRequestCollectionController : BaseController
{
IUnitOfWork _unitOfWork;
IPortfolioRequestService _portfolioRequestService;
IUserService _userService;
#region Ctors
public PortfolioRequestCollectionController(IUnitOfWork unitOfWork, IPortfolioRequestService portfolioRequestService, IUserService userService)
{
_unitOfWork = unitOfWork;
_portfolioRequestService = portfolioRequestService;
_userService = userService;
}
#endregion
[HttpPost]
[ValidateAntiForgeryToken]
[HasPermissionAttribute(PermissionId.ManagePortfolioRequest)]
public ActionResult Create(CreateViewModel viewModel)
{
if (ModelState.IsValid)
{
// validate file exists
if (viewModel.File != null && viewModel.File.ContentLength > 0)
{
// TODO: ggomez - also add to CreatePortfolioRequestCollection method
// see if file upload input control can be restricted to excel and csv
// add additional info below control
if (_portfolioRequestService.ValidatePortfolioRequestFileType(viewModel.File.FileName))
{
try
{
// create new PortfolioRequestCollection instance
_portfolioRequestService.CreatePortfolioRequestCollection(viewModel.File.FileName, viewModel.File.InputStream, viewModel.ReasonId, PortfolioRequestCollectionSourceId.InternalWebsiteUpload, viewModel.ReviewAllRequestsBeforeRelease, _userService.GetUserName());
_unitOfWork.Commit();
}
catch (Exception ex)
{
ModelState.AddModelError(string.Empty, ex.Message);
return View(viewModel);
}
return RedirectToAction("Index", null, null, "The portfolio construction request was successfully submitted!", null);
}
else
{
ModelState.AddModelError("File", "Only Excel and CSV formats are allowed");
}
}
else
{
ModelState.AddModelError("File", "A file with portfolio construction requests is required");
}
}
IEnumerable<PortfolioRequestCollectionReason> portfolioRequestCollectionReasons = _unitOfWork.Repository<PortfolioRequestCollectionReason>().Get();
viewModel.Init(portfolioRequestCollectionReasons);
return View(viewModel);
}
On the web application I am using Unity DI container to inject the same instance of the unit of work per http request to all callers, so the controller class gets a new instance and then the service class that uses the unit of work gets the same instance as the controller. This way the service adds some records to the repository which is enrolled in a unit of work and can be committed by the client code in the controller.
One question regarding the code and architecture described above. How can I get rid of the unit of work dependency at the service classes? Ideally I don't want the service class to have an instance of the unit of work because I don't want the service to commit the transaction, I just would like the service to have a reference to the repository it needs to work with, and let the controller (client code) commit the operation when it see fits.
On to the windows service application, I would like to be able to get a set of records with a single unit of work, say all records in pending status. Then I would like to loop through all those records and query the database to get each one individually and then check the status for each one during each loop because the status might have changed from the time I queried all to the time I want to operate on a single one. The problem I have right now is that my current architecture doesn't allow me to have multiple unit of works for the same instance of the service.
public class ProcessPortfolioRequestsJob : JobBase
{
IPortfolioRequestService _portfolioRequestService;
public ProcessPortfolioRequestsJob(IPortfolioRequestService portfolioRequestService)
{
_portfolioRequestService = portfolioRequestService;
}
The Job class above takes a service in the constructor as a dependency and again is resolved by Unity. The service instance that gets resolved and injected depends on a unit of work. I would like to perform two get operations on the service class but because I am operating under the same instance of unit of work, I can't achieve that.
For all of you gurus out there, do you have any suggestions on how I can re-architect my application, unit of work + repository + service classes to achieve the goals above?
I intended to use the unit of work + repository patterns to enable testability on my service classes, but I am open to other design patterns that will make my code maintainable and testable at the same time while keeping separation of concerns.
Update 1
Adding the DataContext class that inheris from EF's DbContext where I declared my EF DbSets and configurations.
public class DataContext : DbContext
{
public DataContext()
: base("name=ArchSample")
{
Database.SetInitializer<DataContext>(new MigrateDatabaseToLatestVersion<DataContext, Configuration>());
base.Configuration.ProxyCreationEnabled = false;
}
public DbSet<PortfolioRequestCollection> PortfolioRequestCollections { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.Add(new PortfolioRequestCollectionConfiguration());
base.OnModelCreating(modelBuilder);
}
}

If your purpose for using Unit of Work (UoW) was for testability, you took the wrong path. Unit of work does nothing for testability. Its main purposes is to provide atomic transactions to disparate data sources, provide UoW functionality to a data layer that doesn't already provide it, or to wrap an existing UoW in a way that makes it more easily replaceable... something which you've nullified by using the generic repository (this tightly couples it to Entity Framework anyways).
I suggest you get rid of the Unit of Work completely. Entity Framework is already a UoW. Even Microsoft has changed their mind and no longer recommend UoW with EF.
So, if you get rid of UoW, then you can just use repositories to wrap your EF queries. I don't suggest using a generic repository, as this leaks your data layer implementation all over your code (something your UoW was already doing), but rather create Concrete repoTsitories (these can use generic repositories internally if you like, but the generic repository should not leak outside of your repository).
This means your service layer takes the specific concrete repository it needs. For instance, IPortfolioRepository. Then you have a PortfolioRepository class that inherits from IPortfolioRepository which takes your EF DbContext as a parameter that gets injected by your Depndency Injection (DI) framework. If you configure your DI container to instance your EF context on a "PerRequest" basis, then you can pass the same instance to all your repositories. You can have a Commit method on your repository that calls SavesChanges, but it will save changes to all changes, not just to that repository.
As far as Testability goes, you have two choices. You can either mock the concrete repositories, or you can use the built-in mocking capabilities of EF6.

I have been through that hell hole myself and here's what I have done:
Ditch the UoW completely. EF's DBContext is a UoW basically. No point in re-inventing the wheel.
Per MSDN:
DbContext Class
Represents a combination of the Unit-Of-Work and Repository patterns
and enables you to query a database and group together changes that
will then be written back to the store as a unit.
Service layer + Repo layer seemed like a good choice. However, repos are always a leaky abstraction and espcially when DBContext's DbSet are the equivalent of repositories.
Then when the need for a Windows service arises, things become muddied further with another layer now. Throw async or background processing in the mix, and things quickly start leaking.
If you ask my 2 cents, I would say go with the service layer + EF, one wrapping business logic, the other one wrapping UOW/Repository pattern.
Alternatively, and for Windows Services especially, I'm finding that moving to a command-query based approach works better.
Not only it helps testability, it also helps in asynchronous tasks where I don't have to worry about keeping the DBContext alive even after the request has ended (DBContext is now tied with the command handler and stays alive as long as the async command stays alive).
Now if you've recently ended up digesting all those facts about UOW/Repository pattern, then surely, just even reading about Command-Query pattern will make your mind hurt. I have been down that path but trust me, its worth the time to at least look into it and giving it a try.
These posts may help:
Meanwhile... on the query side of my architecture
Meanwhile... on the command side of my architecture
If you're brave enough (after digesting thru CQRS), then take a look at MediatR which implements the Mediator pattern (which basically wraps up command-query with notifications) and allows to work via pub-sub. The pub-sub model suits nicely in the Windows Service and services layer.

Related

Injecting Different Implementations of Same Interface in ASP.NET 5

In ASP.NET 5, I have an IRepository interface that I used to access some databases, like this:
public interface IRepository {
IQueryable<T> QueryItems(string sql);
}
public class Repository : IRepository {
private readonly string ConnectionString;
public Repository(string connStr) {
// Save the injected connection string
this.ConnectionString = connStr;
}
public IQueryable<T> QueryItems(string sql) {
// Implementation ignored here
}
}
In my Startup.cs class, I am registering the IoC/DI like this:
services.AddTransient<IRepository>(s => new Repository("DUMMY_CONNSTR"));
That all works fine if I only have one connection string. However, how can I register and subsequently inject the correct IRepository if I use the Repository to connect to 2+ different databases with different connection strings?
services.AddTransient<IRepository>(s => new Repository("DUMMY_CONNSTR"));
services.AddTransient<IRepository>(s => new Repository("DIFFERENT_CONNSTR"));
In older IoC/DI systems, I would have use "named" implementations that could be resolved with something like a [Dependency("DUMMY")] attribute on the constructor parameter.
Any help would be appreciated.
There are a few approach that you can take one is to inject a factory and base on the specific criteria you can produce a repository, the other approach is use a Dispatcher that also produce the repository base on the criteria, below is a question that I ask with the same problem. The question below have both approach but they were codding a beta version of .net core
See this question for reference and code
You can substitute StructureMap or Autofac for the default DI container (see my blog post for detailed instructions). Both support "named" interface registration (StructureMap named instances and Autofac named and keyed services).
Additionally, if you target dnx451, you can use Autofac's WithKey attribute. Using the Visual Studio sample project from the blog post, add the following dependency in project.json:
"frameworks": {
"dnx451": {
"dependencies": {
"Autofac.Extras.AttributeMetadata": "4.0.0"
}
}
},
Given a test class with the following constructor:
public MyClass([WithKey("logging")] IRepository repository)
{
Repository = repository;
}
you would register everything in ConfigureServices (note the use of WithAttributeFilter():
containerBuilder.Register(c => new Repository("DEFAULT_CONNSTR")).Keyed<IRepository>("default");
containerBuilder.Register(c => new Repository("LOGGING_CONNSTR")).Keyed<IRepository>("logging");
containerBuilder.RegisterType<MyClass>().WithAttributeFilter();

Identity 2.0.0 in MVC5 architecture advice

I'm trying to integrate the recently released ASP.NET Identity 2.0.0 into a 3-layer MVC application. I'm not sure I'm going in the correct direction. I can see two approaches to take.
In the first approach, I've gone with integrating Identity into each logical layer. Having some technical issues integrating but still developing.
In the second approach, go with a a self-contained encapsulated assembly dedicated for security.
I've gone with approach 1 at the moment, but questioning it all. Also, any other approaches to take?
Approach 1
Web
Startup.cs
/App_Start/Startup.Auth
/Controllers/Account
/Controllers/Manage
/Controllers/RolesAdmin
/Controllers/UserAdmin
/ViewModels
/Views
Business Logic
/Service/AccountService
/Service/ApplicationRoleManager
/Service/ApplicationUserManager
/Service/EmailService
/Service/SmsService
/Service/SignInHelper
Data
ApplicationDbContext
ApplicationUser
So, I've simply taken Identity and plugged it into each layer I see that fits.
I've put most of the log in the Business Logic layer, as it doesn't belong in the Web and there no 'real' database code for it to belong in the Data layer.
Side-issue: I'm a bit uncomfortable that in the Web/App_Start/Startup.Auth, I have to instantiate the Busness Logic object to call
app.CreatePerOwinContext(ApplicationDbContext.Create);
in the Data layer. I've yet to think about this more. This is another issue (but I see it is related to the architecture I've chosen).
Approach 2
Creating an assembly purely for Security which contains no layers, i.e. simply plug in Identity 2.0.0 into this one assembly. And my application can reference this. It goes against the layers though. But it encapsulates security. Given security objects can (or should) be resident throughout the application lifetime, this doesn't seem like a bad idea at all. Haven't thought about about scalability though.
I have taken approach 1, and when creating the context I have a helper class that I attempt to get the context from HttpContext.Current.["DbActiveContext"] and use it if it exists, if not create then new one, and use a single context for the entire application. So you do not end up with one context for aspnet idenity and another one for the rest of the app. It looks like you are trying to use a repository pattern in the first approach, if that is the case, then your model for your identity should be in the DB layer, and for full repository pattern, you should be using dependency injection when creating your objects, by doing so, you will not have a dependency until the object is created at run time.
namespace Data.Common
{
public class ConnectionHelper : IConnectionHelper
{
private ApplicationDbContext _context;
public ApplicationDbContext Context
{
get
{
if (_context == null && HttpContext.Current.Items["DbActiveContext"] != null)
{
_context = (ApplicationDbContext)HttpContext.Current.Items["DbActiveContext"];
}
else if (_context == null && HttpContext.Current.Items["DbActiveContext"] == null)
{
_context = new ApplicationDbContext();
HttpContext.Current.Items.Add("DbActiveContext", _context);
}
return _context;
}
set { _context = value; }
}
}
}
Also if you want to use the usermanager in the service layer with DI you can do something like:
public UserController()
: this(
new ApplicationUserManager(new UserStore<ApplicationUser>(new ConnectionHelper().Context)),
new UserService())
{
}
With the UserService signature like:
public class UserService
{
private readonly IRepository<ApplicationUser> _user;
private readonly UserManager<ApplicationUser> _userManager;
public UserService(IRepository<ApplicationUser> user,
UserManager<ApplicationUser> userManager)
{
_user = user;
_userManager = userManager;
}
public UserService()
: this(
new Repository<ApplicationUser>(new ConnectionHelper()),
new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ConnectionHelper().Context)))
{
}
I hope this helps you!

MVC3 tool using Entity Framework caching issues with Ninject

I've got a new MVC 3 application which is showing some issues when modifying data manually in the Database.
The tool is still in development and once in a while I want to change my user's teamId. When I do so, I have to kill the Web development Server and run it again otherwise the queries don't pick the new teamId.
Same thing when I publish the tool to IIS, if I ever modify something on the database, I need to either copy over the 'bin' folder again or stop the application and re-run it.
When I modify data from the application itself, I have no problems.
This is how my Ninject looks like:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel kernel = new StandardKernel(new TrackerServices());
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return null;
return (IController)kernel.Get(controllerType);
}
private class TrackerServices : NinjectModule
{
public override void Load()
{
var context = new TrackerEntities();
Bind<IUserRepository>().To<UserRepository>().WithConstructorArgument("context", context);
}
}
}
My Interface:
public interface IUserRepository : IRepository<User>
{
User GetByName(string name);
}
my Implementation:
public User GetByName(string login)
{
var userLogin = _misc.GetUsername(login);
return _context.Users.Where(x => x.Login == userLogin).Single();
}
And my Index Action
public ActionResult Index()
{
var teamid = (int)_users.GetByName("myName").TeamId;
This has never happened before, but this tool is the first one I'm using with Ninject. I'm wondering if there's a relation between my problem and using a repository?
There are two issues that are combining to create this problem:
The way you've created your context is causing it to effectively be a singleton.
Entity Framework will not automatically check for a new version of an entity which the context is already tracking.
To solve this, I would recommend that you recreate your repository once per request (there won't be a significant performance hit for this, as it's fairly lightweight), by using this binding:
Bind<IUserRepository>().To<UserRepository>().InRequestScope();
Ninject should be able to create your TrackerEntities context automatically, but if not (or if you want to make it clear), you can use the following binding:
Bind<TrackerEntities>().ToSelf().InRequestScope(); (The InRequestScope is not really required here, as the default transient scope should be okay).
You could also go down the road of forcing a refresh of the entity (using ObjectContext.Refresh()), but that's probably not a great idea because you'd have to do it explicitly for each entity.

What is the scope of my Ninject injected ObjectContext in my custom MembershipProvider (using Request scope)?

I use Entity Framework 4 and ASP.NET MVC 3. I made a custom membership provider and use Ninject to inject an EFAccountRepository into it (Bound IAccountRepository to EFAccountRepository).
This account repository has an ObjectContext injected into it. I also use this repository (and others) in my controllers. For this reason when I bound IContext to my ObjectContext, I set the scope to "per request" so the ObjectContext only lives in one request and is shared between the repositories.
I am sometimes get the following error when trying to log in:"The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."
I wonder how often the membership provider gets instantiated. I injected the repository into the membership provider by marking the repository property with [Inject] and calling Kernel.Inject in the Application_Start function in the global.asax file.
If the provider gets instantiated more than once I would have to inject again I suppose. However, I don't get a null pointer exception, so I don't think that's it.
Update 1
Here's some code:
MyNinjectModule.cs
public override void Load()
{
Bind<IMyContext>().To<MyObjectContext>().InRequestScope();
// put bindings here
Bind<IAccountRepository>().To<EFAccountRepository>
}
Global.asax
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
var kernel = new StandardKernel(new MyNinjectModule());
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(kernel));
kernel.Inject(Membership.Provider);
}
MyMembershipProvider.cs
[Inject]
public IAccountRepository accountRepository { get; set; }
public override bool ValidateUser(string username, string password)
{
// I get the exception here.
return (from a in accountRepository.Accounts
where a.UserName == username
&& a.Password == password
select true).SingleOrDefault();
}
EFAccountRepository.cs
private readonly IMyContext context;
public EFAccountRepository(IMyContext context)
{
this.context = context;
}
public IQueryable<Account> Accounts
{
get { return context.Accounts; }
}
MyObjectContext.cs
public class MyObjectContext : ObjectContext, IMyContext
{
public IObjectSet<Account> Accounts { get; private set; }
public FlorenceObjectContext()
: this("name=DomainModelContainer")
{
}
public FlorenceObjectContext(string connectionString)
: base(connectionString, "DomainModelContainer")
{
Accounts = CreateObjectSet<Account>();
}
}
PS: I'm always open to comments on my code in general ;).
The exception says that you are incorrectly handling disposing of your context. Somewhere you call context.Dispose (or have context in using) but after that you want to use context again which is not possible because context is already disposed. If you are using per request context you must dispose context only once at the end of request processing (when you are sure that no code will use the context).
You didn't specify a scope for your EFAccountRepository binding so it defaults to .InTransientScope(). This means a new instance of the object will be created each time you resolve the IAccountRepository [refer to https://github.com/ninject/ninject/wiki/Object-Scopes ].
Also, transient scope objects
are automatically garbage collected as soon as there are no references to them [Ninject doesn't cache them]
are not automatically disposed by anyone
In contrast, you bound MyObjectContext to IObjectContext .InRequestScope(). This means it will be reused when you are in the same HTTP request handling operation.
Also, a request scope object
won't be garbage collected until your http request is done
might be automatically disposed once the HTTP request is done, if it's IDisposable. [Not sure precisely when, but from other questions I have seen I suspect it depends on the version of Ninject]
Now, ObjectContext is IDisposable, so it seems reasonable to conclude that
an object reference to the IObjectContext exists, and you are using the IObjectContext outside of the HTTP request which it was created in.
Ninject has automatically disposed of it, since the HTTP request has completed.
In order to solve the issue, you need to figure out why your object context object reference is surviving so long, and consider either eliminating the long-livedness... or removing its dependency on short-lived (request-scoped) objects.
[note clearly the question already has an accepted answer, but I think the accepted answer was kind of hard to understand.]

Multiple IUnitOfWork implementations in single ASP.NET MVC project

We have a site using Unity and IUnitOfWork for our EF context. Until now we've only been using a single EF Context so this is the one mapped in Unity config. This has all been handled through constructor injection and this is something we'd like to maintain for consistency.
We've now introduced another EF Context for our PaymentController that is used within the site but Unity config currently only allows us to create one type for IUnitOfWork.
I know that I can create a new <register/> element for the new context with a distinct name attribute but how do I implement this within the controller constructor to use the one named payments?
<register type="IUnitOfWork" mapTo="FirstContext" />
<register type="IUnitOfWork" mapTo="PaymentsContext" name="payments"/>
public class PaymentController()
{
public PaymentController(IUnitOfWork unitOfWork)
{
//How to I tell unity that this needs to be a payments
_unitOfWork = unitOfWork;
}
}
Many Thanks
When the FirstContext and PaymentsContext have each an unique set of entities (for instance, each connect to a different database) it is worth wild to explicitly define this in code. One way of doing this is by specifying a factory for each unit of work:
public interface IFirstContextFactory
{
IUnitOfWork CreateNew();
}
public interface IPaymentContextFactory
{
IUnitOfWork CreateNew();
}
public class PaymentController()
{
public PaymentController(PaymentContextFactory paymentContextFactory)
{
//How to I tell unity that this needs to be a payments
this.paymentContextFactory = paymentContextFactory;
}
public void DoSomething()
{
using (var context = this.paymentContextFactory.CreateNew())
{
// Do something useful
context.Commit();
}
}
}
Not only makes this your dependencies very clear (because you know what type of context the code is dealing with), but it also simplifies the DI configuration, because you won't need any named registrations.

Resources