Autofac lazy property injection - asp.net

I'm trying to inject business logic implementations into web API base controller. Somehow property in base controller is always null.
Also how can I do lazy injection?
Startups.cs
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<ViewBusinessLogic>().As<IViewBusinessLogic>().
PropertiesAutowired();
containerBuilder.Populate(services);
var container = containerBuilder.Build();
return container.Resolve<IServiceProvider>();
}
Interface, implementation and base controller:
public interface IViewBusinessLogic
{
IEnumerable<dynamic> GetView(Guid viewId);
}
public class ViewBusinessLogic : BusinessLogic, IViewBusinessLogic
{
public IEnumerable<dynamic> GetView(Guid viewId)
{
return new List<dynamic>
{
new { Test = "Test1" },
new { Test = "Test2" }
};
}
}
public abstract class BaseController : Controller
{
public IViewBusinessLogic ViewBusinessLogic { get; }
}

Controllers aren't resolved by the DI framework by default. You need to add AddControllerAsServices to have them be resolved by the DI of your choice.
From this GitHub issue:
Hi,
Maybe I'm wrong but as I tested deeply (and checked Mvc source code), Controllers are not resolved from IServiceProvider, but only constructor arguments of them are resolved from IServiceProvider.
Is that by design? I'm very suprised. Because, I'm using a different DI framework which supports property injection. And I can not use property injection since Controller instances are not requested from IServiceProvider.
Have you added AddControllersAsServices in your Startup (https://github.com/aspnet/Mvc/blob/ab76f743f4ee537939b69bdb9f79bfca35398545/test/WebSites/ControllersFromServicesWebSite/Startup.cs#L37)
The example above quoted for future reference.
public void ConfigureServices(IServiceCollection services)
{
var builder = services
.AddMvc()
.ConfigureApplicationPartManager(manager => manager.ApplicationParts.Clear())
.AddApplicationPart(typeof(TimeScheduleController).GetTypeInfo().Assembly)
.ConfigureApplicationPartManager(manager =>
{
manager.ApplicationParts.Add(new TypesPart(
typeof(AnotherController),
typeof(ComponentFromServicesViewComponent),
typeof(InServicesTagHelper)));
manager.FeatureProviders.Add(new AssemblyMetadataReferenceFeatureProvider());
})
// This here is important
.AddControllersAsServices()
.AddViewComponentsAsServices()
.AddTagHelpersAsServices();
services.AddTransient<QueryValueService>();
services.AddTransient<ValueService>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
As for the second part of your question: I don't think it's possible to have lazy instantiation via IoC container at all. Best fit for you is to create a factory class and inject the factory rather than the concrete service.
But usually you don't need lazy instantiation anyways, the instantiation of services should be fast. If it's not, you probably doing some funky stuff in the constructor (connecting somewhere, or doing other long running operations), which is an anti-pattern.

Related

How do I instantiate class with dependency injection in .net core 5 or 6?

In a .net core 5 or 6 api, if I have a dependency:
services.AddScoped<IMyDependency>((svc) =>
{
return new MyDependency(appSettings.ConnectionStrings.MyDB);
});
and I have a class that uses the dependency:
public class MyClass
{
public MyClass(IMyDependency dependency)
{
...
}
}
How do I instantiate the class so that the dependency is injected into the constructor? In a controller, this is done for me when the controller is instantiated. How do I do it for my own classes?
I can use services.GetServices explicitly, but I think that is frowned upon.
I can use services.GetServices explicitly, but I think that is frowned
upon.
Yes, this is the documented way to do it:
Services and their dependencies within an ASP.NET Core request are
exposed through HttpContext.RequestServices.
Source
HttpContext.RequestServices is of type IServiceProvider which offers the GetService method.
But it is also adviced not to do it:
Avoid using the service locator pattern. For example, don't invoke
GetService to obtain a service instance when you can use DI instead
Source
This won't be done by default. If you are trying to use something that is injected into the request pipeline, you would have to pass that injected value in the controller and pass it on to the constructor.
public class HomeController : Controller
{
private IMyDependency _dependency;
public HomeController(IMyDependency dependency)
{
_dependency = dependency;
}
[Route("")]
public IActionResult Index()
{
MyClass myclass = new MyClass(_dependency);
....
return View(myclass.stuff);
}
Add the class and its dependencies to the service collection, then inject it into your methods or use the IServiceProvider GetRequiredService
eg.
public class MyClass
{
public MyClass(IMyDependency dependency)
{
...
}
}
...
startup.cs
services.AddScoped<IMyDependency, MyDependency>();
services.AddScoped<MyClass>()
...
[Route("home")]
public IActionResult Index([FromServices]MyClass myClass)
{
var result = myClass.DoStuff();
....
return View(result);
}

Dependency injection in my singleton class .NET Core

I'm having trouble injecting the dependency I pass into the constructor of my Asegurador class.
When I want to instantiate, _instance = new Asegurador(); I don't have the parameter required by the constructor (IGeneralRepository), how can I solve this problem?
Note that my Asegurador class is a singleton.
private Asegurador(IGeneralRepository generalRepository)
{
_token = GetTokenAsync().Result;
_repository = generalRepository;
}
public static Asegurador Instance
{
get
{
if (_instance == null)
{
_local = System.Environment.GetEnvironmentVariable("SEGUROS_LOCAL") ?? "local";
_instance = new Asegurador();
}
return _instance;
}
}
When using a DI container you can (and should) let it take care of handling the Lifetime of a dependency.
.Net core's dependency injection lets you define 3 different lifetimes for your services (Docs):
Transient: a transient service is recreated each time it is injected
Scoped: a scoped service is created once for each request
Singleton: a singleton is created once in the whole application lifetime.
The best approach to achieve what you are trying to do is the following:
Amend your Asegurador class so that it has a public constructor and get rid of the static Instance property
public class Asegurador {
public Asegurador(IGeneralRepository generalRepository)
{
_token = GetTokenAsync().Result; //I know too few about it but I would try to pass it as a dependency as well
_repository = generalRepository;
}
}
instead of calling Asegurador.Instance inject the dependency in the client class
public class IUseTheAsegurador {
private Asegurador _asegurador;
public IUseTheAsegurador(Asegurador asegurador)
{
_asegurador = asegurador;
}
}
Register all in the DI in your Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSingleton<Asegurador>();
services.AddScoped<IUseAsegurador>(); //This can be Singleton or Transient as well, depending on your needs
...
}
I (a lot of people actually :D) prefer this approach because it leaves the responsability of guaranteeing a single instance to the DI and also because lets you write unit tests for the client class (IUseTheAsegurador in the example) in an easier way.

Dependency injection for non controller classes and calling them

Trying to wrap my head around dependency injection, coming from the world of static classes and instantiated classes. Here is what I currently have:
[SomeFilter]
public class AController : Controller
{
private readonly IOptions<AppSettings> _appSettings;
public AController(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings;
}
// GET: /characters/
public IActionResult Index()
{
//do something
}
SomeFilter gets called immediately, and does this:
public class SomeFilter: ActionFilterAttribute, IActionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
OtherClass.RunMe();
}
}
OtherClass looks like this:
public class OtherClass
{
private readonly IOptions<AppSettings> _appSettings;
public OtherClass(IOptions<AppSettings> appSettings)
{
_appSettings = appSettings;
}
public RunMe()
{
//do something
}
I also have OtherClass registered as a service.Singleton in the Startup.cs.
I get an error stating:
"An object reference is required for a non-static field"
for the OtherClass.RunMe(); call.
I was under the assumption that I can call this class from anywhere within my code instead of having to create a new instance of it? Essentially, how do I call methods from other classes using dependency injection?
You can't constructor injection on filters. It's all about run time order. When you try injection on constructor, your IoC container not reachable at the moment. You should be use property/setter injection.
I prefer using structuremap container for to do this. Because structuremap has very easy to apply any type injection. For example when you have a filter registry like this
public class ActionFilterRegistry : Registry
{
public ActionFilterRegistry(Func<IContainer> containerFactory)
{
For<IFilterProvider>().Use(
new StructureMapFilterProvider(containerFactory));
Policies.SetAllProperties(x =>
x.Matching(p =>
p.DeclaringType.CanBeCastTo(typeof(ActionFilterAttribute)) &&
p.DeclaringType.Namespace.StartsWith("YourNameSpace") &&
!p.PropertyType.IsPrimitive &&
p.PropertyType != typeof(string)));
}
}
And you register it on your global.asax(prefer) or one of your startup class.
Example app_Start method.
DependencyResolver.SetResolver(new StructureMapDependencyResolver(() => Container ?? ObjectFactory.Container));
ObjectFactory.Container.Configure(cfg =>
{
cfg.AddRegistry(new StandardRegistry());
cfg.AddRegistry(new ControllerRegistry());
cfg.AddRegistry(new ActionFilterRegistry(() => Container));
cfg.AddRegistry(new MvcRegistry());
});
Then you can use any filter with injection. But pay attention you shouldn't be use contructor injection like you do.
I found a way to inject into the filter by using
[ServiceFilter(typeof(MyFilter))]
instead of just
[MyFilter]
and within the filter's
(ActionExecutingContext context)
{
var controller = context.Controller as Controller.
controller.whateverIneed
}
This now provides me with what I need within the filter. What I also realized is that I can't remove the need for creating references to other classes using new, as I was under the impression Core's dependency was all about "no more new". This gets into fundamentals with Core which I'm still grasping with.
What I ended up doing was creating new classes that do some work, but they are setup as services and registered in the startup.cs. I'm still grappling on how to intermingle registered services (which I can inject) and new instances of worker classes (which usually hold static information), and passing information between them all.

Creating a Unity DependencyResolver for SignalR

I'm using SignalR 0.5.2 and I'm trying to get a DependencyResolver set up using Unity. I've written the simplest code I can. I have a hub that I'm trying to inject into which looks like this:
public class SimpleHub : Hub
{
private readonly ITestService _service;
public SimpleHub(ITestService service)
{
_service = service;
}
public void Update()
{
Clients.callback("Kevin");
}
}
and a DependencyResolver that looks like this:
public class UnityDependencyResolver : DefaultDependencyResolver
{
private readonly IUnityContainer _container;
public UnityDependencyResolver(IUnityContainer container)
{
_container = container;
}
public override object GetService(Type serviceType)
{
if (_container.IsRegistered(serviceType))
{
return _container.Resolve(serviceType);
}
return base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
if (_container.IsRegistered(serviceType))
{
return _container.ResolveAll(serviceType);
}
return base.GetServices(serviceType);
}
}
I register the dependency resolver in Global.asax
protected void Application_Start()
{
IUnityContainer container = new UnityContainer();
InitializeContainer(container);
SignalR.IDependencyResolver resolver = new UnityDependencyResolver(container);
GlobalHost.DependencyResolver = resolver;
RouteTable.Routes.MapHubs();
// more MVC stuff here
}
where InitializeContainer register the ITestService in Unity
The resolver "works" in that it's getting called for all the SignalR types, and if I leave my hub with a default constructor it all gets loaded. However the resolver never gets asked to resolve the ITestService interface.
I've also tried passing the resolver to MapHubs, still no luck. I've also tried property injection using the [Dependency] attribute and that didn't work either.
Do I need to register the resolver with MVC as well? (I have tried that by implementing both IDependecyResolver interfaces but get an exception telling me the resolver doesn't implement IServiceLocator)
So I've sort of fixed this. I wondered if the fact that the Hub was registered with the signalr container and the interface was registered with the Unity container was causing the issue. So I registered the Hub with Unity and then everything works.
This sort of makes sense as there are two containers.
Is this the standard behaviour?
In case someone else is wondering... I found a good SPA example that uses
SignalR 1.0.1
Unity 3
A bunch of other frameworks
The interesting thing is the way he create the container, the dependencies and everything else. Worth checking it out.

How do I Inject Dependencies with Ninject, where instances are deserialised from json

This is my first try using DI, I've chosen ninject for it's reportedly easy learning curve, and have this question.
I'm creating objects like this:
var registrants = JsonConvert.DeserializeObject<List<Registrant>>(input);
I currently have this constructor for Registrant
[Inject]
public Registrant(IMemberRepository memberRepository)
{
_memberRepository = memberRepository;
}
What is the best way to have the repository dependency be injected into the deserialized object(s) using Ninject?
You can't use constructor injection with objects that are not created by Ninject (e.g. deserialized objects). But you can use property injection. Just call kernel.Inject(obj)
One question that remains is why you want to inject those objects. Normally, you don't want to use depedency injection on data container objects. In a proper design they don't have any dependency on services. The operations that need to be done on the services are done by the owner of the data container objects. I recommend to consider a refactoring of your design.
Assuming you're using Ninject V2, and you're using it in the context of an ASP.NET app, you should be using Ninject.Web to do the hookups.
Then you set up a Global class with the Factory Method support hooked in:
public class Global : NinjectHttpApplication
{
protected override Ninject.IKernel CreateKernel()
{
var kernel = new StandardKernel( new Module() );
kernel.Components.Add( new FuncModule( ) );
return kernel;
}
}
that registers the module that will Bind IMemberRepository to something:
public class Module : NinjectModule
{
public override void Load()
{
Bind<IMemberRepository>().To<MemberRepository>();
}
}
and the page wires up like this:
public class ThePage : PageBase
{
readonly Func<Registrant> _createRegistrant;
public ThePage( Func<Registrant> createRegistrant )
{
_createRegistrant = createRegistrant;
}
private void OnCreateRegistrant()
{
var newRegistrant = _createRegistrant();
}
}
NB not 100% sure if constructor injection is supported for Web Forms pages or wheter the above needs to drop to property injection... anyone?
(assuming the classes you have are as follows:)
public class MemberRepository : IMemberRepository
{
}
public interface IMemberRepository
{
}
public class Registrant
{
private readonly IMemberRepository _memberRepository;
public Registrant( IMemberRepository memberRepository )
{
_memberRepository = memberRepository;
}
}

Resources