I want to use EF 5 model validation to avoid duplicate values in the database, so I'm using a model class like this:
[Table("MeasureUnits")]
public class MeasureUnit : IValidatableObject
{
public int MeasureUnitId { get; set; }
public string Symbol { get; set; }
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
using (MeasureUnitRepository rep = new MeasureUnitRepository())
{
MeasureUnit measureUnit = rep.FindDuplicateBySymbol(this);
if (measureUnit != null)
yield return new ValidationResult(
"There is another unit with this symbol, you can't duplicate it",
new[] { "Symbol" });
}
}
The repository class creates the DbContext, implements IDisposable, has the logic to find the duplicate and it all works just as intended.
However, using the debugger I realized the validation is performed twice for every insert or update, so the repository (and DbContext) gets instantiated and disposed twice also.
Besides that, there is another DbContext living in the controller but just don't find the way to use it inside the model class, other than including the DbContext in the model's constructor, but I feel it's not the right solution.
Is there a better o "right" way to achieve this validation?
Thanks in advance.
When you have to go to the database then you need to use DbContext and DbContext has an Overridable method called ValidateEntity. See this article: Entity Framework Validation.
I put the code I use in another answer here
And more about how I've structured the validation in MVC here.
Also, instantiating a context inside your repository is likely to cause you grief. The repositories will need to share a context. You could treat the context as your unit of work and pass it into the repository in the constructor, or you could wrap the context in your own unit of work and pass that in.
You can use any IOC container available out there like Unity, Ninject, Autofac or StructureMap to inject your repository as a dependency.
This way you would be able to access the same object in the controller, your Validate method or wherever you need to use it.
Some of these IOC(Ninject for sure - look for 'request scope') containers are capable of integrating with ASP.NET MVC so that the dependency(your repository in that case) is created once per request and disposed when the request ends.
Example using Ninject:
You create a globally accessible(the design is up to you) ninject kernel
public static class NinjectKernel
{
public static IKernel Kernel = new StandardKernel();
static NinjectKernel()
{
Kernel.Bind<IMyRepository>().To<MyRepositoryImpl>().InRequestScope();
}
}
and a controller factory for MVC controllers
public class NinjectControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext,
Type controllerType)
{
return controllerType == null ? null : (IController)NinjectKernel.Kernel.Get(controllerType);
}
}
You can then set your controller factory in Global.asax like this
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
and get the repository in your Validate method in a similar way it's done in the Controller factory.
Related
I'm working on a classic .Net Framework Web API solution.
I have 3 layers. Let's call them
MVC - with POST, GET, UPDATE, DELETE controllers.
BIZZ - for business with my service class. My service class are king of repositories with CREATE, READ, UPDATE, DELETE and specific methods.
DATA - with POCO and definition of DB context.
I will not develop the EF layer. It is a classic Entity Framework project with POCO.Here is a sample of a Service and with BaseService class
public abstract class Service : IDisposable
{
protected DbContext dbContext = new DbContext();
public void Dispose()
{
dbContext.Dispose();
}
}
Then I have a cart service and a order service. They are similar in their structure so I will only write the code useful for this example.
public class CartService : Service
{
public Cart Create(Cart cart)
{
// Create the cart
}
public Cart Read(Guid id)
{
// Read
}
public Cart Update(Cart cart)
{
// I do some check first then
}
public void Delete(Cart cart)
{
// Delete
}
public void Checkout(Cart cart)
{
// Validation of cart removed in this example
dbContext.Cart.Attach(cart);
cart.DateCheckout = DateTime.UtcNow;
dbContext.Entry(cart).State = EntityState.Modified; // I think this line can be removed
dbContext.SaveChanges();
using (var orderService = new OrderService())
{
foreach (var order in cart.Orders)
{
order.DateCheckout = cart.DateCheckout;
order.Status = OrderStatus.PD; // pending
orderService.Update(order);
}
}
}
}
public class OrderService : Service
{
public Cart Create(Cart cart)
{
// Create the cart
}
public Cart Read(Guid id)
{
// Read
}
public Cart Update(Cart cart)
{
dbContext.Entry(order).State = EntityState.Modified;
dbContext.SaveChanges();
// More process here...
return order;
}
public void Delete(Cart cart)
{
// Delete
}
}
So, I have a service, cart service, that call another service, order service. I must work like this because I cannot simply accept the cart and all orders in it as it is. When I save a new order or update an existing order I must create a record in some other tables in other databases. The code is not in my example. So, I repeat I have a service that call another service and then I have 2 dbContext. At best this just create 2 context in memory, at worst this create exception. Exception like you cannot attach an entity to 2 contexts or this entity is not in context.
Well, I would like all my service use the same context. I suppose you will al tell me to use Dependency Injection. Yes, well ok but I don't want, each time I create a new service have to pass the context. I don't want to have to do that:
public void Checkout(Cart cart)
{
// ...
using (var orderService = new OrderService(dbContext))
{
// ...
}
}
I would like to do something that impact my base service only if possible. A singleton maybe... At this point I can see your face. Yes I know Singleton are soo bad. Yes but i'm doing a IIS Web API. Each request is a new instance. I don't care about the impact of the singleton. And I can load my database by changing the connection string in config file so the benefit of DI is there already. Well, I also know it is possible to have singleton with DI. I just don't know how.
So, what can I do to be sure I share my dbContext with all my services?
Disclaimer: This example is not intended to be a "good" one and certainly does not follow best practices, but faced with an existing legacy code base which from your example already suffers from a number of questionable practices, this should get you past the multiple context issues.
Essentially if you're not already using a IoC Container to perform dependency injection then what you need is to introduce a unit of work to manage the scope of a DbContext where your base Service class provides a DbContext provided by the unit of work. (Essentially a DbContext Registry)
For the unit of work and assuming EF6 I would recommend Mehdime's DbContextScope which is available as a NuGet package. Alternatively you can find the source code on Github and implement something similar without too much trouble. I like this pattern because it leverages the CallContext to serve as the communication layer between the ContextScope (Unit of Work) created by the DbContextScopeFactory and the AmbientDbContextScope. This will probably take a little time to get your head around but it injects very nicely into legacy applications where you want to leverage the Unit of Work and don't have dependency injection.
What it would look like:
In your Service class you would introduce the AmbientDbContextLocator to resolve your DbContext:
private readonly IAmbientDbContextLocator _contextLocator = new AmbientDbContextLocator();
protected DbContext DbContext
{
get { return _contextLocator.Get<DbContext>(); }
}
And that's it. Later as you refactor to accommodate Dependency injection, just inject the AmbientDbContextLocator instead of 'new'ing it up.
Then, in your web API controllers where you are using your services, (not the services themselves) you need to add the DbContextScopeFactory instance..
private readonly IDbContextScopeFactory _contextScopeFactory = new DbContextScopeFactory();
Lastly, in your API methods, when you want to call your services, you need to simply use the ContextScopeFactory to create a context scope. The AmbientDbContextLocators will retrieve the DbContext from this context scope. The context scope you create with the factory will be done in a using block to ensure your contexts are disposed. So, using your Checkout method as an example, it would look like:
In your Web API [HttpPost] Checkout() method:
using (var contextScope = _contextScopeFactory.Create())
{
using(var service = new CartService())
{
service.Checkout();
}
contextScope.SaveChanges();
}
Your cart service Checkout method would remain relatively unchanged, only instead of accessing dbContext as a variable (new DbContext()) it will access the DbContext property which gets the context through the context locator.
The Services can continue to call DbContext.SaveChanges(), but this isn't necessary and the changes will not be committed to the DB until the contextScope.SaveChanges() is called. Each service will have its own instance of the Context Locator rather than the DbContext and these will be dependent on you defining a ContextScope to function. If you call a Service method that tries to access the DbContext without being within a using (var contextScope = _contextScopeFactory.Create()) block you will receive an error. This way all of your service calls, even nested service calls (CartService calls OrderService) will be interacting with the same DbContext instance.
Even if you just want to read data, you can leverage a slightly faster DbContext using _contextScopeFactory.CreateReadOnly() which will help guard against unexpected/disallowed calls to SaveChanges().
When using the ASP.NET Core stack, the tutorial for using EF with it defaults to using DI to provide your DB context, just not with a service layer. That said, it actually does the right thing for this out of the box. I'll give a brief rundown of the bare minimum necessary for this to work, using whatever the latest versions of ASP.NET Core Web API and EF Core were on NuGet at the time of writing.
First, let's get the boilerplate out of the way, starting with the model:
Models.cs
public class ShopContext : DbContext
{
public ShopContext(DbContextOptions options) : base(options) {}
// We add a GUID here so we're able to tell it's the same object later.
public string Id { get; } = Guid.NewGuid().ToString();
public DbSet<Cart> Carts { get; set; }
public DbSet<Order> Orders { get; set; }
}
public class Cart
{
public string Id { get; set; }
public string Name { get; set; }
}
public class Order
{
public string Id { get; set; }
public string Name { get; set; }
}
Then some bare-bones services:
Services.cs
public class CartService
{
ShopContext _ctx;
public CartService(ShopContext ctx)
{
_ctx = ctx;
Console.WriteLine($"Context in CartService: {ctx.Id}");
}
public async Task<List<Cart>> List() => await _ctx.Carts.ToListAsync();
public async Task<Cart> Create(string name)
{
return (await _ctx.Carts.AddAsync(new Cart {Name = name})).Entity;
}
}
public class OrderService
{
ShopContext _ctx;
public OrderService(ShopContext ctx)
{
_ctx = ctx;
Console.WriteLine($"Context in OrderService: {ctx.Id}");
}
public async Task<List<Order>> List() => await _ctx.Orders.ToListAsync();
public async Task<Order> Create(string name)
{
return (await _ctx.Orders.AddAsync(new Order {Name = name})).Entity;
}
}
The only notable things here are: the context comes in as a constructor parameter as God intended, and we log the ID of the context to verify when it gets created with what.
Then our controller:
ShopController.cs
[ApiController]
[Route("[controller]")]
public class ShopController : ControllerBase
{
ShopContext _ctx;
CartService _cart;
OrderService _order;
public ShopController(ShopContext ctx, CartService cart, OrderService order)
{
Console.WriteLine($"Context in ShopController: {ctx.Id}");
_ctx = ctx;
_cart = cart;
_order = order;
}
[HttpGet]
public async Task<IEnumerable<string>> Get()
{
var carts = await _cart.List();
var orders = await _order.List();
return (from c in carts select c.Name).Concat(from o in orders select o.Name);
}
[HttpPost]
public async Task Post(string name)
{
await _cart.Create(name);
await _order.Create(name);
await _ctx.SaveChangesAsync();
}
}
As above, we take the context as a constructor parameter to triple-check it's what it should be; we also need it to call SaveChanges at the end of an operation. (You can refactor this out of controllers if you want to, but they'll work just fine as units of work for now.)
The part that ties this together is the DI configuration:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
// Use whichever provider you have here, this is where you grab a connection string from the app configuration.
services.AddDbContext<ShopContext>(options =>
options.UseInMemoryDatabase("Initrode"));
services.AddScoped<CartService>();
services.AddScoped<OrderService>();
}
AddDbContext() defaults to registering a DbContext to be created per-request by the container. Web API provides the AddControllers method that puts those into the DI container, and we also register our services manually.
The rest of Startup.cs I've left as-is.
Starting this up and opening https://localhost:5001/shop should log something like:
Context in CartService: b213966e-35f2-4cc9-83d1-98a5614742a3
Context in OrderService: b213966e-35f2-4cc9-83d1-98a5614742a3
Context in ShopController: b213966e-35f2-4cc9-83d1-98a5614742a3
with the same GUID for all three lines in a request, but a different GUID between requests.
A little additional explanation of what goes on above:
Registering a component in a container (using Add() and such above) means telling the container those components exist and that it should create them for you when asked, as well as what identifiers they're available under and how to create them. The defaults for this are more or less "make the component available as its class, and create it by calling its one public constructor, passing other registered components into it" - the container looks at the constructor signature to figure this out.
"Scoped" in an ASP.NET Core app means "per-request." I think in this case one could also use services with a transient lifetime - a new one created every time it's needed, but they'll still get the same DbContext as long as they're created while handling the same request. Which one to do is a design consideration; the main constraint is that you can't inject shorter-lived components into longer-lived components without having to use more complex techniques, which is why I favour having all components as short-lived as possible. In other words, I only make things longer-lived when they actually hold some state that needs to live for that time, while also doing that as sparingly as possible because state bad. (Just recently I had to refactor an unfortunate design where my services were singletons, but I wanted my repositories to be per-request so as to be able to inject the currently logged in user's information into the repository to be able to automatically add the "created by" and "updated by" fields.)
You'll note that with support for doing things this way being built-in to both ASP.NET Core and EF Core, there's actually very little extra code involved. Also, the only thing needed to go from "injecting a context into your controllers" (as the tutorial does) to "injecting a context into services that you use from your controllers" is adding the services into DI - since the controller and context are already under DI, anything new you add can be injected into them and vice versa.
This should give you a quick introduction into how to make things "just work" and shows you the basic use case of a DI container: you declaratively tell it or it infers "this is an X", "this is an Y", "this is a Z and it needs to be created using an X and a Y"; then when you ask the container to give you a Z, it will automagically first create an X and Y, then create Z with them. They also manage the scope and lifetime of these objects, i.e. only create one of a type for an API request. Beyond that it's a question of experience with them and familiarity with a given container - say Ninject and Autofac are much more powerful than the built-in one - but it's variations on the same idea of declaratively describing how to create an object possibly using other objects (its dependencies) and having the container "figure out" how to wire things together.
I'm having some problems with getting unity to provide dependencies for my MVC controllers.
I want my ApplicationUser data and my business data in the same database and I am using code-first migrations with Entity Framework. To that end my DbContext inherits from IdentityDbContext and then implements an interface which represents my business data:
public class DealFinderDb : IdentityDbContext<ApplicationUser>, IDealFinderDb
{
public DealFinderDb() : base("name=DealFinderConnectionString", false)
{
}
public IDbSet<Deal> Deals { get; set; }
public IDbSet<Category> Categories { get; set; }
public IDbSet<SavedSearch> SavedSearches { get; set; }
public static DealFinderDb Create()
{
return new DealFinderDb();
}
}
public interface IDealFinderDb : IDisposable
{
IDbSet<Deal> Deals { get; set; }
IDbSet<Category> Categories { get; set; }
IDbSet<SavedSearch> SavedSearches { get; set; }
int SaveChanges();
DbEntityEntry<TEntity> Entry<TEntity>(TEntity entity)
where TEntity : class;
}
In my controller I need to be able to get the current user which means my controller has a dependency, not only on a IDealFinderDb but also on a UserManager. I understand that the best way to test this is to mock an IUserStore and pass that into the constructor of my controller. I have written the tests that mock both the IUserStore and the controller's HttpContext and these tests work as expected. This means my controller looks like this:
public class SavedSearchesController : Controller
{
private readonly IDealFinderDb dealFinderDb;
private readonly UserManager<ApplicationUser> userManager;
public SavedSearchesController(IDealFinderDb dealFinderDb, IUserStore<ApplicationUser> userStore)
{
this.dealFinderDb = dealFinderDb;
this.userManager = new UserManager<ApplicationUser>(userStore);
}
public ActionResult Index()
{
var user = this.userManager.FindById(this.User.Identity.GetUserId());
var usersSavedSearches = this.dealFinderDb.SavedSearches.Where(s => s.User.Id == user.Id);
return this.View(usersSavedSearches);
}
// Snip unrelated action methods.
protected override void Dispose(bool disposing)
{
if (disposing)
{
this.dealFinderDb.Dispose();
}
base.Dispose(disposing);
}
}
This seems fine but I am using Unity to provide implementations for these interfaces at run-time and this is where I'm stuck. My first attempt at my UnityConfig looks like this:
container.RegisterType<IDealFinderDb, DealFinderDb>();
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(
new InjectionConstructor(typeof(DealFinderDb)));
...but the problem with that is I end up with a DbContext being instantiated twice leading to an error of "System.InvalidOperationException: 'An entity object cannot be referenced by multiple instances of IEntityChangeTracker.'" when I call Add() on any of my IDBSets in my DbContext I guess this is because unity is instantiating my DbContext twice.
So my next attempt was to ensure that only a single instance of DealFinderDb is created and that looks like this in my UnityConfig:
container.RegisterType<DealFinderDb, DealFinderDb>(new ContainerControlledLifetimeManager());
container.RegisterType<IDealFinderDb, DealFinderDb>();
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(
new InjectionConstructor(typeof(DealFinderDb)));
...but when this.userManager.FindById() is called in my controller I get the error "System.InvalidOperationException: 'The operation cannot be completed because the DbContext has been disposed.'". Obviously I could avoiding calling Dispose on my Context but this is bad as I assume means I am actually using the same DBContext instance for the entire life-cycle of my application.
What should I put in my UnityConfig to ensure that both the IDealFinderDb and IUserStore dependencies are satisfied and that only a single context is instantiated each time my controller is instantiated?
Thanks
What should I put in my UnityConfig to ensure that both the
IDealFinderDb and IUserStore dependencies are satisfied and that only
a single context is instantiated each my controller is instantiated?
You should use per-graph lifetime manager which is called PerResolveLifetimeManager in Unity:
container.RegisterType<IDealFinderDb, DealFinderDb>(new PerResolveLifetimeManager());
According to best practice to software design pattern, you should always follow Singleton Pattern while creating database context and logger context and many other things as per business requirement if you feel there is a need for singleton object go for that and while using singleton pattern do take care of thread safety singleton if you are implementing threads.its so easy and for help, you can refer MSDN, it has an implementation of the singleton.
https://msdn.microsoft.com/en-us/library/ff647854.aspx
Hope this helps.
I have been trying to create a Repository Pattern along with Dependency injection, But Looks like I am missing some simple step. Here is my code
public class HomeController
{
private readonly ILoggingRepository _loggingRepository;
public HomeController(ILoggingRepository loggingRepository)
{
_loggingRepository = loggingRepository;
}
public void MyMethod()
{
string message = "MyMessage Called";
_loggingRepository .LogMessage(message);
}
}
// ILoggingRepository.cs
public interface ILoggingRepository
{
void LogMessage(string message);
}
// LoggingRepository.cs
public class LoggingRepository : ILoggingRepository
{
public void LogMessage(string message)
{
using (var dbContext = new DbContext())
{
var serviceLog = new Log() { Message = message, Logged = DateTime.UtcNow };
dbContext.Logs.Add(serviceLog);
dbContext.SaveChanges();
}
}
}
This works perfectly all right so far, but the problem arises when i make more than one repository calls.
Now I know that Entity framework 6.0 has inbuilt unit of work representation so I didn't created a UnitofWork Interface or class
But the problem appears when I do something like this in two different transactions. Lets say
Area area = _areaRepository.GetArea(); // Line 1
area.Name = "NewArea"; // Line 2
_areaRepository.SaveArea(area); // Line 3
now because it _areaRepository creates a new DbContext in Line 3, it doesn't changes the name of area as it doesn't consider EntityState.Modified
I have to explicitly set that, which isn't correct.
So I guess I need to do all this in single Transaction, Where I am doing wrong here ?
What is the correct and best way to achieve this, Should I inject my DbContext also into the repository?
This is how I doit all times:
If dont use Repository or Unit of Work layers, because Entity Framework db Context already implements those patterns. So, I only have a Service layer:
public interface IBaseService<VO, ENT>{
IQueryable<VO> GetAll();
VO Get(object id);
}
public abstract class BaseService<VO, ENT> : IBaseService<VO, ENT>{
MyContext db;
public BaseService(MyContext db){
this.db = db;
}
public IQueryable<VO> GetAll(){
return db.Set<ENT>().ProjectTo<VO>();
}
}
A service class have a dbContext injected in the constructor. This classes are located in a Service library. Then, how the dbContext and the service are resolved is a problem of the project who will be using them. The ProjectTo method is an extension for IQueryable from the Automapper Nuget. For example:
A Windows Service needs all services instance in the same thread shares the same dbContext. So, in the windows service project, I use Ninject https://www.nuget.org/packages/Ninject/4.0.0-beta-0134, this library is a dependency resolver, wich I use to configure how dependencies are builded, creating a Kernel, like this:
var kernel = new StandardKernel();
kernel.Bind<MyContext>().ToSelf().InThreadScope();
kernel.Bind<IServiceImplInterface>().To<ServiceImplClass>().InThreadScope();
I you are creating a Web project, you will need to install a aditional nuget (Ninject.WebCommon, Ninject.Web.COmmon.WebHost, Ninject.MVC5) to provide a .InRequestScope() method to the binding configuration, like this:
var kernel = new StandardKernel();
kernel.Bind<MyContext>().ToSelf().InRequestScope();
kernel.Bind<IServiceImplInterface>().To<ServiceImplClass>().InRequestScope();
You need setup those kernel when the app startup. In a web project is in the global.asax, in a windows service project, should be in the Service constructor:
You can visit www.ninject.org/learn.html to learn more about ninject. But, there are othres like Autofac or Caste Windsor, it is up to you. If you like to keep using the repository pattern, just use Ninject inject them into the Service layer, like i did with the dbContext.
The best approach is to have one instance of DbContext, injecting it on each repository implementation. That way you will have a single instance of the database context, so EF will be able to detect changes on the entity objects.
If you need to use isolated dbContexts as in your example, then you need to explicitly set the state of the object as Modified.
Depending on the type of project, you should set the context on a specific scope. For example, for web applications one option is to use instance per Web request (per lifetime scope). Check this url where you can see a good explanation of the different instance scopes.
The using statement simply creates a new scope, executing the Dispose() method after the code block. EF does a lot on the background to maintain the UoW and state of the objects, but in your case, with the using, you are not using this fature.
First, a DbContext is a repository. If you want to wrap it in a custom repository, they should have the same lifecycle.
Second, your Unit-of-work is your controller. The repository should be scoped to unit-of-work.
This means that your repository needs to be Disposable, since the DbContext is.
So something like:
public interface ILoggingRepository : IDisposable
{
void LogMessage(string message);
}
// LoggingRepository.cs
public class LoggingRepository : ILoggingRepository
{
MyDbContext db;
public LoggingRepository(MyDbContext db)
{
this.db = db;
}
public void Dispose()
{
db.Dispose();
}
public void LogMessage(string message)
{
var serviceLog = new MonitoringServiceLog() { Message = message, Logged = DateTime.UtcNow };
db.MonitoringServiceLogs.Add(serviceLog);
db.SaveChanges();
}
}
If your ILoggingRepository wan't a database, it might be a file or something else that is expensive to create or open and needs to be closed.
I am building an ASP.NET Core MVC application with Entity Framework Code-First.
I implemented a simple repository pattern, providing basic CRUD operations for all the model classes I have created.
I chose to follow all the recommendations provided in docs and DI is one of these.
In ~~.NET 5~~ (6 years later update: .net 5 was the alpha name of .net core 1.0) dependency injection works very well for any class that we do not directly instantiate (e.g.: controllers, data repositories, ...).
We simply inject them via the constructor, and register the mappings in the Startup class of the application :
// Some repository class
public class MyRepository : IMyRepository
{
private readonly IMyDependency _myDependency;
public MyRepository(IMyDependency myDependency)
{
_myDependency = myDependency;
}
}
// In startup.cs :
services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<IMyRepository, MyRepository>();
The problem is that in some of my model classes, I would like to inject some of the dependencies I have declared.
But I think that I cannot use the constructor injection pattern because model classes are often explicitly instantiated. Therefore, I would need to provide myself with the dependencies, which I can't.
So my question is: is there another way than constructor injection to inject dependencies, and how? I was for example thinking of an attribute pattern or something like that.
As I already explained in a comment, when creating an object using new, there is nothing from the dependency injection framework that is involved in the process. As such, it’s impossible for the DI framework to magically inject things into that object, it simply doesn’t know about it.
Since it does not make any sense to let the DI framework create your model instances (models are not a dependency), you will have to pass in your dependencies explicitly if you want the model to have them. How you do that depends a bit on what your models are used for, and what those dependencies are.
The simple and clear case would be to just have your model expect the dependencies on the constructor. That way, it is a compile time error if you do not provide them, and the model has access to them right away. As such, whatever is above, creating the models, is required to have the dependencies the model type needs. But at that level, it’s likely that this is a service or a controller which has access to DI and can request the dependency itself.
Of course, depending on the number of dependencies, this might become a bit complicated as you need to pass them all to the constructor. So one alternative would be to have some “model factory” that takes care of creating the model object. Another alternative would also be to use the service locator pattern, passing the IServiceCollection to the model which can then request whatever dependencies it needs. Note that is generally a bad practice and not really inversion of control anymore.
Both these ideas have the issue that they modify the way the object is created. And some models, especially those handled by Entity Framework, need an empty constructor in order for EF to be able to create the object. So at that point you will probably end up with some cases where the dependencies of your model are not resolved (and you have no easy way of telling).
A generally better way, which is also a lot more explicit, would be to pass in the dependency where you need it, e.g. if you have some method on the model that calculates some stuff but requires some configuration, let the method require that configuration. This also makes the methods easier to test.
Another solution would be to move the logic out of the model. For example the ASP.NET Identity models are really dumb. They don’t do anything. All the logic is done in the UserStore which is a service and as such can have service dependencies.
The pattern often used in domain driven design (rich domain model to be specific) is to pass the required services into the method you are calling.
For example if you want to calculate the vat, you'd pass the vat service into the CalculateVat method.
In your model
public void CalculateVat(IVatCalculator vatCalc)
{
if(vatCalc == null)
throw new ArgumentNullException(nameof(vatCalc));
decimal vatAmount = vatcalc.Calculate(this.TotalNetPrice, this.Country);
this.VatAmount = new Currency(vatAmount, this.CurrencySymbol);
}
Your service class
// where vatCalculator is an implementation IVatCalculator
order.CalculateVat(vatCalculator);
Finally your service can inject another services, like a repository which will fetch the tax rate for a certain country
public class VatCalculator : IVatCalculator
{
private readonly IVatRepository vatRepository;
public VatCalculator(IVatRepository vatRepository)
{
if(vatRepository == null)
throw new ArgumentNullException(nameof(vatRepository));
this.vatRepository = vatRepository;
}
public decimal Calculate(decimal value, Country country)
{
decimal vatRate = vatRepository.GetVatRateForCountry(country);
return vatAmount = value * vatRate;
}
}
I know my answer is late and may not exactly what you're asking for, but I wanted to share how I do it.
First of all: If you want to have a static class that resolves your dependencies this is a ServiceLocator and it's Antipattern so try not to use it as you can.
In my case I needed it to call MediatR inside of my DomainModel to implement the DomainEvents logic.
Anyway, I had to find a way to call a static class in my DomainModel to get an instance of some registered service from DI.
So I've decided to use the HttpContext to access the IServiceProvider but I needed to access it from a static method without mention it in my domain model.
Let's do it:
1- I've created an interface to wrap the IServiceProvider
public interface IServiceProviderProxy
{
T GetService<T>();
IEnumerable<T> GetServices<T>();
object GetService(Type type);
IEnumerable<object> GetServices(Type type);
}
2- Then I've created a static class to be my ServiceLocator access point
public static class ServiceLocator
{
private static IServiceProviderProxy diProxy;
public static IServiceProviderProxy ServiceProvider => diProxy ?? throw new Exception("You should Initialize the ServiceProvider before using it.");
public static void Initialize(IServiceProviderProxy proxy)
{
diProxy = proxy;
}
}
3- I've created an implementation for the IServiceProviderProxy which use internally the IHttpContextAccessor
public class HttpContextServiceProviderProxy : IServiceProviderProxy
{
private readonly IHttpContextAccessor contextAccessor;
public HttpContextServiceProviderProxy(IHttpContextAccessor contextAccessor)
{
this.contextAccessor = contextAccessor;
}
public T GetService<T>()
{
return contextAccessor.HttpContext.RequestServices.GetService<T>();
}
public IEnumerable<T> GetServices<T>()
{
return contextAccessor.HttpContext.RequestServices.GetServices<T>();
}
public object GetService(Type type)
{
return contextAccessor.HttpContext.RequestServices.GetService(type);
}
public IEnumerable<object> GetServices(Type type)
{
return contextAccessor.HttpContext.RequestServices.GetServices(type);
}
}
4- I should register the IServiceProviderProxy in the DI like this
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
services.AddSingleton<IServiceProviderProxy, HttpContextServiceProviderProxy>();
.......
}
5- Final step is to initialize the ServiceLocator with an instance of IServiceProviderProxy at the Application startup
public void Configure(IApplicationBuilder app, IHostingEnvironment env,IServiceProvider sp)
{
ServiceLocator.Initialize(sp.GetService<IServiceProviderProxy>());
}
As a result now you can call the ServiceLocator in your DomainModel classes "Or and needed place" and resolve the dependencies that you need.
public class FakeModel
{
public FakeModel(Guid id, string value)
{
Id = id;
Value = value;
}
public Guid Id { get; }
public string Value { get; private set; }
public async Task UpdateAsync(string value)
{
Value = value;
var mediator = ServiceLocator.ServiceProvider.GetService<IMediator>();
await mediator.Send(new FakeModelUpdated(this));
}
}
The built-in model binders complain that they cannot find a default ctor. Therefore you need a custom one.
You may find a solution to a similar problem here, which inspects the registered services in order to create the model.
It is important to note that the snippets below provide slightly different functionality which, hopefully, satisfies your particular needs. The code below expects models with ctor injections. Of course, these models have the usual properties you might have defined. These properties are filled in exactly as expected, so the bonus is the correct behavior when binding models with ctor injections.
public class DiModelBinder : ComplexTypeModelBinder
{
public DiModelBinder(IDictionary<ModelMetadata, IModelBinder> propertyBinders) : base(propertyBinders)
{
}
/// <summary>
/// Creates the model with one (or more) injected service(s).
/// </summary>
/// <param name="bindingContext"></param>
/// <returns></returns>
protected override object CreateModel(ModelBindingContext bindingContext)
{
var services = bindingContext.HttpContext.RequestServices;
var modelType = bindingContext.ModelType;
var ctors = modelType.GetConstructors();
foreach (var ctor in ctors)
{
var paramTypes = ctor.GetParameters().Select(p => p.ParameterType).ToList();
var parameters = paramTypes.Select(p => services.GetService(p)).ToArray();
if (parameters.All(p => p != null))
{
var model = ctor.Invoke(parameters);
return model;
}
}
return null;
}
}
This binder will be provided by:
public class DiModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null) { throw new ArgumentNullException(nameof(context)); }
if (context.Metadata.IsComplexType && !context.Metadata.IsCollectionType)
{
var propertyBinders = context.Metadata.Properties.ToDictionary(property => property, context.CreateBinder);
return new DiModelBinder(propertyBinders);
}
return null;
}
}
Here's how the binder would be registered:
services.AddMvc().AddMvcOptions(options =>
{
// replace ComplexTypeModelBinderProvider with its descendent - IoCModelBinderProvider
var provider = options.ModelBinderProviders.FirstOrDefault(x => x.GetType() == typeof(ComplexTypeModelBinderProvider));
var binderIndex = options.ModelBinderProviders.IndexOf(provider);
options.ModelBinderProviders.Remove(provider);
options.ModelBinderProviders.Insert(binderIndex, new DiModelBinderProvider());
});
I'm not quite sure if the new binder must be registered exactly at the same index, you can experiment with this.
And, at the end, this is how you can use it:
public class MyModel
{
private readonly IMyRepository repo;
public MyModel(IMyRepository repo)
{
this.repo = repo;
}
... do whatever you want with your repo
public string AProperty { get; set; }
... other properties here
}
Model class is created by the binder which supplies the (already registered) service, and the rest of the model binders provide the property values from their usual sources.
HTH
Is there another way than constructor injection to inject dependencies, and how?
The answer is "no", this cannot be done with "dependency injection". But, "yes" you can use the "service locator pattern" to achieve your end-goal.
You can use the code below to resolve a dependency without the use of constructor injection or the FromServices attribute. Additionally you can new up an instance of the class as you see fit and it will still work -- assuming that you have added the dependency in the Startup.cs.
public class MyRepository : IMyRepository
{
public IMyDependency { get; } =
CallContextServiceLocator.Locator
.ServiceProvider
.GetRequiredService<IMyDependency>();
}
The CallContextServiceLocator.Locator.ServiceProvider is the global service provider, where everything lives. It is not really advised to use this. But if you have no other choice you can. It would be recommended to instead use DI all the way and never manually instantiate an object, i.e.; avoid new.
I'm simply adding some supplemental information here to the answers provided that can help.
IServiceProvider was provided in the accepted answer, but not the important IServiceProvider.CreateScope() method. You can use it to create scopes as necessary that you added through ConfigureServices.
I'm not sure if IServiceProvider is actually a Service Locator pattern behind the scenes or not, but it's how you create scopes as far as I know. At least in the case if it is a Service Locator pattern, it's the official one for today in .NET, and so it's not compounded by the problems of writing your own Service Locator, which I also agree is anti-pattern.
Example, Startup.cs/ConfigureServices and Configure:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<SomeDbContext>(options =>
{
options.UseSqlServer(Configuration.GetSection("Databases").GetSection("SomeDb")["ConnectionString"]);
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
}, ServiceLifetime.Scoped);
services.AddMvcCore().AddNewtonsoftJson();
services.AddControllersWithViews();
}
public async void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider provider)
{
...
IServiceScope scope = provider.CreateScope();
SomeDbContext context = scope.ServiceProvider.GetRequiredService<SomeDbContext>();
SomeModelProxyClass example = new SomeModelProxyClass(context);
await example.BuildDefaults(
Configuration.GetSection("ProfileDefaults").GetSection("Something"),
Configuration.GetSection("ProfileDefaults").GetSection("SomethingSomething"));
scope.Dispose();
}
The above is for doing some default interactions on Startup, maybe if you need to build some default records in your database on a first usage, just as an example.
Ok so let's get to your repository and dependency though, will they work?
Yep!
Here's a test in my own CRUD project, I made a simple minimalist implementation of your IMyDependency and IMyRepository like so, then added them scoped as you did to Startup/ConfigureServices:
public interface IMyRepository
{
string WriteMessage(string input);
}
public interface IMyDependency
{
string GetTimeStamp();
}
public class MyDependency : IMyDependency
{
public MyDependency()
{
}
public string GetTimeStamp()
{
return DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString();
}
}
public class MyRepository : IMyRepository
{
private readonly IMyDependency _myDependency;
public MyRepository(IMyDependency myDependency)
{
_myDependency = myDependency;
}
public string WriteMessage(string input)
{
return input + " - " + _myDependency.GetTimeStamp();
}
}
Here ContextCRUD is a Model class from my own project not derived from Scaffold-DbContext tooling like my other database classes, it's a container of logic from those scaffold Model classes, and so I put it in the namespace Models.ProxyModels to hold its own business logic for doing CRUD operations so that the Controllers are not gummed up with logic that should be in the Model:
public ContextCRUD(DbContext context, IServiceProvider provider)
{
Context = context;
Provider = provider;
var scope = provider.CreateScope();
var dep1 = scope.ServiceProvider.GetService<IMyRepository>();
string msg = dep1.WriteMessage("Current Time:");
scope.Dispose();
}
Debugging I get back the expected results in msg, so it all checks out.
The calling code from the Controller for reference, just so you can see how IServiceProvider is passed from upstream by constructor injection in the Controller:
[Route("api/[controller]")]
public class GenericController<T> : Controller where T: DbContext
{
T Context { get; set; }
ContextCRUD CRUD { get; set; }
IConfiguration Configuration { get; set; }
public GenericController(T context, IConfiguration configuration, IServiceProvider provider)
{
Context = context;
CRUD = new ContextCRUD(context, provider);
Configuration = configuration;
}
...
You can do it, check out [InjectionMethod] and container.BuildUp(instance);
Example:
Typical DI constructor (NOT NEEDED IF YOU USE InjectionMethod) public
ClassConstructor(DeviceHead pDeviceHead) {
this.DeviceHead = pDeviceHead; }
This attribute causes this method to be called to setup DI.
[InjectionMethod] public void Initialize(DeviceHead pDeviceHead) {
this.DeviceHead = pDeviceHead; }
I need some help - I am trying to use a custom validation attribute in an ASP.NET MVC web project that needs to make a database call.
I have windsor successfully working for the controllers and the IRepository interface is injected normally. The problem arrises when I need to inject the repository into the attribute class.
The attribute class has the following code:
public class ValidateUniqueUrlNodeAttribute : AbstractValidationAttribute
{
private readonly string message;
private readonly IArticleRepository articleRepository;
public ValidateUniqueUrlNodeAttribute(string message)
{
this.message = message;
}
public ValidateUniqueUrlNodeAttribute(string message, IArticleRepository articleRepository):this(message)
{
this.articleRepository = articleRepository;
}
public override IValidator Build()
{
var validator = new UniqueUrlNodeValidator(articleRepository) { ErrorMessage = message };
ConfigureValidatorMessage(validator);
return validator;
}
My problem is that I cannot seem to make Windsor intercept the contruction of the attribute to pass in the IArticleRepository
The current code in my global.asax file is as follows:
container = new WindsorContainer();
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container));
container
.RegisterControllers(Assembly.GetExecutingAssembly())
.AddComponent<IArticleRepository, ArticleRepository>()
.AddComponent<ValidateUniqueUrlNodeAttribute>();
Any help would be greatly appreciated.
AFAIK no dependency injection container can directly manage an attribute, since it's instantiated by the runtime and there's no way to intercept that.
However, they can cheat by either:
Using a static gateway to the container (example), or
Using a "BuildUp" feature that injects whatever dependencies are found within an already-constructed object. This is called BuildUp in Unity or InjectProperties in Autofac.
Windsor doesn't support #2 (ref1, ref2), so you can either:
Try one of the hacks to make Windsor support #2 (hack1, hack2)
Use a static gateway
Implement your own IValidatorBuilder and make it use Windsor to create validators. I'm sure this is implemented somewhere but I can't find it right now...
Don't know if this helps, but I subclassed ValidationAttribute to expose a Resolve<T>() method like so:
public abstract class IocValidationAttribute : ValidationAttribute
{
protected T Resolve<T>()
{
return IocHelper.Container().Resolve<T>();
}
}
Then it can be used in any custom ValidatorAttribute that needs to hit a database:
public class UniqueEmailAttribute : IocValidationAttribute
{
public override bool IsValid(object value)
{
ICustomerRepository customerRepository = Resolve<ICustomerRepository>();
return customerRepository.FindByEmail(value.ToString()) == null;
}
}
I think it's a variation of the 'Static Gateway' approach mentioned by Mauricio Scheffer. I don't know if this is a good design or not. I'm not a huge fan of it, I'd rather the dependency was injected more 'elegantly', though I can't use constructor injection obviously, I'd like to use Property injection but can't work out a way to hook into the ASP.NET MVC framework code to do this (I've even pored though the MVC2 source code).
I was able to wire it up [using Autofac as it happens, but it's just constructor injection via the ASP.NET MVC DependencyResolver] in this answer, enabling one to write:
class MyModel
{
...
[Required, StringLength(42)]
[ValidatorService(typeof(MyDiDependentValidator), ErrorMessage = "It's simply unacceptable")]
public string MyProperty { get; set; }
....
}
public class MyDiDependentValidator : Validator<MyModel>
{
readonly IUnitOfWork _iLoveWrappingStuff;
public MyDiDependentValidator(IUnitOfWork iLoveWrappingStuff)
{
_iLoveWrappingStuff = iLoveWrappingStuff;
}
protected override bool IsValid(MyModel instance, object value)
{
var attempted = (string)value;
return _iLoveWrappingStuff.SaysCanHazCheez(instance, attempted);
}
}
With some helper classes (look over there), you wire it up e.g. in ASP.NET MVC like so in the Global.asax :-
DataAnnotationsModelValidatorProvider.RegisterAdapterFactory(
typeof(ValidatorServiceAttribute),
(metadata, context, attribute) =>
new DataAnnotationsModelValidatorEx(metadata, context, attribute, true));
Hmm.
Can you test the effect of removing the (string message) ctor, and see if that at least forces Castle to use the ctor with the Repostiory ?
Otherwise we call AddComponent(name, type, type). Other than that it really should work...
Also does this hint at my first idea ? How do I use Windsor to inject dependencies into ActionFilterAttributes