Injecting Dependency in Method in ASP.NET Core - c#

I have the following scenario:
I got a service ICompanyDocumentsService with a single implementation CompanyDocumentsServicewhich I register in my Startup class:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ICompanyDocumentService, CompanyDocumentService>();
}
I need this service in many places, and it doesn't bother me using DI in Constructor.
However, there is one place where I need it injected in a Method (or probably in a property would be even better):
public abstract class CompanyDocumentBase
{
public abstract object GetAllProperties(Employee employee, string properties,
CompanyDocumentReferenceData documentReferenceData);
// blah, blah, lots of Formatting Methods
private CompanyDocumentService CompanyDocumentService { get; set; } // **inject service here**
public string GetFormattedEmployeeIndividualEmploymentAgreementNumber(Employee employee,
ICompanyDocumentService companyDocumentService = null) // **optional because
//inherited class doesn't need to know anything about this service, it concerns only it's result**
{
companyDocumentService = CompanyDocumentService;
var test =
companyDocumentService.GetEmloyeeIndividualEmploymentAgreementNumber(employee.Id);
return string.Empty;
}
}
There are many classes inheriting CompanyDocumentBase which are only concerned in it's method results, as mentioned above, that's why that parameter is optional, and that's why I don't need injecting DI in constructor, thus the inheriting classes won't be needing that.
public class JobDescriptionCompanyDocument : CompanyDocumentBase
{
public override object GetAllProperties(Employee employee,
string properties, CompanyDocumentReferenceData documentReferenceData)
{
var document = JsonConvert.DeserializeObject<JobDescriptionModel>(properties);
document.IndividualEmploymentAgreementNumber = GetEmployeeIndividualEmploymentAgreementNumber(employee);
return document;
}
}
Is there any simple way to achieve this? Preferable without needing to install a separate library like Unity or Autofac.
Ideal it would be to somehow get the instance of CompanyDocumentsService directly into that property, something like:
private CompanyDocumentService CompanyDocumentService => Startup.Services.blah that instance

One hack way (personally I wouldn’t recommend it), is after your container is built, you could resolve an instance of IHttpContextAccessor and set it to static class, e.g. IoC
Then you could do private CompanyDocumentService CompanyDocumentService => IoC.HttpContextAccessor.HttpContext.RequestServices.GetService().
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httpcontext.requestservices?view=aspnetcore-3.1
The interface is a singleton, and provides access to scoped services from a static context.
Note you might have to explicitly register HttpContextAccessor:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-3.1
UPDATE
What I'd recommend
If you are open to object factories, and changing the way how DocumentBase is instantiated, try make a factory, and whenever you need an instance of DocumentBase, only use the factory to create it:
public abstract class CompanyDocumentBase
{
// Use internal so that access only limited to friendly assembly
internal CompanyDocumentService CompanyDocumentService { get; set; }
}
// Inject this class to where you need to create an instance of CompanyDocumentBase
public class CompanyDocumentFactory<T> where T : CompanyDocumentBase
{
private readonly IServiceProvider _services;
// DI contaiener has implicit IServiceProvider support, when you do this on constructor, it injects service provider of *current* scope
// If this factory is registered as singleton, you need to use IHttpContextAccessor to use request's service provider in Create method
// because your DocumentService is scoped.
public CompanyDocumentFactory(IServiceProvider services)
{
_services = services;
}
public T Create()
{
// Create an instance of document use your current method.
var instance = new T();
instance.CompanyDocumentService = _services.GetRequiredService<ICompanyDocumentService>();
return instance;
}
}

Related

Unity multiple interfaces implementation registered by convention

