Blazor (server side) dependency injection in controller - c#

I'm programming using Server-side Blazor. In program.cs I have this to register the service:
builder.Services.AddScoped<MyClass>();
Then, I have a controller page (not a razer component page) with this definition (using the class in the constructor for the object to be injected):
public class DownloadController : Controller
{
private readonly MyClass _myobject;
public DownloadController(MyClass myobject)
{
this._myobject = myobject;
}
}
The problem is that "myobject" is always null, as if dependency injection is not working for the controller. If I inject the object in a razor component page (using #inject Myclass myobject), it works without a problem.
Any ideas about what is going on?
Edit: after doing some experiments, injection works if I change AddScoped to AddSingleton. The problem is that the object shouldn't be a singleton class, it should be created and disposed during the scope of the Blazor circuit. It seems I'm lacking some fundamentals behind the scenes? Could someone explain why it'd work with AddSingleton and not with AddScoped.

Related

Inject controllers that implements an interface

In ASP.NET Core MVC all classes that implement Controller will be automatically resolved and added to the MVC pipeline. These controllers can also be injected into the DI container using services.AddMvc().AddControllersAsServices();
I also have a controller that also implements a specific interface, which I can also add to the DI container: services.AddSingleton<IMyInterface, MyImpl>();
public class MyImpl : Controller, IMyInterface { }
However, becase this controller also implements Controller it has already been added in AddControllersAsServices() so adding it to the DI container one more time causes there to be two instances of this class.
The reason for this design is that I will have multiple implementations of IMyInterface and later need to decide which one to use, but each implementation will also need to be a controller in order to provide certain API endpoints (each controller will provide different endpoints, so there will be no conflicts there).
How can I ensure that only one instance of my class is instantiated, and how can I then get all implementations of IMyInterface?
As much as Im concerned Controller class is instantiated on each request, so even if you specify something like this (Ninject style):
services.Bind<IMyInterface, MyController>().To<MyController>().InSingletonScope();
It will be very bad. I mean, Controller is statefull, and you just mix everything up and breaking it's internal context.
What you might do is decorate through controller, instead of managing its lifetime yourself:
public class MyImpl : IMyInterface
{
}
public class MyController : Controller
{
private readonly IMyInterface _inner; //delegate implementation to this one.
public MyController(IMyInterface inner)
{
_inner = inner;
}
}
And injection:
services.Bind<IMyInterface>().To<MyImpl>().InSingletonScope();//this is your logic.
sercices.Bind<MyController>().ToSomethingWhatever();//this line is managed by ASP .NET, mentioned this only to show the idea
You might need remove the MyImpl inheriting from Controller class. Also you need to consider MyImpl as sevice rather than Controller.
Another option is that this can be achieved with IoC container like Autofac or Ninject or Castle Windsor. When using with Autofac it will be something like the below
Add the Autofac, Autofac ASP.Net MVC4 Integration using NuGet Package
Open GLobal.asax.cs
Make following changes in the Application_Start().
3a. Comment out the below code as
//WebApiConfig.Register(GlobalConfiguration.Configuration);
3b. Create a new method RegisterAutofac(), call this as the first method call inside Application_Start()
3c. Below with the sample implementation for RegisterAutofac() method
private void RegisterAutofac()
{
var builder = new Autofac.ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterSource(new ViewRegistrationSource());
// The object to be injected in constructor etc.
builder.RegisterType<MyImpl>().As<IMyInterface>().SingleInstance();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}

Declaring constructor inside Controller inheriting ControllerBase

I'm working on web application project which uses ASP.NET Core 2.1. Along with developing the API we are also trying to Unit test it using MSTest framework.
My Controllers are inheriting from ControllerBase. In my Test Bench I'm mocking my Business Layer using Moq Framework. When I'm calling the Controller from the test method, I need to pass a Mocked Business instance to the controller, for which I'm trying to declare parameterized constructor.
It's working fine for test cases, but my normal flow is disturbed. I even tried using both parameterized and parameterless constructors.
This works fine with Dot Framework which inherits APIController.
public class BookingController: ControllerBase {
BusinessManager business = new BusinessManager();
//Non-Parameterized Constructor
public BookingController() {}
//Parameterized Constructor
public BookingController(BusinessManager mockedBusiness) {
this.business = mockedBusiness;
}
}
A non-parameterized constructor should be used when called from UI.
Parameterized should only work when called from Test Bench passing some instance.
In the original code, the
BusinessManager business = new BusinessManager();
was tightly coupling the controller to the dependency, and is considered a code smell. Which is why you ended up having to try a work around in order to be able to test the controller in isolation.
Use the explicit dependency principle and keep the parameterized constructor
public class BookingController: ControllerBase {
private readonly BusinessManager business;
//Parameterized Constructor
public BookingController(BusinessManager business) {
this.business = business;
}
//...
}
In Startup, register you dependency with the service collection
public void ConfigureServices(IServiceCollection services) {
//...
services.AddScoped<BusinessManager>();
//...
}
The will allow the framework to inject the required dependency at run time when the controller is created in your normal flow, and also allows the controller to be flexible enough to be tested in isolation with your mocked business instance.

Can I resolve a scoped instance from inside a singleton instance in asp.net 5

I've been using a trick for a while to help with maintaining an audit trail. In or before the controller, I create a User which is bound in some way to the request. I can use DI to create most of my application as singletons and I can just inject a Func<User> wherever I think I need User information. I get the per-request User from the Func and can easily add audit information to everything.
This keeps my domain classes User agnostic and lets my DI container act as a User management system.
Now I'm using asp.net 5 and I'm having trouble doing the same thing. Honestly I've never been sure I should be able to do this, but I've gotten used to it.
I'm trying to do something like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddScoped<IUser, User>();
services.AddSingleton<IDependantOnUser, DependantOnUser>
services.AddScoped<Func<IUser>(c => c.GetRequiredService<IUser>);
}
Then in or before my controller I create and populate the user instance.
public class ValuesController : Controller
{
public ValuesController(Func<User> userFunc)
{
user = userFunc();
// hydrate user instance as needed
}
}
Then finally, I should have access to the user instance in my singleton object.
public class DependantOnUser : IDependantOnUser
{
public DependantOnUser(Func<User> userFunc)
{
user = userFunc();
// I want this to be the same instance as that generated by the controller
}
}
But I can't get this to work. Before asp.net 5, I've been using Autofac to achieve this, but haven't had any luck there. I've tried playing around with transient/scoped/singleton a bit with no luck. I've even tried resolving my own IServiceProvider and using it directly instead of just generating a user with c => c.GetRequiredService<IUser>
Everything I do seems to be working with the wrong IServiceProvider instance. Is there a way resolve an instance from a different ServiceProvider? Any other suggestions would also be helpful.
Before you suggest I just register everything using AddScoped(), some of the objects between my presentation and persistence layers work a lot better as singletons.
Also I would prefer not to just pass User information as a parameter to every method in my domain (we record it with nearly every CRUD operation and pass it with most external calls we make)
I believe that it is antipattern to inject scope depedency to singleton one, please refer to Captive Dependencies
Autofac Captive Dependencies

