Best practice -- how to get back the internal binding from controller factory? - asp.net-mvc

I am following "ASP.Net MVC 3" by Steven Sanderson and Adam Freeman, and at one point they define ControllerFactory. The exposed interface is for creating controllers, and what is injected into them (like classes providing data) is black box (for outside world).
I am at the point, that I don't really want to get any controller, but the binding set for controller -- namely class providing data.
I could add another method for controller factory (like GetBinding) and it would work, but would it be the right way to do it?
Just to focus on something. I have IDataProvider and two classes -- MockupProvider and ProviderForReal. I would like to set it once, that for now whenever I need IDataProvider I will get MockupProvider. This is set up (by me) in controller factory.
And I would like to retrieve what I set up in most elegant way, so I won't bind again interface-class again. Is adding such method -- GetBinding -- to controller factor a good pattern?
I am not constructing the controller, I need binding controllers use.
In other words...
There is controller factory. Inside there are defined some bindings. I have to use retrieve them (binding, not controller). Technically I could do this in several ways:
take a look at the code, look at specific binding, and use the the bound type (hardcoding it) somewhere else
add public method to controller factory GetBinding
...?
What is the right way?
Update
My controller factory:
public class NinjectControllerFactory : DefaultControllerFactory
{
private IKernel ninject_kernel;
public NinjectControllerFactory()
{
ninject_kernel = new StandardKernel();
AddBindings();
}
private void AddBindings()
{
ninject_kernel.Bind<IBookRepository>().To<DataManagement.Concrete.EFBookRepository>();
// ninject_kernel.Bind<IBookRepository>().ToConstant(DataManagement.Mocks.Mocks.BookRepository);
}
public T GetBinding<T>()
{
return ninject_kernel.Get<T>();
}
protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
return null;
else
return (IController)ninject_kernel.Get(controllerType);
}
}

I'm trying to answer your questions following the comments. If it won't be suitable for you I'm prepared to delete it.
So in my ASP.NET MVC applications I'm using ninject and its mvc extension to inject dependencies to my controllers (and underlying services and repositories).
Global.asax
public class MvcApplication : Ninject.Web.Mvc.NinjectHttpApplication
{
/// this is here only to see that NinjectHttpApplication uses its own ControllerFactory, which is supposed to create your controllers with dependencies injected
protected override Ninject.Web.Mvc.NinjectControllerFactory CreateControllerFactory()
{
return base.CreateControllerFactory();
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
// here you can configure your bindings according to actual requirements
kernel.Bind<IDataProvider>().To<ProviderForReal>().InRequestScope();
kernel.Bind<IDataService>().To<RealDataService().InRequestScope();
return kernel;
}
}
Controller
public class MyController : Controller
{
private readonly IDataProvider dataService;
// i will get injected an IDataProvider according to my actual configuration
public MyController(IDataService dataService)
{
this.dataService = dataService;
}
}
IDataService
public class RealDataService: IDataService{
private readonly IDataProvider dataProvider;
public RealDataService(IDataProvider dataProvider){
this.dataProvider = dataProvider;
}
}
Update
You do not need to write your own controller factory. In the code above I have put my override of CreateControllerFactory method only to show that Ninject.Web.Mvc.NinjectHttpApplication implicitly overrides this method and uses its own NinjectControllerFactory implmentation which will resolve dependencies for you (even if that dependencies are indirect - as you can see in my updated code => Ninject will resolve it for you because it will see that MyController needs IDataService and will look into bindings and will see that there is binding to RealDataService, but it has only constructor with dependency on IDataProvider. So it will look again to bindings and will see that IDataProvider is bound to ProviderForReal than it will create ProviderForReal inject it to ReadDataService and than RealDataService to MyController).

Related

Net Core Dependency Injection for Non-Controller