I'm trying to register by convention multiple implementation of single interface and later use all those interfaces as dependency in other classes. Unfortunatelly, I'm having some problems trying to do so.
I want to register multiple implementation, so I added WithName.TypeName druing registration but this seems to be causing problems. Without it, I can't register multiple implementations for single interface.
Below is simple example which is not working. Unity is throwing exception and I don't know why.
Unity.ResolutionFailedException: 'Resolution failed with error: No
public constructor is available for type KYPClient.IConf.
namespace KYPClient
{
public interface IConf
{
string conf();
}
public class Conf : IConf
{
public string conf()
{
return "conf";
}
}
public interface ILoader
{
string load();
}
public class Load_1 : ILoader
{
public string load()
{
return "load-1";
}
}
public class Load_2 : ILoader
{
public string load()
{
return "load-2";
}
}
public class MainCls
{
private IConf _conf;
private IEnumerable<ILoader> _loaders;
public MainCls(IConf conf, IEnumerable<ILoader> loaders)
{
_conf = conf;
_loaders = loaders;
}
public void Run()
{
System.Console.WriteLine(_conf.conf());
foreach (var l in _loaders)
{
Console.WriteLine(l.load());
}
}
}
internal static class Client
{
private static void Main()
{
using var container = new UnityContainer();
container.RegisterTypes(
AllClasses.FromAssemblies(typeof(MainCls).Assembly),
WithMappings.FromAllInterfaces,
WithName.TypeName,
WithLifetime.ContainerControlled);
var main = container.Resolve<MainCls>();
main.Run();
}
}
}
The issue is you're using the WithName.TypeName option. This means that each type from the assembly is done as a named registration in the container. This is a good thing in your case because you are registering multiple ILoader instances, so the container has to be able to differentiate them. However, it also means that when it's being resolved, you have to pass the name in order for the container to find it.
In other words, when the container sees the constructor public MainCls(IConf conf, IEnumerable<ILoader> loaders) it interprets that as "inject the IConf instance with the default name" which doesn't exist in your container. Your IConf is registered with the name "Conf" (or possibly "KYPClient.Conf", I'm not sure, as I've never used the RegisterTypes method).
Thus, you have to explicitly name it in your constructor. Also, per How to configure Unity to inject an array for IEnumerable you need an array to get all the registered ILoader types.
public MainCls([Dependency("Conf")] IConf conf, ILoader[] loaders)
Of course, there are some drawbacks to using named dependencies (such as, what happens if you refactor and rename your class). Take a look at the second answer to With Unity how do I inject a named dependency into a constructor? for a strategy around that using a factory pattern.

How to register manually-created decorator instance

Typically, to register some configuration value using constructor injection I would do this:
string setting = ConfigurationManager.AppSettings["SomeSetting"];
container.Register<IService>(new Service(setting));
How do you accomplish something similar, in order to pass a configuration value into a decorator constructor?
Is the only means to create some configuration provider class which could get injected into the decorator? Seems like RegisterDecorator should have an overload which allows manually newing the class as needed.
There are several ways to achieve this. If that part of the object graph is simple, building the object graph by hand might give the best results:
container.RegisterSingleton<IService>(new ServiceDecorator(
setting,
new RealService()));
// or
container.Register<IService>(() => new ServiceDecorator(
setting,
new RealService()));
There is no delegate overload for RegisterDecorator in Simple Injector, which means that you can't register a decorator using RegisterDecorator that is hand-wired, but there some alternative approaches.
You can extract the setting value into its own class. This allows the that abstraction to get injected into the decorator:
container.RegisterSingleton<MySetting>(new MySetting(setting));
container.RegisterDecorator(typeof(IService), typeof(ServiceDecorator));
public ServiceDecorator : IService {
public ServiceDecorator(MySetting setting, IService decoratee) { }
}
Or you can inject the setting into a property of the decorator:
container.RegisterDecorator(typeof(IService), typeof(ServiceDecorator));
container.RegisterInitializer<ServiceDecorator>(dec => dec.Setting = setting);
public ServiceDecorator : IService {
public string Setting { get; set; }
public ServiceDecorator(IService decoratee) { }
}
Or you can make the Setting a static property:
ServiceDecorator.Setting = setting;
container.RegisterDecorator(typeof(IService), typeof(ServiceDecorator));
If the decorator itself can't be changed, you can derive from that class:
public ServiceDecoratorWithSetting : ServiceDecorator {
public static string Setting { get; set; }
public ServiceDecorator(IService decoratee) : base(Setting, decoratee) { }
}
ServiceDecoratorWithSetting.Setting = setting;
container.RegisterDecorator(typeof(IService), typeof(ServiceDecoratorWithSetting));
A last option is to override parameter injection behavior, but that's a bit more complex, and I usually only advice this in integration scenarios.