Using MEF with MVC

I'm starting to use MEF with my MVC application, so that it follows SOLID priciples.
I asked this question last week: Should a dependency be injected many "levels" up than it is needed? and part of what I asked (in the comments) was, if you have two constructors;
One constructor for Dependancy Injection
Another construtor with no parameters
And the contstructor with no parameters instantiates instances of the dependancies needed, then this should make a Service Locator moot. The response was that a class should not instantiate it's own dependancies. OK, I get this, but looking at this MS tutorial on MEF:
http://msdn.microsoft.com/en-us/library/hh708870(v=vs.110).aspx
They say you should have two constructors:
public HomeController() : this(new TraceLogger())
{
}
public HomeController(ILogger logger)
{
_logger = logger;
}
But from what I've been told, the first constructor is a no-no as the class is instantiating it's own dependacy?
Also, in the tutorial, MS just say; replace the second construtor with this:
public HomeController([Import("myTraceLogger")]ILogger logger)
{
_logger = logger;
}
What's the point in that? I still have to supply an instance of of the ILogger... unless I'm missing something? I removed the default constructor:
public HomeController() : this(new TraceLogger())
{
}
And the application just says: "No parameterless constructor defined for this object."
So I must have to supply an instance, because if MEF was creating a new instance, surly it would work without a default constructor... and if not, what's the point in using MEF? I might as well just do the dependancy injection myself.
Sounds like you need to use [ImportingConstructor] attribute on your HomeController(ILogger) constructor. Like so:
[ImportingConstructor]
public HomeController([Import("myTraceLogger")]ILogger logger)
{
_logger = logger;
}
MEF creates a singleton instance of ILogger (by default). It will make sure to create ILogger before it creates your HomeController class.
A service locator is convenient when you are creating a list of objects with exported types as part of some run-time workflow.
OK. So you could use MEF to do Dependancy Injection and inject the parts, but personally I wouldn't. The performance i've seen on it is pretty dire. If you use it wrongly it can also leak and consume memory easily.
You can apply your solid principals with other techniques. Use a well know Inversion of Control (IoC) container, such as StructureMap or AutoFac. You can add the nuget package to your MVC app, write a few lines of setup code in the global asax and your constructors will automagically work. These are also much more forgiving and easier to setup and configure.
When you application starts up and creates the IoC container (or when the object is first requested depending on your settings), the dependency is 'Newed' up and injected into your class constructor. Effectively you don't need to do much other than tell the IoC container where to find an instance of a Logger class (i.e. in which assembly) if you class requests an ILogger.
public HomeController(ILogger logger)
{
_logger = logger;
}
Check out these posts.
Structure Map website
How do I get StructureMap working with an
AngularJs / MVC5 and WebApi2 web project
How to configure
StructureMap for asp.net MVC 5

C# ASP.NET Dependency Injection with IoC Container Complications

