Does CompositionContainer.SatisfyImportsOnce reuse components? - c#

In a WCF service project, I have created a simple wrapper for MEF CompositionContainer to simplify its instantiation :
internal class CompositionProxy
{
private static Lazy<CompositionContainer> m_lazyCC;
static CompositionProxy()
{
m_lazyCC = new Lazy<CompositionContainer>(() =>
{
var batch = new CompositionBatch();
var dc1 = new DirectoryCatalog(
HttpContext.Current.Server.MapPath("~/bin")
);
return new CompositionContainer(dc1);
}
);
}
public static CompositionContainer DefaultContainer
{
get
{
return m_lazyCC.Value;
}
}
}
The idea is to have one CompositionContainer for the application lifetime, which search for export in the bin directory.
Then, I set up some webservices, that requires to have on imported property :
All of them are built like this :
public class MyService: IMyService
{
public MyService()
{
CompositionProxy.DefaultContainer.SatisfyImportsOnce(this);
}
[Import]
private IContext Context { get; set; }
public void DoTheJob()
{
// Logic goes here
}
}
Elsewhere, I have one class that match this export :
[Export(typeof(IContext))]
public class MyContext
{
public MyContext(){
Log("MyContext created");
}
}
In the constructor, I ask the composition container to populate the IContext Context property.
This seems to work, in my service, I can see the Context property is correctly populated.
However, I'm experiencing memory leaks, and my tracing show me the MyContext class is instantiated only once.
Can you clarify if I'm misusing the composition framework ?
I supposed it's a good idea to have one composition container for the application lifetime, was I wrong ?
the multiple calls to SatisfyImportsOnce seems to populate the target with the same unique instance. Is it true ? If true, how can I simply change my code to have a new instance each time the method is called ?
Any suggestion to improve my code ?

I supposed it's a good idea to have one composition container for the application lifetime
Yes, you are supposed to create one container for the application lifetime.
the multiple calls to SatisfyImportsOnce seems to populate the target with the same unique instance. Is it true ? If true, how can I simply change my code to have a new instance each time the method is called ?
You need [Import(RequiredCreationPolicy=CreationPolicy.NonShared)].
Any suggestion to improve my code ?
If possible, do not expose the container as a global and litter your code with calls to it. That's the Service Locator pattern, which has some disadvantages when compared to Dependency Injection. Instead of your service trying to compose itself, just declare what it needs:
[Export(typeof(IMyService))]
public class MyService: IMyService
{
private readonly IContext context;
public MyService(
[Import(typeof(IContext),
RequiredCreationPolicy=CreationPolicy.NonShared)]
IContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.context = context;
}
public void DoTheJob()
{
// Logic goes here
}
}
In a WCF service, I think you should only need to call the container in your ServiceHostFactory implementation. I'm not really familiar with WCF though.

Related

Change dependency resolution for specific scope only