How to implement Factory Interface in Simple Injector With Parameters

This answer shows how to resolve instances using a factory interfaces without parameters.
I am using the following code
public interface ISimpleBarFactory
{
Bar CreateBar(int value);
}
public sealed class SimpleBarFactory : ISimpleBarFactory
{
private readonly Container _container;
public SimpleBarFactory (Container container)
{
_container = container;
}
public Bar CreateBar(int value)
{
_container.Register(() => new Bar(vlue));
return _container.GetInstance<Bar>();
}
}
to resolve instances which have constructor parameters.
However, I get the following exception when using the factory to instantiate the service class:
The container can't be changed after the first call to GetInstance, GetAllInstances and Verify.
Which is the right way of to resolve instances using factory interfaces with parameters?
Update
The following is my code. I am migrating the code from Ninject.
public interface IFormsUIFactory
{
AccountUI CreateAccountUI(Account account);
}
public class FormsUIFactory
{
private readonly IFormsUIFactory _uiFactory;
public FormsUIFactory(IFormsUIFactory uiFactory)
{
_uiFactory = uiFactory;
}
public void CreateAccountUI(Account account)
{
_uiFactory.CreateAccountUI(account);
}
}
UI class to be injected
public partial class AccountUI : Form
{
private readonly IAccountMaintenanceProcessor _processor;
private readonly Account _account;
public AccountUI(IAccountMaintenanceProcessor accountProcessor, Account account)
{
_processor = accountProcessor;
_account = account;
}
}
Instantiating code:
var account = new Account();
// Populate values for the account
var frm = _uiFactory.CreateAccountUI(account);
The problem you are having is caused by the fact that you are mixing runtime data (your Account) object, with components. You DI container is in charge of building object graphs of components. Those components should typically be stateless and runtime data should flow through the object graphs using method calls. Injecting runtime data in constructors of your components, makes those components statefull and complicates your application in many different ways; you are witnessing one of those complications today. But there are many of downsides of doing this. For instance, injecting runtime data into the constructor makes it impossible to verify your object graph (using an automated test) and makes it easy for your application to break at runtime. So this in no way Simple Injector specific, but Simple does make the problem more eminent by not allowing to passing in runtime values when resolving services.
You can find a detailed explanation about this here.
So instead, try to keep your components as stateless as possible and at least keep runtime data out of the constructor. A simple way to achieve this is to add a property to the form that allows setting the entity you are working with. A generic interface can be added to a form to allow this:
interface IForm<TEntity>
{
TEntity Entity { get; set; }
}
This generic interface can be used in the IFormFactory abstraction:
interface IFormFactory
{
TForm CreateFormFor<TForm, TEntity>(TEntity entity)
where TForm : Form, IForm<TEntity>;
}
Creating an implementation for IFormFactory is as easy as this:
public class FormFactory : IFormFactory
{
private readonly Container container;
public FormFactory(Container container) {
this.container = container;
}
public TForm CreateFormFor<TForm, TEntity>(TEntity entity)
where TForm : Form, IForm<TEntity> {
var form = this.container.GetInstance<TForm>();
form.Entity = entity;
return form;
}
}

Inject a component property into another component's constructor parameter with Autofac