I apologise for the length, and I know there are some answers on this but I searched a lot and haven't found the right solution,
so please bear with me.
I am trying to create a framework for legacy applications to use DI in ASP.NET webforms. I will probably use Castle Windsor
as the framework.
These legacy applications will use in part an MVP pattern in some places.
A presenter would look something like this:
class Presenter1
{
public Presenter1(IView1 view,
IRepository<User> userRepository)
{
}
}
Now the ASP.NET Page would look something like this:
public partial class MyPage1 : System.Web.UI.Page, IView1
{
private Presenter1 _presenter;
}
Before using DI I would instantiate the Presenter as follows in the OnInit of the page:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
_presenter = new Presenter1(this, new UserRepository(new SqlDataContext()));
}
So now I want to use DI.
First I must create a handler factory to override the construction of my page.
I found THIS really good answer to help:
How to use Dependency Injection with ASP.NET Web Forms
Now I can easily set up my containers in my composition root as Mark Seeman suggest to use the Global.asax
(This means though to create a static container that must be thread safe and sealed not to be able to add further registrations)
Now I can go and declare the constructor injection on the page
public MyPage1() : base()
{
}
public MyPage1(Presenter1 presenter) : this()
{
this._presenter = presenter;
}
Now we run into the first problem, I have a circular dependency.
Presenter1 depends on IView1, But the page depends on the presenter.
I know what some will say now that the design is probably incorrect when you have circular dependencies.
First I dont think the Presenter design is incorrect, by it taking a dependency in the constructor to the View, and I can say this
by looking at plenty of MVP implementations.
Some may suggest changing the Page to a design where Presenter1 becomes a property and then using Property injection
public partial class MyPage1 : System.Web.UI.Page, IView1
{
[Dependency]
public Presenter1 Presenter
{
get; set;
}
}
Some may even suggest removing the dependency to presenter completely and then simply Wiring up via a bunch of events, But this is
not the design I wanted and frankly dont see why I need to make this change to accomodate it.
Anyway regardless of the suggestion, another problem exists:
When the Handler factory gets a page request only a type is available (NOT THE VIEW INTERFACE):
Type pageType = page.GetType().BaseType;
now using this type you can resolve the Page via IoC and its dependencies:
container.Resolve(pageType)
This will then know that there is a property called Presenter1 and be able to inject it.
But Presenter1 needs IView1, but we never resolved IView1 through the container, so the container won't know
to provide the concrete instance the handler factory just created as it was created outside of container.
So we need to hack our handler factory and replace the view interface:
So where the handler factory resolves the page:
private void InjectDependencies(object page)
{
Type pageType = page.GetType().BaseType;
// hack
foreach (var intf in pageType.GetInterfaces())
{
if (typeof(IView).IsAssignableFrom(intf))
{
_container.Bind(intf, () => page);
}
}
// injectDependencies to page...
}
This poses another problem, most containers like Castle Windsor will not allow you to reregister this interface
to the instance it is pointing to now. Also with the container being registered in the Global.asax, it is not thread-safe to
do as the container should be read only at this point.
The other solution is to create a function to rebuild the container on each web request, and then check to see
if the container contains the component IView if not set the instance. But this seems wasteful and goes against suggested use.
The other solution is to create a special Factory called
IPresenterFactory and put the dependency in the page constructor:
public MyPage1(IPresenter1Factory factory) : this()
{
this._presenter = factory.Create(this);
}
The problem is that you now need to create a factory for each presenter and then make a call to the container
to resolve other dependencies:
class Presenter1Factory : IPresenter1Factory
{
public Presenter1Factory(Container container)
{
this._container = container;
}
public Presenter1 Create(IView1 view)
{
return new Presenter1(view, _container.Resolve<IUserRepository>,...)
}
}
This design also seems cumbersome and over complicated, does any one have ideas for a more elegant solution?
Perhaps I misunderstand your problems, but the solution seems fairly simple to me: promote the IView to a property on the Presenter1:
class Presenter1
{
public Presenter1(IRepository<User> userRepository)
{
}
public IView1 View { get; set; }
}
This way you can set the presenter on the view like this:
public Presenter1 Presenter { get; set; }
public MyPage1()
{
ObjectFactory.BuildUp(this);
this.Presenter.View = this;
}
Or without property injection, you can do it as follows:
private Presenter1 _presenter;
public MyPage1()
{
this._presenter = ObjectFactory.Resolve<Presenter1>();
this._presenter.View = this;
}
Constructor injection in Page classes and user controls will never really work. You can get it to work in full trust (as this article shows), but it will fail in partial trust. So you will have to call the container for this.
All DI containers are thread-safe, as long as you don't manually add registrations yourself after the initialization phase and with some containers even that is thread-safe (some containers even forbid registering types after initialization). There would never be a need to do this (except for unregistered type resolution, which most containers support). With Castle however, you need to register all concrete types upfront, which means it needs to know about your Presenter1, before you resolve it. Either register this, change this behavior, or move to a container that allows resolving concrete types by default.

Categories

Resources