Seems crazy that something like this is causing me such a headache. But here it is:
How do you use the built-in dependency injection for net core for a non-controller class? Please provide an example with includes instantiation.
Thanks.
Just make the class a service.
In startup.cs
services.AddScoped<AccountBusinessLayer>();
Then in controller, same as you do for other services:
private readonly AccountBusinessLayer _ABL;
Include in constructor as you do for other services:
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,IOptions<IdentityCookieOptions> identityCookieOptions,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory,
RoleManager<IdentityRole> roleManager,
AccountBusinessLayer ABL
)
{
_userManager = userManager;
_signInManager = signInManager;
_externalCookieScheme = identityCookieOptions.Value.ExternalCookieAuthenticationScheme;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
_roleManager = roleManager;
_ABL = ABL;
}
You can easily define a static class with one property like:
public static class StaticServiceProvider
{
public static IServiceProvider Provider { get; set; }
}
after defined class you have to scope the service in the Startup.ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
//TODO: ...
services.AddScoped<IUnitOfWork, HttpUnitOfWork>();
services.AddSingleton<ISomeInterface, ISomeImplementation>();
}
then inside the Startup.Configure method on startup you can set the provider as static class property:
public void Configure(IApplicationBuilder app, ...)
{
StaticServiceProvider.Provider = app.ApplicationServices;
//TODO: ...
}
Now you can easily call StaticServiceProvider.Provider.GetService method almost everywhere in your application:
var unitOfWork = (IUnitOfWork)StaticServiceProvider.Provider.GetService(typeof(IUnitOfWork));
I'm not sure this is the best answer, but the way I decided to do it is to do the following:
1) Per the answer by #BrunoLM at on this question Resolving instances with ASP.NET Core DI suggested by #SystemCrash, I created a new project called UnderstandingDependencyInjection and pasted in the code examples.
Important: What I describe next see next will not make sense unless you visit the referenced link above (#1). What you see below is a partial solution that builds on the answer another user provided in a another SO question.
2) Next, I created another class called OtherService. I added a method DoSomething() that took a dependency on the TestService.
3) In the constructor of OtherService, I requested IServiceProvider in order to get a concrete implementation of ITestService so I could call its GenerateRandom() method.
4) Back in the HomeController.cs, I merely passed along the IServiceProvider reference to the constructor of OtherService.
So, this is what I have:
OtherService.cs
using System;
using Microsoft.Extensions.DependencyInjection;
namespace UnderstandingDependencyInjection.Services
{
public class OtherService
{
private readonly ITestService _testService;
public OtherService(IServiceProvider serviceProvider)
{
_testService = serviceProvider.GetService<ITestService>();
}
public int DoSomething()
{
var rnd = _testService.GenerateRandom();
return rnd * 2;
}
}
}
HomeController.cs
using Microsoft.Extensions.DependencyInjection;
using UnderstandingDependencyInjection.Services;
namespace UnderstandingDependencyInjection.Controllers
{
public class HomeController : Controller
{
private readonly ITestService _testService;
private readonly IServiceProvider _serviceProvider;
public HomeController(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_testService = serviceProvider.GetService<ITestService>();
}
public IActionResult Index()
{
// This works!
// var rnd = _testService.GenerateRandom();
// What if I need to reference the TestService
// from another service? I.e., OtherService?
var otherService = new OtherService(_serviceProvider);
var rnd = otherService.DoSomething();
ViewBag.RandomNumber = rnd;
return View();
}
So, to summarize, the key to this technique is to pass around the concrete reference of IServiceProvider that your controller receives ... passing from the controller into any other custom classes that will also need any services that are registered into ASP.NET Core's DI framework.
What about static methods that depend on the TestService?
But, I may not want / need to create an instance of OtherService. I may want to merely call a method statically, but that method takes a dependency on a service managed by ASP.NET Core MVC's Dependency Injection framework. What now?
In this case, the best I can figure out, you would need to pass in the reference ON THE METHOD CALL to the static method. It looks nasty, and I'm hoping there's a more elegant way ... but here's what I figured out.
5) Building on the previous steps (above) I added a new class called StaticService.
6) I created a method DoSomething that takes IServiceProvider as a parameter.
7) I use the concrete instance of the IServiceProvider to get a concrete instance of the ITestService. I use this to call GenerateRandom().
8) From the controller, call the StaticService.DoSomething() method passing it the concrete instance of IServiceProvider that I'm holding on to.
StaticService.cs
using Microsoft.Extensions.DependencyInjection;
namespace UnderstandingDependencyInjection.Services
{
public class StaticService
{
// No constructors
public static int DoSomething(IServiceProvider serviceProvider)
{
var testService = serviceProvider.GetService<ITestService>();
var rnd = testService.GenerateRandom();
return rnd * 3;
}
}
}
HomeController.cs
public IActionResult Index()
{
// This works!
// var rnd = _testService.GenerateRandom();
// What if I need to reference the TestService
// from another service? I.e., OtherService?
//var otherService = new OtherService(_serviceProvider);
//var rnd = otherService.DoSomething();
// What if I need to reference the TestService
// from another service with a STATIC method?
// Best I can tell, you have to pass the
// ServiceProvider in on the method call.
var rnd = StaticService.DoSomething(_serviceProvider);
ViewBag.RandomNumber = rnd;
return View();
}
But isn't passing around ServiceProvider an anti-pattern?
In short, yes. You wind up passing ServiceProvider around everywhere in code. Some would argue that this gives every controller and ever class access to every service registered in ASP.NET Core's DI. That's true, and that seems bad.
But what are your alternatives? Should every class that has a dependency on your service ALSO be defined as a service and registered with the DI? In other words, should I create IOtherService, and then pass it a concrete ITestService in its constructor?
I could do that, HOWEVER now my controller's constructor needs BOTH ITestService AND IOtherService. In other words, in order to work correctly, the Controller needs to know how OtherService does its job and that it uses ITestService internally. That seems bad, too.
What to do?
What's the Best Answer?
Frankly, I think the best answer is found here:
Passing Services using Dependency Injection and Factory Pattern in ASP.NET
#Steven says in his answer:
It does mean however that you might need to move away from the built-in DI container of ASP.NET Core to a more feature rich DI library, because the built-in container is not capable of making a context aware registration for ILogger while having the library auto-wire other constructor dependencies as well.
There are actually many ways to inject your dependency, the most common one you will find on controllers. There is also this variant
var someService = (ISomeService)HttpContext.RequestServices.GetService(typeof(ISomeService));