I have one dependency registered as follows:
interface IDependency { }
class DependencyImpl : IDependency { }
Startup:
services.AddScoped<IDependency, DependencyImpl>();
This works as intendended as I do want to reuse the same instance in the scope of my Web API requests.
However, in one background service, I'd like to tell which instance it will resolve to:
class MyBackgroundService
{
private readonly IServiceScopeFactory _scopeFactory; // set in ctor
public void DoStuff()
{
var itens = GetItens();
var dependencyInstance = new DependencyImpl();
Parallel.ForEach(itens, (item) =>
{
using(var scope = _scopeFactory.CreateScope())
{
scope.SwapDependencyForThisScopeOnly<IDependency>( () => dependencyInstance ); // something like this
var someOtherService = scope.ServiceProvider.GetRequiredService<ItemService(); // resolve subsequent services with provided dependencyInstance
someOtherService.Process(item);
}
});
}
}
I can't reuse the same Scope because ItemService (and/or it's dependencies) uses other scoped services that can't be shared. Neither I want to replace dependency resolution for the entire application.
Is it possible to do what I want here? Does it make sense?
I'm using dotnet core 2.2 with default IoC container for that matters.
Edit in reply to #Steven: DependencyImpl contains configurations for how an item will be processed. One of those includes an relatively expensive query. DependencyImpl is also injected more than once in the graph. So, currently, it reads the configuration once, cache them in private properties, and use the cached version on subsequent reads. Because I know I'll be reusing the same configuration for all itens here, I'd like to avoid reading the configuration again for each parallel execution.
My real-world dependency is more similar to this:
interface IDependency
{
Task<Configuration> GetConfigurationAsync();
}
class DependencyImpl : IDependency
{
private readonly Configuration _configuration;
private readonly DbContext _dbContext;
ctor(DbContext dbContext)
{
_dbContext = dbContext;
}
public async Task<Configuration> GetConfigurationAsync()
{
if(_configuration is null)
{
// read configurations
}
return _configuration;
}
}
I understand that, as is, my class is not thread-safe. I'd have to force a read at the start and/or add some thread safety here.
Also, those processings used to happen during the lifetime of a web request, and the background service is the new stuff. I'd prefer to change as little of existing code as possible, because there are few tests in place, and of course time constraints from the powers-that-be.
In general, it is not a good idea to change the structure of the registered object graphs while the application is running. Not only is this hard to achieve with most containers, it is prone to suble problems that are hard to detect. I, therefore, suggest a small change in your design that change circumvents the problem you are facing.
Instead of trying to change the dependency as a whole, instead pre-populate an existing dependency with the data loaded on a a different thread.
This can be done using the following abstraction/implementation pair:
public interface IConfigurationProvider
{
Task<Configuration> GetConfigurationAsync();
}
public sealed class DatabaseConfigurationProvider : IConfigurationProvider
{
private readonly DbContext _dbContext;
public DatabaseConfigurationProvider(DbContext dbContext)
{
_dbContext = dbContext;
}
public Configuration Configuration { get; set; }
public async Task<Configuration> GetConfigurationAsync()
{
if (Configuration is null)
{
await // read configurations
}
return Configuration;
}
}
Notice the public Configuration on the DatabaseConfigurationProvider implementation, which is not on the IConfigurationProvider interface.
This is the core of the solution I'm presenting. Allow your Composition Root to set the value, without polluting your application abstractions, as application code doesn't need to overwrite the Configuration object; only the Composition Root needs to.
With this abstraction/implementation pair, the background service can look like this:
class MyBackgroundService
{
private readonly IServiceScopeFactory _scopeFactory; // set in ctor
public Task DoStuff()
{
var itens = GetItens();
// Create a scope for the root operation.
using (var scope = _scopeFactory.CreateScope())
{
// Resolve the IConfigurationProvider first to load
// the configuration once eagerly.
var provider = scope.ServiceProvider
.GetRequiredService<IConfigurationProvider>();
var configuration = await provider.GetConfigurationAsync();
Parallel.ForEach(itens, (item) => Process(configuration, item));
}
}
private void Process(Configuration configuration, Item item)
{
// Create a new scope per thread
using (var scope = _scopeFactory.CreateScope())
{
// Request the configuration implementation that allows
// setting the configuration.
var provider = scope.ServiceProvider
.GetRequiredService<DatabaseConfigurationProvider>();
// Set the configuration object for the duration of the scope
provider.Configuration = configuration;
// Resolve an object graph that depends on IConfigurationProvider.
var service = scope.ServiceProvider.GetRequiredService<ItemService>();
service.Process(item);
}
}
}
To pull this off, you need the following DI configuration:
services.AddScoped<DatabaseConfigurationProvider>();
services.AddScoped<IConfigurationProvider>(
p => p.GetRequiredService<DatabaseConfigurationProvider>());
This previous configuration registers DatabaseConfigurationProvider twice: once for its concrete type, once for its interface. The interface registration forwards the call and resolves the concrete type directly. This is a special 'trick' you have to apply when working with the MS.DI container, to prevent getting two separate DatabaseConfigurationProvider instances inside a single scope. That would completely defeat the correctness of this implementation.
Make an interface that extends IDependency and only applies to the faster implementation that you need to request, e.g., IFasterDependency. Then make a registration for IFasterDependency. That way your faster class is still an IDependency object and you won't disrupt too much existing code, but you can now request it freely.
public interface IDependency
{
// Actual, useful interface definition
}
public interface IFasterDependency : IDependency
{
// You don't actually have to define anything here
}
public class SlowClass : IDependency
{
}
// FasterClass is now a IDependencyObject, but has its own interface
// so you can register it in your dependency injection
public class FasterClass : IFasterDependency
{
}

