c#: DJ and additional parameter - c#

For example, I have a class CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService with the following dependencies:
protected readonly IDeviceService _deviceService;
protected readonly IAzureFunctionLogService _azureFunctionLogService;
protected readonly IDeviceValidationService _deviceValidationService;
so, I can create ctor for the class:
public CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService(
IDeviceService deviceService,
IDeviceValidationService deviceValidationService,
IAzureFunctionLogService azureFunctionLogService)
{
_deviceService = deviceService;
_deviceValidationService = deviceValidationService;
_azureFunctionLogService = azureFunctionLogService;
}
then inject all dependencies like:
services.AddTransient<CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService>();
services.AddSingleton<Func<CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService>>(sp =>
() => sp.GetRequiredService<CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService>()
);
and then use it like this:
private readonly Func<CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService> _service;
public FunctionDebugPendingStatusWorkflow(
Func<CreateAutoDeletingRequestReachSuspensionDaysLimitAndInactiveLongTimeService> service,
//....
ILoggerFactory loggerFactory)
{
_service = service;
//....
_logger = loggerFactory.CreateLogger<FunctionDebugPendingStatusWorkflow>();
}
so, it works fine.
But how can I add one more param to ctor, which set in caller? For example, I want to pass deviceId to ctor and can't describe it as dependency using dependency injector in Program.cs (in my case)
I have to create "Init" method like this:
public void Init(int deviceId)
{
_device = _deviceService.GetDeviceById(deviceId);
// ...
}
and add logic there.
Then I have to call _service.Init(...); before using _service methods. It works, but all disadvantages and potential problems are obviously (if forgot to call etc)
How to pass this parameter using DI ?

Related

What is the best way to implement Dependency Injection in Base Controller

I have the follow trouble, in my base controller i do dependency injection. And i have a class child with implementation of base controller and i need pass the constructor. So my doubt is, my way to implementation of dependency injection is correctly?
If no, what is the best way to do this?
I use unity to implementate D.I, and my ide is VS2017 web api 2.
Follow this code i using:
Base controller or parent controller:
public class BaseController : ApiController
{
public string[] includes = null;
private readonly IFiltroServico servico;
public BaseController(IFiltroServico _servico)
{
servico = _servico;
}
}
Base controller to generics types implements Base Controller:
public abstract class BaseController<E, R, F> : BaseController
where E : class
where R : class
where F : class
{
private readonly IFiltroServico servico;
public AreaFormacaoController(IFiltroServico _servico): base(_servico)
{
servico = _servico;
}
}
Child controller:
public abstract class BaseController<R> : BaseController
where R : class
{
private readonly IFiltroServico servico;
public AreaFormacaoController(IFiltroServico _servico): base(_servico)
{
servico = _servico;
}
//services of controller;
}
You don't need to define the private field servico over and over again as it is already preset in the base controller. Just define it as protected readonly in the base class and use it in the childs.
Other than that your code is fine.
It is perfectly reasonable that a child has the same dependency parameters in the constructor as it inherits behavior of the base class that is most likely relying on the dependency.
Another option would be to use property injection in the base class but you need to add a unity specific attribute to the property. I don't like that as you bind your code directly to Unity.
Have you seen https://simpleinjector.org/index.html
check out git from https://github.com/simpleinjector/SimpleInjector
It is one of the best Inversion of Control library (IOC).
Only thing you need to do is register all your services and types.
using SimpleInjector;
static class Program
{
static readonly Container container;
static Program() {
// 1. Create a new Simple Injector container
container = new Container();
// 2. Configure the container (register)
container.Register<IOrderRepository, SqlOrderRepository>();
container.Register<ILogger, FileLogger>(Lifestyle.Singleton);
container.Register<CancelOrderHandler>();
// 3. Verify your configuration
container.Verify();
}
static void Main(string[] args)) {
// 4. Use the container
var handler = container.GetInstance<CancelOrderHandler>();
var orderId = Guid.Parse(args[0]);
var command = new CancelOrder { OrderId = orderId };
handler.Handle(command);
}
}
Once you register all your types and services you can inject those services where ever you want
public class CancelOrderHandler {
private readonly IOrderRepository repository;
private readonly ILogger logger;
private readonly IEventPublisher publisher;
// Use constructor injection for the dependencies
public CancelOrderHandler(
IOrderRepository repository, ILogger logger, IEventPublisher publisher) {
this.repository = repository;
this.logger = logger;
this.publisher = publisher;
}
public void Handle(CancelOrder command) {
this.logger.Log("Cancelling order " + command.OrderId);
var order = this.repository.GetById(command.OrderId);
order.Status = OrderStatus.Cancelled;
this.repository.Save(order);
this.publisher.Publish(new OrderCancelled(command.OrderId));
}
}
public class SqlOrderRepository : IOrderRepository {
private readonly ILogger logger;
// Use constructor injection for the dependencies
public SqlOrderRepository(ILogger logger) {
this.logger = logger;
}
public Order GetById(Guid id) {
this.logger.Log("Getting Order " + order.Id);
// Retrieve from db.
}
public void Save(Order order) {
this.logger.Log("Saving order " + order.Id);
// Save to db.
}
}
Let me know if you have any queries, Thanks.