How to use dependency injection with constructor parameter?

What is the right approach to use dependency injection when I want to also pass in a parameter to the constructor of a class?
For example, here I want an IApplicationService to be injected, but I also want to pass in an application id:
public class ApplicationViewModel
{
private readonly IApplicationService _applicationService;
private readonly int _applicationId;
public ApplicationViewModel(IApplicationService applicationService, int applicationId)
{
_applicationService = applicationService;
_applicationId = applicationId;
}
}
Currently, I'm using constructor injection on the controller and passing this on:
public class HomeController : Controller
{
private readonly IApplicationService _applicationService;
public HomeController(IApplicationService applicationService)
{
_applicationService = applicationService;
}
public ActionResult Application(int applicationId)
{
return View(new ApplicationViewModel(_applicationService, applicationId));
}
}
This works, but seems a bit ugly. The controller could have lots of action methods, each of which could require lots of services. The controller would end up getting a whole bunch of stuff injected that would mostly not be used. Also, I would rather be able to change what the view model needs injected without changing the controller.
I also tried using property injection on the view model, but it didn't work in MVC5 and property injection appears to be generally regarded as a Bad Idea™.
I'm sure the problem is that I'm not structuring the code properly. Any ideas?

Dependency injection in constructor of controller with using a ControllerFactory in ASP.NET MVC 5