How to override config.json data using C# code?

I have followed this blog here on how to use IOC with Autofac, this is the first time hearing about IOC and autoFac.
I have downloaded the project from the link the blog provided and I have been looking through the project and I am trying to find out how the classes:
public class DatabaseSettings
{
public string ConnectionString { get; protected set; }
public int TimeoutSeconds { get; protected set; }
}
public class UserSettings
{
public string DefaultUsername { get; protected set; }
public bool ActiveByDefault { get; protected set; }
}
... gets populated without no invocation of the load function in 'Database reader'?
Is it because of (these) :
public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
public T LoadSection<T>() where T : class, new() => LoadSection(typeof(T)) as T;
If it is the above codes what are they(so I can read up on how they work)?
Final Question, Is it possible to save the data back to the config.json using this approach?
The entries like
public T Load<T>() where T : class, new() => Load(typeof(T)) as T;
just mean you can use the "generic" syntax when accessing in the functions. It's a bit neater than passing in the Type as a method parameter, and also means you get a strongly-typed object back. Another way of writing the above is:
public T Load<T>() where T : class, new()
{
var type = typeof(T);
var loaded = Load(type);
return loaded as T;
}
It's a useful language feature but nothing to do with IoC itself. The IoC magic itself is mostly contained in SettingsModule. This bit:
builder.RegisterInstance(new SettingsReader(_configurationFilePath, _sectionNameSuffix))
.As<ISettingsReader>()
.SingleInstance();
tells Autofac to provide a SettingsReader (the RegisterInstance part) whenever anyone requests an ISettingsReader (the As<> bit). .SingleInstance means it will treat the SettingsReader as a singleton: only one of them will be created and that same object is passed to everywhere an ISettingsReader is requested.
This other part
var settings = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => t.Name.EndsWith(_sectionNameSuffix, StringComparison.InvariantCulture))
.ToList();
settings.ForEach(type =>
{
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(type))
.As(type)
.SingleInstance();
});
is just a fancy way of automatically telling it what to do whenever it sees a request for DatabaseSettings or UserSettings. As per the original question, this is where the Load function is actually called. A simpler way of doing the same would just be:
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(typeof(DatabaseSettings))).As<DatabaseSettings>();
builder.Register(c => c.Resolve<ISettingsReader>().LoadSection(typeof(UserSettings))).As<UserSettings>();
You could write out the logic for those as "when a DatabaseSettings object is requested (.As), find an implementation for ISettingsReader, and then call LoadSection on that (the first part)"
Elsewhere in the Container class there's also this:
builder.RegisterType<UserService>().As<IUserService>();
which just tells Autofac what to do for an IUserService.
The result is that where in the main application method we have:
using (var scope = container.BeginLifetimeScope())
{
var userService = scope.Resolve<IUserService>();
Without that main method "knowing" anything about the concrete types it uses, we'll get a fully functioning IUserService back. Internally, Autofac will resolve the chain of dependencies required by plugging all of the constructor parameters for each type in the chain. That might look something like:
IUserService requested
Resolve UserService
Resolve IDatabase
return Database
Resolve UserSettings
Resolve ISettingsReader
return SettingsReader
Call LoadSection on ISettingsReader
return generated UserSettings object
For your Final Question - yes! However, IoC isn't necessarily what would enable you to do so. It just lets you bind together and access whichever custom classes you'd create to allow saving.
You might create a new interface like
public interface ISettingsWriter
{
void Save<T>(T settings);
}
And then for some reason you add a method which accesses that in the UserService:
public class UserService : IUserService
{
private readonly IDatabase _database;
private readonly UserSettings _userSettings;
private readonly ISettingsWriter _settingsWriter;
public UserService(IDatabase database, UserSettings userSettings, ISettingsWriter settingsWriter)
{
_database = database;
_userSettings = userSettings;
_settingsWriter = settingsWriter;
}
public void UpdateUserSettings()
{
_settingsWriter.Save(new UserSettings());
}
Using it in this way is a bit simpler than in the original sample code - I'd recommend taking this approach until you get more used to it. It means that the only other thing you'd need to add would be the registration for the settings writer, like:
builder.RegisterType<SettingsWriter>()
.As<ISettingsWriter>();

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.

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

Best practice for Ninject to get different implementations based on top level project

I am just starting to learn Dependency Injection and I am stuck here.
My project has a WCF DataService over an Entity Framework DbContext.
public class MyDataService : DataService<MyDbContext>
{
protected override MyDbContext CreateDataSource()
{
// I want to use dependency injection for this
return new MyDbContext();
}
}
The class is either
a) IIS hosted, so I don't have any control
b) for integration tests, created with var host = new DataServiceHost(type, new Uri[] { });
both use different contstructors for MyDbContext
So basically to inject the Context with this
protected override MyDbContext CreateDataSource()
{
INinjectModule module = ???; // -
IKernel kernel = new StandardKernel(module);
return kernel.Get<MyDbContext>();
}
So the question is, what is best practice in this situation?
Should I:
a) Create a Module in a Class Library that both main projects and the service use
b) Create a public static Variable inside the DataService project that holds the Ninject module.
c) Create a public static Variable inside the DataService project that holds the Ninject kernel
d) Something else.
I would prefer something like
protected override MyDbContext CreateDataSource()
{
DefaultKernel.Get<MyDbContext>();
}
Firstly, you should have a Composition Root. That is, a single place where your Kernel is created (not in every single function).
Secondly, you don't need a NinjectModule here.. you're asking Ninject to create an instance of a concrete object (which in almost all circumstances.. defeats the purpose).
What you should create, is a separate NinjectModule pass it into the constructor of the Kernel.. something like this:
interface IContext {
}
class MyDbContext : DbContext, IContext {
}
class YourModule : NinjectModule {
protected override void Bind() {
Bind<IContext>().To<MyDbContext>();
}
}
// In your composition root somewhere
var kernel = new StandardKernel(new NinjectModule[] { new YourModule() });
// in your createdatasource method
kernel.Get<IContext>();
This will get you started. Normally, your composition root is what drives injection of objects throughout your application, thereby eliminating the need to pass the Kernel around (which you will have to do in your current setup).
The hard thing to understand when starting out with DI/IoC is that it is the container's job to create your entire dependency graph. Therefore, if you setup the following bindings:
IContract1 -> ConcreteObject1
IContract2 -> ConcreteObject2
IContract3 -> ConcreteObject3
..and have the following setup:
class ConcreteObject1 : IContract1 {
public ConcreteObject1(IContract2 contract3) {
}
}
class ConcreteObject2 : IContract2 {
public ConcreteObject2(IContract3 contract3) {
}
}
If you ask your container for a concrete implementation of IContract1 (which will be ConcreteObject1), then it will create it.... BUT: ConcreteObject1 requires a concrete implementation of IContract2 in the constructor. So the container says "Wait, I know how to create this".. and passes in an instance of ConcreteObject2. Again, it says "wait, ConcreteObject2 wants a concrete implementation of IContract3.. again, it goes and fetches one.
Hopefully that helps.

Categories