With Autofac IoC container, say one has the following scenario:
public interface IHaveASpecialProperty
{
SpecialType SpecialProperty { get; }
}
public class HaveASpecialPropertyImpl : IHaveASpecialProperty
{
// implementation
}
public class SomeComponent
{
public SomeComponent(SpecialType special)
{
_special = special;
// rest of construction
}
private readonly SpecialType _special;
// implementation: do something with _special
}
// in composition root:
containerBuilder.RegisterType<HaveASpecialPropertyImpl>
.As<IHaveASpecialProperty>();
containerBuilder.RegisterType<>(SomeComponent);
Is there a way to register, within Autofac container, the HaveASpecialPropertyImpl type to act as a kind of provider/ factory of SpecialType instances?
What I currently have is this classic approach:
public class SomeComponent
{
public SomeComponent(IHaveASpecialProperty specialProvider)
{
_special = specialProvider.SpecialProperty;
// rest of construction
}
private readonly SpecialType _special;
// implementation: do something with _special
}
The rationale is basically related to the Law of Demeter: specialProvider is used only to grab a SpecialType instance, which instead is the actual dependency needed and used by SomeComponent, so it seems reasonable to just inject that SpecialType instance, without concerning SomeComponent on where that instance comes from.
PS: I've read about Delegate Factories, not sure if that's the (only?) way to go.
You can register a delegate :
builder.Register(c => c.Resolve<IHaveASpecialProperty>().SpecialProperty)
.As<ISpecialType>();
Using this registration, each time you will resolve a ISpecialType Autofac will resolve a IHaveASpecialProperty and return the SpecialProperty property value as ISpecialType.

how to use dependency injection to provide data that is required by several classes

several classes in my dll require a set of the data ( general configurations ) . these data are provided by the one who uses the dll through implementing an interface IConfigs . so data should be injected as a dependency . now I wonder how to do that .
Update :
sorry , if the question was not clear . the problem is should I have an instance of IConfigs in each class that needs it and using constructor injection ( that I don't like this approach ) or there is a cleaner way to handle this situation ?
You can use injection dependency by property.
If you use MEF :
Service
[Export(typeof(IServiec))]
public class Service : IService
{
....
}
Client
public class Client
{
[Import]
public IService Service
{
}
}
Nota : You add lines in order to register your catalog and container
If I understand you correctly, you want do register different derived classes with one interface, don't know what IoC Container you uses, but in here I uses Unity as in sample code, but most of other IoC Containers support using one string to differentiate registration in one interface. Assume you have:
public interface IConfig {}
public class ConfigA : IConfig {}
public class ConfigB : IConfig {}
So you can register both ConfigA and ConfigB to IConfig with different name:
var container = new UnityContainer();
container.RegisterType<IConfig, ConfigA>("A");
container.RegisterType<IConfig, ConfigA>("B");
public class MainClass
{
private IConfig _config;
public MainClass([Dependency("A")] IConfig config)
{
_config = config;
}
}
If you don't want to use constructor dependency, use property:
public class MainA
{
[Dependency("A")]
private IConfig Config { get; set; }
}
As your helper classes are static, you won't be able to use DI unless you use a ServiceLocator style and have your helper class retrieve injected values itself, something like this:
public static class HelperClass
{
static HelperClass()
{
var config = ServiceLocator.Get<IConfig>();
UserId = config.Get("UserId");
}
public static int UserId { get; private set; }
}
This is not considered good practice because your helper class then has a hidden dependency on your ServiceLocator being set up with an IConfig which contains a UserId.
I'd therefore recommend you change your helper class to be non-static, and have the IConfig it needs injected into it via its constructor, like this:
public class HelperClass
{
public HelperClass(IConfig config)
{
UserId = config.Get("UserId");
}
public int UserId { get; private set; }
}
You can then inject your HelperClass into your service classes via their constructors, like this:
public class ServiceClass
{
private readonly HelperClass _helperClass;
public ServiceClass(HelperClass helperClass)
{
_helperClass = helperClass;
}
}
This way each component can be swapped out, stubbed or mocked as necessary. If your HelperClass has no state of its own you can configure your DI container to manage it with a Singleton lifetime, which essentially makes it 'static' with none of the disadvantages.

Categories