ASP.NET Core 2 - Multiple Azure Redis Cache services DI

In ASP.NET Core 2 we can add a Azure Redis Cache like this:
services.AddDistributedRedisCache(config =>
{
config.Configuration = Configuration.GetConnectionString("RedisCacheConnection");
config.InstanceName = "MYINSTANCE";
});
Then the usage will be like this:
private readonly IDistributedCache _cache;
public MyController(IDistributedCache cache)
{
_cache = cache;
}
How can I do it so that I will have:
private readonly IDistributedCache _cache1;
private readonly IDistributedCache _cache2;
public MyController(IDistributedCache cache1, IDistributedCache cache2)
{
_cache1 = cache1;
_cache2 = cache2;
}
My questions how can I add another service that points to a different Azure Redis Cache Connection and instance and make separation of them when I want to use them?
Behind the scene, AddDistributedRedisCache() extension method does the following (code on github):
Registers action to configure RedisCacheOptions. Lambda that you pass to AddDistributedRedisCache() is responsible for that.
Instance of RedisCacheOptions is passed to constructor of RedisCache wrapped into IOptions<T>.
Registers Singletone implementation RedisCache of IDistributedCache interface.
Unfortunatelly, both of these actions aren't well suited for what you ask.
Only one action could be registered for configuring specific type of options.
Native implementation of .net core dependency injection does not support registration override.
There is still a solution that will do what you want. However this solution somewhat killing me.
The trick is that you inherit your custom RedisCacheOptions1, RedisCacheOptions2 from RedisCacheOptions and register distinct configurations for both of them.
Then you define your custom IDistributedCache1 and IDistributedCache2 interfaces that inherit from IDistributedCache.
And finally you define classes RedisCache1 (that inherits implementation from RedisCache and also implements IDistributedCache1) and RedisCache2 (the same).
Something like this:
public interface IDistributedCache1 : IDistributedCache
{
}
public interface IDistributedCache2 : IDistributedCache
{
}
public class RedisCacheOptions1 : RedisCacheOptions
{
}
public class RedisCacheOptions2 : RedisCacheOptions
{
}
public class RedisCache1 : RedisCache, IDistributedCache1
{
public RedisCache1(IOptions<RedisCacheOptions1> optionsAccessor) : base(optionsAccessor)
{
}
}
public class RedisCache2 : RedisCache, IDistributedCache2
{
public RedisCache2(IOptions<RedisCacheOptions2> optionsAccessor) : base(optionsAccessor)
{
}
}
public class MyController : Controller
{
private readonly IDistributedCache _cache1;
private readonly IDistributedCache _cache2;
public MyController(IDistributedCache1 cache1, IDistributedCache2 cache2)
{
_cache1 = cache1;
_cache2 = cache2;
}
}
// Bootstrapping
services.AddOptions();
services.Configure<RedisCacheOptions1>(config =>
{
config.Configuration = Configuration.GetConnectionString("RedisCacheConnection1");
config.InstanceName = "MYINSTANCE1";
});
services.Configure<RedisCacheOptions2>(config =>
{
config.Configuration = Configuration.GetConnectionString("RedisCacheConnection2");
config.InstanceName = "MYINSTANCE2";
});
services.Add(ServiceDescriptor.Singleton<IDistributedCache1, RedisCache1>());
services.Add(ServiceDescriptor.Singleton<IDistributedCache2, RedisCache2>());

Dependency Injection with classes other than a Controller class