I'm developing ASP.NET MVC 5 app. I need to use parameters in controller's constructor. DefaultControllerFactory can't resolve it and i inherited from it my own ControllerFactory:
public class ControllerFactoryProvider : DefaultControllerFactory
{
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
string controllerType = string.Empty;
IController controller = null;
// Read Controller Class & Assembly Name from Web.Config
controllerType = ConfigurationManager.AppSettings[controllerName];
if (controllerType == null)
throw new ConfigurationErrorsException("Assembly not configured for controller " + controllerName);
// Create Controller Instance
IDataTransmitter _dataTransmitter = new DataTransmitter();
controller = Activator.CreateInstance(Type.GetType(controllerType), _dataTransmitter) as IController;
return controller;
}
public void ReleaseController(IController controller)
{
//This is a sample implementation
//If pooling is used to write code to return the object to pool
if (controller is IDisposable)
{
(controller as IDisposable).Dispose();
}
controller = null;
}
}
I registered it in Global.asax:
ControllerBuilder.Current.SetControllerFactory(new
ControllerFactoryProvider());
But when i run my app it whatever use DefaultControllerFactory didn't see constructor with parameters.
Where can i have an error?
As I said in the comments, there is no need to override your controller factory. You just need to plug in your preferred dependency injection container.
I haven't had the opportunity to work with every dependency injection containers for .net but I'll try to give an objective answer.
Ninject
To set up Ninject in an asp.net Mvc 5 project is very straight forward.
Installing the nuget package
There's a very handy nuget package called Ninject.MVC5.
You can install it:
Using the manage nuget packages dialogue, or
By running Install-Package Ninject.MVC5 in the package manager console.
After installing Ninject.MVC5 you will see a new file in your solution in App_Start/ called NinjectWebCommon.cs. Here you can see what the contents of that file will end up being.
Wiring up your dependencies
Now that the package is installed you want to register your denpencies using ninject's api.
Let's say you have an IFoo interface and its implementation Foo
public interface IFoo
{
int Bar()
}
public class Foo : IFoo
{
public int Bar()
{
throw new NotImplementedException();
}
}
In your NinjectWebCommon class you're going to tell ninject how to resolve an IFoo interface:
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFoo>().To<Foo>();
}
Keep in mind that by default Ninject has implicit self binding of concrete types, that means that
If the type you’re resolving is a concrete type (like Foo above), Ninject will automatically create a default association via a mechanism called implicit self binding. It’s as if there’s a registration like this:
Bind<Foo>().To<Foo>();

ASP.NET MVC ViewHelpers and Dependency Injection

