.NET Core DbContext Dependency Resolution Scope - c#

I am experiencing an issue where DbContext instance injected into a controller is different than the instance injected into a service.
Below is my DbContext registration:
services.AddDbContext<CRMContext>();
services.AddScoped<IEstimateRepository, EstimateRepository>();
services.AddScoped<IMaterialRecordRepository, MaterialRecordRepository>();
My understanding is that by default, AddDbContext adds the context as Scoped, so I would expect that the controller and service would share the same instance.
For reference, here is the controller constructor and the service:
public LineItemController(IEstimateRepository repository)
{
_estimateRepository = repository;
}
public VentChuteLineItemRequiredEventHandler(IEstimateRepository estimateRepository, IMaterialRecordRepository materialRepository)
{
_materialRepository = materialRepository;
_estimateRepository = estimateRepository;
}
I am also using Autofac in this application, however as far as I can tell it is not in any way related to the problem at hand. It seems to be just a fundamental misunderstanding on my part of how the scoped lifetime of the DbContext is handled.

The issue ended up being related to a static class that I was using to create an instance of the service in question.
public static class DomainEventHandler
{
public static ILifetimeScope _container { get; set; }
public static void Raise<T>(T args) where T : IDomainEvent
{
foreach (var handler in _container.Resolve<IEnumerable<IHandle<T>>>())
{
handler.Handle(args);
}
}
}
Since the DomainEventHandler class is static, I assume the .net core dependency resolver knew that the lifetime of any instances it contains to not match the request, and therefore created a new DbContext instance for it to use.
Refactoring this class to no longer be static resolves the issue.

Related

Fulfilling IUserStore Dependency with Unity

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.

DbContext with Ninject ADO.NET