At this point I'm injecting things into my Controllers with ease, in some cases building my own ResolverServices class. Life is good.
What I cannot figure out how to do is get the framework to automatically inject into non-controller classes. What does work is having the framework automatically inject into my controller IOptions, which is effectively the configuration for my project:
public class MessageCenterController : Controller
{
private readonly MyOptions _options;
public MessageCenterController(IOptions<MyOptions> options)
{
_options = options.Value;
}
}
I'm thinking whether I can do the same for for my own classes. I assume I'm close when I mimic the controller, like this:
public class MyHelper
{
private readonly ProfileOptions _options;
public MyHelper(IOptions<ProfileOptions> options)
{
_options = options.Value;
}
public bool CheckIt()
{
return _options.SomeBoolValue;
}
}
I think where I'm failing is when I call it like this:
public void DoSomething()
{
var helper = new MyHelper(??????);
if (helper.CheckIt())
{
// Do Something
}
}
The problem I have tracking this down is practically everything that talks about DI is talking about it at the controller level. I tried hunting down where it happens in the Controller object source code, but it gets kinda crazy in there.
I do know I can manually create an instance of IOptions and pass it to the MyHelper constructor, but it seems like I should be able to get the framework do that since it works for Controllers.
Below is a working example of using DI without anything that involves MVC Controllers. This is what I needed to do to understand the process, so maybe it will help somebody else.
The ShoppingCart object gets, via DI, an instance of INotifier (which notifies the customer of their order.)
using Microsoft.Extensions.DependencyInjection;
using System;
namespace DiSample
{
// STEP 1: Define an interface.
/// <summary>
/// Defines how a user is notified.
/// </summary>
public interface INotifier
{
void Send(string from, string to, string subject, string body);
}
// STEP 2: Implement the interface
/// <summary>
/// Implementation of INotifier that notifies users by email.
/// </summary>
public class EmailNotifier : INotifier
{
public void Send(string from, string to, string subject, string body)
{
// TODO: Connect to something that will send an email.
}
}
// STEP 3: Create a class that requires an implementation of the interface.
public class ShoppingCart
{
INotifier _notifier;
public ShoppingCart(INotifier notifier)
{
_notifier = notifier;
}
public void PlaceOrder(string customerEmail, string orderInfo)
{
_notifier.Send("admin#store.com", customerEmail, $"Order Placed", $"Thank you for your order of {orderInfo}");
}
}
public class Program
{
// STEP 4: Create console app to setup DI
static void Main(string[] args)
{
// create service collection
var serviceCollection = new ServiceCollection();
// ConfigureServices(serviceCollection)
serviceCollection.AddTransient<INotifier, EmailNotifier>();
// create service provider
var serviceProvider = serviceCollection.BuildServiceProvider();
// This is where DI magic happens:
var myCart = ActivatorUtilities.CreateInstance<ShoppingCart>(serviceProvider);
myCart.PlaceOrder("customer#home.com", "2 Widgets");
System.Console.Write("Press any key to end.");
System.Console.ReadLine();
}
}
}
Let's say MyHelper is used by MyService which in turn is used by your controller.
The way to resolve this situation is:
Register both MyService and MyHelper in Startup.ConfigureServices.
services.AddTransient<MyService>();
services.AddTransient<MyHelper>();
The controller receives an instance of MyService in its constructor.
public HomeController(MyService service) { ... }
MyService constructor will in turn receive an instance of MyHelper.
public MyService(MyHelper helper) { ... }
The DI framework will be able resolve the whole object graph without problems. If you are worried about new instances being created every time an object is resolved, you can read about the different lifetime and registration options like the singleton or request lifetimes.
You should be really suspicious when you think you have to manually create an instance of some service, as you might end up in the service locator anti-pattern. Better leave creating the objects to the DI Container. If you really find yourself in that situation (let's say you create an abstract factory), then you could use the IServiceProvider directly (Either request an IServiceProvider in your constructor or use the one exposed in the httpContext).
var foo = serviceProvider.GetRequiredService<MyHelper>();
I would recommend reading the specific documentation about the ASP.Net 5 DI framework and about dependency injection in general.
Unfortunately there is no direct way. The only way I managed to make it work is by creating a static class and using that everywhere else as below:
public static class SiteUtils
{
public static string AppName { get; set; }
public static string strConnection { get; set; }
}
Then in your startup class, fill it in as below:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
//normal as detauls , removed for space
// set my variables all over the site
SiteUtils.strConnection = Configuration.GetConnectionString("DefaultConnection");
SiteUtils.AppName = Configuration.GetValue<string>("AppName");
}
Although this is bad pattern, as this will stay for the whole life cycle of the application and I couldn't find better way to use it outside controller.
Here's a more complete example to directly answer the OP's question, based on the current .NET Core 2.2 DI documentation here. Adding this answer since it may help someone that's new to .NET Core DI, and because this question is Google's top search result.
First, add an interface for MyHelper:
public interface IMyHelper
{
bool CheckIt();
}
Second, update the MyHelper class to implement the interface (in Visual Studio, press ctrl-. to implement the interface):
public class MyHelper : IMyHelper
{
private readonly ProfileOptions _options;
public MyHelper(IOptions<ProfileOptions> options)
{
_options = options.Value;
{
public bool CheckIt()
{
return _options.SomeBoolValue;
}
}
Third, register the interface as a framework-provided service in the DI service container. Do this by registering the IMyHelper service with the concrete type MyHelper in the ConfigureServices method in Startup.cs.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<IMyHelper, MyHelper>();
...
}
Fourth, create a private variable to reference an instance of the service. Pass the service as an argument in the constructor (via constructor injection) then initialize the variable with the service instance. Reference any properties or call methods on this instance of the custom class via the private variable.
public class MessageCenterController : Controller
{
private readonly MyOptions _options;
private readonly IMyHelper _myHelper;
public MessageCenterController(
IOptions<MyOptions> options,
IMyHelper myHelper
)
{
_options = options.value;
_myHelper = myHelper;
}
public void DoSomething()
{
if (_myHelper.CheckIt())
{
// Do Something
}
}
}
You may use Activator.CreateInstance(). Here is a wrapper function for it. The way you use this is as follows.
var determinedProgrammatically = "My.NameSpace.DemoClass1"; // implements IDemo interface
var obj = CreateInstance<My.NameSpace.IDemo, string>(determinedProgrammatically, "This goes into the parameter of the constructor.", "Omit this parameter if your class lives in the current assembly");
Now you have an instance of obj which is instantiated from type determined programmatically. This obj can be injected into non controller classes.
public TInterface CreateInstance<TInterface, TParameter>(string typeName, TParameter constructorParam, string dllName = null)
{
var type = dllName == null ? System.Type.GetType(typeName) :
System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName.StartsWith(dllName, System.StringComparison.OrdinalIgnoreCase)).GetType(typeName);
return (TInterface)System.Activator.CreateInstance(type, constructorParam);
}
PS: You may iterate through System.AppDomain.CurrentDomain.GetAssemblies() to determine the name of the assembly that houses your class. This name is used in the 3rd parameter of the wrapper function.
TL;DR: You can save a singleton in a static var and then access it form other classes, but this an anti-pattern, use with caution.
Long version:
As per this question Resolving instances with ASP.NET Core DI from within ConfigureServices
Any services registered in ConfigureServices() can then be injected
into the Configure() method
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<FooService>();
}
public void Configure(IApplicationBuilder app, FooService fooService)
{
FooServiceInstance = fooService;
}
public static FooService FooServiceInstance { get; private set; }
And then call it from your other code MyStartupClass.FooService.DoStuff()