I'd like to create a ViewHelper to localize my ASP.NET MVC application. Something like this:
public class Translator
{
private readonly ITranslationRepository _repo;
public Translator(ITranslationRepository repo)
{
_repo = repo;
}
public static string Translate(TranslationEnum translationEnum)
{
return _repo.GetTranslation(translationEnum, Session.LanguageId);
}
}
Usage in a (Razor) View looks like this:
<p>#Translator.Translate(TranslationEnum.WelcomeMessage)</p>
Now the problem is of course, I cannot make the Translate method static, because I need to access the instance variable _repo.
How can I inject the repository into a ViewHelper so I can use it in a View like above?
The responsibility of the view is just to transform the data that comes back from the controller to a HTML structure. Views are hard (to impossible) to test automatically, so best is to keep them as dumb as possible.
Instead of using the Translator in your view, inject it into your controller and let the controller call the Translator. This solves a range of problems:
It keeps the view simple.
It improves maintainability.
It improves testability.
It improves the verifiability of your object graphs (because you don't fall back on static method calls or the Service Locator anti-pattern).
Long story short, add a property to the controller's view model and return that to the view. Example:
public class HomeController : Controller {
private readonly ITranslator translator;
public HomeController(ITranslator translator) {
this.translator = translator
}
public ActionResult Index() {
this.View(new HomeViewModel {
WelcomeMessage = this.translator.Translate(TranslationEnum.WelcomeMessage)
});
}
}
And your view can look as follows:
#model HomeViewModel
<p>#Model.WelcomeMessage</p>
first of all, the intention of your design is wrong because it violates the single responsibility principal. Why is a translator dependent on repository?
secondly, why do you need a translator, you can use asp.net globalization?
click me We should not reinvent the wheel.
thirdly, all the html helpers are extension methods which have to be static.
so my suggestion is if you have to use translator, please refactor the Translator class, decouple the repository from it then create a extension methods from there.
or you can use globalization, it sounds horrible to start with but trust me it's not as hard as it looks.
public class Translator
{
private static ITranslationRepository _repo;
public static ITranslationRepository Repo
{
get { /*check null here before return*/ return _repo; } set { _repo = Repo; }
}
public Translator()
{
}
public static string Translate(TranslationEnum translationEnum)
{
return _repo.GetTranslation(translationEnum, Session.LanguageId);
}
}

MVC3 - How to correctly inject dependencies with MVC3 and Ninject?

I am attempting to redesign an existing application using dependency injection with Ninject in MVC3. Here is a portion of the legacy behavior I'm having difficulty with (and yes I know its bad, that's why I'm trying to refactor it):
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
MyUserSession userSession = filterContext.HttpContext.Session[SESSIONKEY_USER] as MyUserSession;
// if session empty, rebuild user information
if (userSession == null)
{
string userName = HttpContext.User.Identity.Name;
userSession = new MyUserSession();
using (ADSearcher ad = new ADSearcher(ldapPath, excludeOUString.Split(',')))
{
// get basic user information from Active Directory
ADUserInfo aduser = MyActiveDirectorySearcher.GetUserRecord(userName);
// ... set several properties queries from AD...
userSession.propertyXYZ = aduser.propXYZ
}
// if user can proxy as another indivudual, set property
using (EDMContainer db = new EDMContainer())
{
if (db.Proxies.Any(p => p.ProxyLogin == userSession.userLogin))
userSession.CanProxy == true;
}
// save new user object to session
filterContext.HttpContext.Session[SESSIONKEY_USER] = userSession;
if(userSession.canProxy)
filterContext.Result = RedirectToAction("Proxy", "Home");
return;
}
}
So currently, the controller users several objects directly: Session, ActiveDirectorySearch, EF Database. I understand it would be better to create a class that exposes a single method "GetUser" masking all the complexity but I'm struggling with how to inject the dependencies.
If I create a class SomeUserProvider, it will also need access to the Session to check for existing user information, and then ActiveDirectorySearcher and Database to rebuild the user properties if session was empty.
My confusion is over the fact that the controller itself will need access to ActiveDirectorySearcher in other action methods and then other classes will also use the same database. Do I inject an IActiveDirSearchrer into the controller's constructor and then pass it down into the ISomeUserProvider? What about IMyDatabase? Is it also injected in controller constructor and passed down?
And last but not lease, ISessionWrapper? I know session is controversial, but I need to track who the current user is and who they are proxied as during each request (GETs and POSTs). So, does that get injected as well?
If the answer is yes to each of those, is it bad to have 3+ injected contstuctor parameters?
I realize my question may be vague, so please ask for clarification where needed. I am open to any and all suggestions and recommendations. My goal is to learn how to do it correctly.
Thanks.
I'm not certain if this is exactly what you're looking for, but this should get you started down the path of refactoring your app for DI
public class YourController : Controller
{
private readonly ISessionWrapper _sessionWrapper;
private readonly IActiveDirSearcher _adSearcher;
private readonly IMyDatabase _database;
public YourController(ISessionWrapper sessionWrapper,
IActiveDirSearcher adSearcher, IMyDatabase database)
{
this._sessionWrapper = sessionWrapper;
this._adSearcher = adSearcher;
this._database = database;
}
// now all actions in this controller have a _sessionWrapper,
// _adSearcher and _database
}
Then you have to bind your injections the Ninject way. Subclass your application from NinjectHttpApplication and override OnApplicationStarted and CreateKernel
public class MvcApplication : NinjectHttpApplication
{
// ...
protected override void OnApplicationStarted()
{
base.OnApplicationStarted();
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
protected override IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<ISessionWrapper>().To<YourSessionWrapperImplementation>();
kernel.Bind<IActiveDirSearcher>().To<YourADImplementation>();
kernel.Bind<IMyDataBase>().To<YourEDMContainerIThink>();
return kernel;
}
}
The implementations of these appear to be described in your question. However, you mentioned other actions (and other classes) depend on these implementations. Good news--the bindings in CreateKernel will take care of any missing dependencies elsewhere in your app. e.g.
public class MyActiveDirImplementation : IActiveDirSearcher
{
private readonly IMyDatabase _database;
// injected automagically WOOHOO!
public MyActiveDirImplementation(IMyDatabase database)
{
this._database = database;
}
public ADUserInfo GetUserRecord(string username)
{
return _database.GetSomeUserRecord(username);
}
}
You could, of course, similarly implement your ISessionWrapper or IMyDatabase

Resources