I am working on a big project that 80% completed (Some features need to be implemented though).But recently we discovered that the project doesn't allow concurrent requests (I mean multiple users request to same repository). Sometime we get null referece & sometimes "Executed can not open available connection , connection state is closed" etc.
Our source code is strongly restricted outside of the world. Here is some code.Let me know if there is any architectural problem, as architectural guys left company. It's using ninject 3.0. I already used InRequestScope() for all manager's repositories but no luck
Update: I am not using any ORM here, I am trying to connect SqlServer through data adapter in my DbContext class
public class DbContext
{
//execute query , nonquery etc using adapter & datatable
//Example
var dt=new DataTable();
_adapter=new _dbfactory.CreateAdapter();
_adapter.Fill(dt);
return dt;
}
//MyController
public class MyController
{
private readonly IMyManager_iMyManager;
public MyController(IMyManager iMyManager){_iMyManager=iMyManager}
public ActionResult Save()
{
_iMyManager.Save()
}
}
// My Manager
public class MyManager:IMyManager
{
private readonly IMyRepository _iMyRepository;
DbContext _dbContext=new
DbContext("someParameter","connectionstring");
public MyManager
(
IMyRepository iMyRepository, DbContext dbContext
)
{
_iMyRepository=iMyRepository;
_dbContext=dbContext;
}
Public DataTable GetDataTable()
{
try
{
_dbContext.Open();
_iMyRepository.GetDataTable()
}
catch(Exception ex){}
finally{_dbContext.Close()}
}
}
// here is the repository
Public class MyRepository:IMyRepository
{
public _dbContext;
public MyRepository(DbContext dbContext)
{
_dbContext=dbContext;
}
public DataTable GetDataTable()
{ return _dbContext.ExecuteQuery()}
}
Finally Here is our ninject binding
public class NinjectDependencyResolver()
{
var context=new DbContext("someparameter","connectionStrin");
kernel.Bind<IMyManager>().To<MyManager>().WithConstructorArgument("_dbContext",context);
kernel.Bind<IMyRepository >().To<MyRepository >().WithConstructorArgument("_dbContext",context);
}
there can have some typo in my code as I wrote everything in so editor
I think you did this too complicated in Ninject Dependency Resolver.
You shouldn't create DbContext with a new keyword. Instead you should make Ninject to be resolving DbContext in request scope or in thread scope.
To register DbContext you can do it like this:
kernel.Bind<DbContext>().To<MyDbContext>().WithConstructorArgument("someArgument", "someValue").InRequestScope();
kernel.Bind<IMyManager>().To<MyManager>().InRequestScope();
kernel.Bind<IMyRepository>().To<MyRepository>().InRequestScope();
You don't need to precise the constructor argument to DbContext as DbContext is only once registered in the Ninject.
You can also register DbContext to a DbContextProvider class and there you can add some specific logic to resolve object.
Example:
kernel.Bind<DbContext>().ToProvider<MyDbContextProvider>().InRequestScope();
internal class MyDbContextProvider : Ninject.Activation.IProvider
{
public object Create(IContext context)
{
return new MyDbContext("connectionStringArgument";
}
public Type Type { get { return typeof (MyDbContext); } }
}
I hope this helps.
You need to remove this initialization in the MyManager since you pass the initialized DbContext via IoC.
DbContext _dbContext=new
DbContext("someParameter","connectionstring");
You also need to remove the finally block in the GetDataTable in the MyManager class since as a rule of thumb, if the object is initialized via IoC, it should be destroyed by IoC as well.
finally{_dbContext.Close()}
If you are initializing something in the field level then why would you initialize it again from the constructor?
private readonly IMyRepository _iMyRepository;
DbContext _dbContext=new DbContext("someParameter","connectionstring");
public MyManager(IMyRepository iMyRepository, DbContext dbContext)
{
_iMyRepository=iMyRepository;
_dbContext=dbContext;
}
This may also be a typo. Either remove the _dbContext initialization from the constructor or delegate the task of initialization to the caller of this class.
Multiple initialization can also be the problem. since you are doing dbcontext initialization both in NinjectDependencyResolver() and MyManager. For this you are getting two different exceptions. This is a platform design issue i guess
Two problems:
// My Manager
public class MyManager:IMyManager
{
private readonly IMyRepository _iMyRepository;
DbContext _dbContext=new
DbContext("someParameter","connectionstring");
public MyManager
(
IMyRepository iMyRepository, DbContext dbContext
)
{
_iMyRepository=iMyRepository;
_dbContext=dbContext;
}
The new that is created for the field will be overwritten when the constructor is called.
public class NinjectDependencyResolver()
{
var context=new DbContext("someparameter","connectionStrin");
kernel.Bind<IMyManager>().To<MyManager>().WithConstructorArgument("_dbContext",context);
kernel.Bind<IMyRepository >().To<MyRepository >().WithConstructorArgument("_dbContext",context);
}
You create the context here once and pass it to each object creation. So you are still reusing the context object instead of creating it for each request scope.

Inheriting from Owned<T>

I am using WebAPI with Autofac and starting a long running task (fire and forget stuff) which will be alive after the lifetime of HTTP request. Therefore, I would like to prevent the ApiController to automatically dispose the object which consists the long running task, after ApiController lifetime ends.
In the Web API controller I would like to use Owned<T> class in order to inject one of the dependencies without binding it to the LifeTimeScope of the ApiController instance. It seems Owned<T> is a good choice for that, but I would like inherit from it in order to have virtual (polymorphic) Value property which I can mock with the Moq library.
However, when I inherit from Owned<T> autofac does not recognize (due to the reflection?) my MyOwned<T> and throws the exception below.
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'autofak.Meta' can be invoked with the available services and parameters: Cannot resolve parameter 'System.Func'2[System.Int32,autofak.MyOwned'1[autofak.Root]] root' of constructor 'Void .ctor(System.Func'2[System.Int32,autofak.MyOwned'1[autofak.Root]])'.
This is my top-level class which depends on Root class.
class Meta
{
public MyOwned<Root> Root { get; private set; }
public Meta(Func<int, MyOwned<Root>> root)
{
Root = root(2);
}
}
My registration code is below:
var container = new ContainerBuilder();
container.RegisterType<child>();
container.RegisterType<grandchild>();
container.RegisterType<Root>();
container.RegisterType<Meta>();
var builder = container.Build();
Is it possible to inherit from Owned and make it work or should I try a different approach?
Update:
Besides the accepted solution, I also followed a different path by creating a SingleInstance() factory in order to create new LifeTimeScope objects from the root/application lifetimescope. Similar to Owned<T> class I created a new class which also stores this new lifetime (created from root lifetime scope) for each task and makes it possible to call Dispose() as in the Owned<T>.
The easiest way to do what you want would be to create a new component that uses a Owned<T> instead of inheriting from Owned<T>
public interface IOwned<T> : IDisposable
{
T Value { get; }
}
public class MyOwned<T> : IOwned<T>
{
public MyOwned(Owned<T> owned)
{
this._owned = owned;
}
private readonly Owned<T> _owned;
public virtual T Value
{
get
{
return this._owned.Value;
}
}
public void Dispose()
{
this._owned.Dispose();
}
}
Then register your component using the RegisterGeneric method and ExternallyOwned.
builder.RegisterGeneric(typeof(MyOwned<>))
.As(typeof(IOwned<>))
.ExternallyOwned();
You need to declare it as ExternallyOwned because without this Autofac will try to dispose this component at the end of its ILifetimeScope and the goal of Owned<T> is to let you decide when you dispose the component.
Another option would be to create your own Owned<T> component which is a lot more complex because you will need to implement IRegistrationSource to manage the child ILifetimeScope created by the Owned<T> component.

ServiceStack Service class with constructor

I’m using Service Stack, and I can´t (or I don´t know how make a Service class with constructor).
Here is what I did:
public class AppHost : AppSelfHostBase
{
public AppHost()
: base("ClientService", typeof(ClientService).Assembly)
{
}
public override void Configure(Container container)
{
}
}
public class Context : ApplicationContext
{
//This class is invoked from program.cs (winform application)
//Here i have the logic of what form should i start.
var listeningOn = string.Format("http://*:{0}/", port);
var appHost = new AppHost();
appHost.Init();
appHost.Start(listeningOn);
ClientService cl = new ClientService((ILayout)f, i);
}
public class ClientService : Service
{
private readonly ILayout _activeForm;
private static Init _initConf;
public ClientService(ILayout f, Init i)
{
_activeForm = f;
_activeForm.GetClientData(i);
_initConf = i;
}
public HttpResult Post(Person request)
{
//Here i use _activeForm and _initConf
}
}
So, as I said, in the class ClientService, I wanna make a constructor, but when I make a request to the post message, it shows me the following error:
Error trying to resolve Service
'DexBrokerClient.Services.ClientService' or one of its auto wired
dependencies
ServiceStack Services are autowired and created using both Constructor and Property Injection. Any Constructor parameters are mandatory and must be registered in ServiceStack's IOC in AppHost.Configure(), e.g:
public override void Configure(Container container)
{
container.Register<ILayout>(c => ...);
container.Register<Init>(c => ...);
}
Whereas any public properties on Services are optional and will be populated from the IOC if they exist or are otherwise null.
Resolving Services
Services should be resolved using base.ResolveService<T> API's when inside Service class or HostContext.ResolveService<T>() singleton outside of Services. This resolves the Service class from ServiceStack's IOC and is populated with the IRequest context (if any).
#Mati, #TheMiddleMan The #mythz's answer expects you to have some general knowledge about dependency injection and containers that is IOC (inversion of control). In your question you ask about constructor injection. ServiceStack's IOC can handle it using auto-wiring if you have pre-configured (registered) the parameter object, for example:
container.Register(c => new Layout());
For more samples see https://docs.servicestack.net/ioc.
More about IOC and DI (dependency injection) can be read from https://dzone.com/articles/ioc-vs-di.

Dependency Injection in Model classes (entities)

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

Categories