Create instance from web.config and with dependency injection in constructor with Ninject

I'm trying to create an instance of an object from a web.config configuration, like this:
<add name="Log4Net" type="Spm.Services.Logging.Log4NetServices.Log4NetReporting, Spm.Services" />
The type Log4NetReporting has a constructor with an argument I want to inject, like this:
public class NLogReporting : ILogReporting
{
[Inject]
public NLogReporting(IRepository<NLogError> nLogRepository)
{
this.nLogRepository = nLogRepository;
}
}
I was trying to create an instance of this object by doing this:
var logger = Activator.CreateInstance(type) as ILogReporting;
But I get an exception saying "No parameterless constructor has been define for this object".
Ideally, I would like to do this using Ninject but I don't know how. My code is separated in different assemblies so the Ninject initialization (look below) is in one assembly (the Web application assembly) and this code is in the Services assembly.
Here's my Ninject initialization code:
private static StandardKernel CreateNinjectKernel()
{
var kernel = new StandardKernel();
RegisterNinjectServices(kernel);
ConfigureAutoMapper(kernel);
return kernel;
}
private static void RegisterNinjectServices(IKernel kernel)
{
kernel.Bind<IRepository<NLogError>>().To<Repository<EntityDbContext, NLogError>>().InRequestScope();
}
Is this possible to do or am I just doing it all wrong?
/Ingo
ideally you would have ILogReporting injected into the service that would use it.
public class SomeService : ISomeService
{
private readonly ILogReporting _logger;
public SomeService(ILogReporting logger)
{
_logger = logger;
}
// .... code....
}
but if you need to request the instance at the time of execution, not creation, then you will need some way to access the DI container (the Ninject Kernel) from wherever you are trying to get the ILogReporting instance. Ninject's WebAPI integration wires its Kernel up to the System.Web.Mvc.IDependencyResolver, so we can use that.
public class SomeService : ISomeService
{
private readonly IDependencyResolver _resolver;
public SomeService(IDependencyResolver resolver)
{
_resolver = resolver;
}
public void Execute()
{
var logger = _resolver.GetService<ILogReporting>();
// .... code....
}
}

Dependency Injection for Presenter

I have a Presenter that takes a Service and a View Contract as parameters in its constructor:
public FooPresenter : IFooPresenter {
private IFooView view;
private readonly IFooService service;
public FooPresenter(IFooView view, IFooService service) {
this.view = view;
this.service = service;
}
}
I resolve my service with Autofac:
private ContainerProvider BuildDependencies() {
var builder = new ContainerBuilder();
builder.Register<FooService>().As<IFooService>().FactoryScoped();
return new ContainerProvider(builder.Build());
}
In my ASPX page (View implementation):
public partial class Foo : Page, IFooView {
private FooPresenter presenter;
public Foo() {
// this is straightforward but not really ideal
// (IoCResolve is a holder for how I hit the container in global.asax)
this.presenter = new FooPresenter(this, IoCResolve<IFooService>());
// I would rather have an interface IFooPresenter so I can do
this.presenter = IoCResolve<IFooPresenter>();
// this allows me to add more services as needed without having to
// come back and manually update this constructor call here
}
}
The issue is FooPresenter's constructor expects the specific Page, not for the container to create a new one.
Can I supply a specific instance of the view, the current page, to the container for just this resolution? Does that make sense to do, or should I do this another way?
The way to solve passing what I like to call data parameters when resolving dependencies in Autofac is by using generated factories.
(Update: this question discusses the same problem and my article shows how you can avoid large amounts of factory delegates).
The solution to your problem will look something like this:
First, declare a factory delegate thath only accepts the data parameters:
public delegate IFooPresenter FooPresenterFactory(IFooView view);
Your presenter goes unchanged:
public FooPresenter : IFooPresenter {
private IFooView view;
private readonly IFooService service;
public FooPresenter(IFooView view, IFooService service) {
this.view = view;
this.service = service;
}
}
Next the Autofac container setup:
var builder = new ContainerBuilder();
builder.Register<FooService>().As<IFooService>().FactoryScoped();
builder.Register<FooPresenter>().As<IFooPresenter>().FactoryScoped();
builder.RegisterGeneratedFactory<FooPresenterFactory>();
Now in your page you can in two lines of code resolve the presenter by first getting the factory and then calling the factory to do the resolution for you:
public partial class Foo : Page, IFooView {
private FooPresenter presenter;
public Foo() {
var factory = IoCResolve<FooPresenterFactory>();
this.presenter = factory(this);
}
}
I actually solved this exact problem and built a framework around it. I used Autofac parameters to pass existing views to the presenter resolution call.
First, I defined a custom resolution interface derived from Autofac's:
public interface IMvpContext : IContext
{
T View<T>();
}
which allowed me to register a presenter which resolves the view:
builder.RegisterPresenter(c => new FooPresenter(
c.View<IFooView>(),
c.Resolve<IFooService>()));
using an extension method which wraps Autofac's IContext in an implementation of IMvpContext:
public static IConcreteRegistrar RegisterPresenter<T>(
this ContainerBuilder builder,
Func<IMvpContext, T> creator)
{
return builder
.Register((context, parameters) => creator(new MvpContext(context, parameters)))
.FactoryScoped();
}
I defined a parameter type representing the view parameter:
public class MvpViewParameter : NamedParameter
{
public static readonly string ParameterName = typeof(MvpViewParameter).AssemblyQualifiedName;
public MvpViewParameter(object view) : base(ParameterName, view)
{}
}
It uses its own assembly-qualified type name as the parameter name. This has a very low likelihood of conflicting with legitimate parameters.
MvpContext passes all standard resolution calls to the base context. For the view, it resolves the parameter with the well-known name:
public sealed class MvpContext : IMvpContext
{
private IContext _context;
private IEnumerable<Parameter> _resolutionParameters;
public MvpContext(IContext context, IEnumerable<Parameter> resolutionParameters)
{
_context = context;
_resolutionParameters = resolutionParameters;
}
#region IContext
// Pass through all calls to _context
#endregion
#region IMvpContext
public T View<T>()
{
return _resolutionParameters.Named<T>(MvpViewParameter.ParameterName);
}
#endregion
}
The call to resolve the presenter provides the view parameter:
public partial class Foo : Page, IFooView
{
private readonly FooPresenter presenter;
public Foo()
{
this.presenter = IoCResolve<IFooPresenter>(new MvpViewParameter(this));
}
}

Categories