Resolve singleton generics where T is a controller that implements interface - dependency-injection

I have this situation:
public class MyController : Controller, ILoggable
{
private readonly ILogger<ILoggable> _logger;
public MyController(ILogger<ILoggable> logger)
{
this._logger = logger;
}
...
}
I want to resolve ILogger<ILoggable> as singleton and ILoggable as Transient.
In my startup I tried with this:
services.AddSingleton(typeof(ILogger<>), typeof(LoggerImpl<>));
But I am not able to resolve ILoggable because is a controller and I do not understand which is the best approach.
EDIT
Here is the problem:
I cannot declare ILogger<MyController> inside my controller because ILogger<ILoggable> is used in third part code. I try to explain better my problem without use dependency injiection.
I have a third part class that has a constructor like this>
Public ExternalClass(ILogger<ILoggable> logger) {…}
Now, in my controller I need to use this external class, but obviously I cannot do something like this:
public class MyController : Controller, ILoggable
{
private readonly ILogger<MyController> _logger;
public MyController(ILogger<MyController> logger)
{
this._logger = logger;
ExternalClass c = new ExternalClass(logger); //Here the error because logger is of type ILogger<MyController>, not ILogger<ILoggable>
}
...
}
I need to solve that via DI.
Can anyone help me please?
Thank you

Related

Dnn Dependency Injection - error occurred when trying to create a controller... make sure the controller has a parameterless public constructor

I have a Dnn module project for a Web API. In the startup I want to configure dependency injection for this module.
The error I get is: "An error occurred when trying to create a controller of type 'SchoolsController'. Make sure that the controller has a parameterless public constructor."
Inner exception is a bit clearer on the actual problem: "Unable to resolve service for type 'MyProj.Persistence.Context.PortfolioContext' while attempting to activate 'MyProj.Persistence.UnitOfWork.UnitOfWork'."
My guess is that this is because my UnitOfWork class constructor requires a DbContext?
My unit-of-work class looks like this:
public class UnitOfWork: IUnitOfWork, IDisposable
{
private readonly PortfolioContext context;
public UnitOfWork(PortfolioContext context)
{
this.context = context;
Schools = new SchoolRepository(context);
Users = new UserRepository(context);
}
}
My controller looks like this:
public class SchoolsController: BaseController
{
private readonly IUnitOfWork unitOfWork;
public SchoolsController(IUnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}
}
My startup class:
public class Startup : IDnnStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IUnitOfWork, UnitOfWork>();
}
}
I've tried to add the DbContext before adding the scoped UnitOfWork like this, but it didn't work:
services.AddSingleton<DbContext, PortfolioContext>((ctx) =>
{
return new PortfolioContext();
});
Any ideas how to do this in Dnn? Normally I would add the DBContext by doing something like this:
services.AddDbContext<DataContext>(x => x.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
But for some reason I cannot find the extension method AddDbContext anywhere in this context (Dnn, IDnnStartup, etc.)
EDIT:
Forgot to add that this is for Dnn 9.6.2 which targets .net 4.7.2
Turns out I wasn't far off.
Where I originally tried this:
services.AddSingleton<DbContext, PortfolioContext>((ctx) =>
{
return new PortfolioContext();
});
Should have actually been this:
services.AddSingleton<PortfolioContext>((ctx) =>
{
return new PortfolioContext();
});

Using the Repository Pattern and DI to switch between SQL and XML ASP.Net MVC

i have XMLProductRepository and SQLProductRepository. now how could i switch between them dynamically. i am new in DI. so searching google for the same and found a link which discuss a bit. but still do not understand on what basis the repository will be changed and how. here is the code
public interface IProductRepository
{
IEnumerable<Product> GetAll();
Product Get(int id);
Product Add(Product item);
void Remove(int id);
bool Update(Product item);
}
public class XMLProductRepository : IProductRepository
{
public XMLProductRepository() {}
public IEnumerable<Product> GetAll() {}
public Product Get(int id) {}
public Product Add(Product item) {}
public void Remove(int id) {}
public bool Update(Product item) {}
}
public class SQLProductRepository : IProductRepository
{
public SQLProductRepository() {}
public IEnumerable<Product> GetAll() {}
public Product Get(int id) {}
public Product Add(Product item) {}
public void Remove(int id) {}
public bool Update(Product item) {}
}
Unity.Mvc3 is using as Di
public static class Bootstrapper
{
public static void Initialise()
{
var container = BuildUnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
//Register the repository
container.RegisterType<IProductRepository, SQLProductRepository>();
return container;
}
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
Bootstrapper.Initialise();
}
public class HomeController : Controller
{
private readonly IProductRepository productRepository;
public HomeController(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
i understand the code that dynamically SQLProductRepository instance is getting injecting into controller. so my question is how to inject XMLProductRepository ?
i want to design something in such a way based on url dependency will be injected.
how to achieve it. looking for guide line. thanks
One possible solution is to inject an IProductRepositoryFactory instead of IProductRepository itself. It would look like this:
interface IProductRepositoryFactory
{
IProductRepository GetRepository(string url);
}
Then your HomeController would look like this:
public class HomeController : Controller
{
private readonly IProductRepositoryFactory productRepositoryFactory;
public HomeController(IProductRepositoryFactory productRepositoryFactory)
{
this.productRepositoryFactory = productRepositoryFactory;
}
}
This way, you'll be able to get required implementation of IProductRepository in your controller action at runtime — all you need is to implement the required logic in the IProductRepositoryFactory.GetRepository(url) method.
Here's a controller action example (note that getting current request URL in such a way makes this method less testable):
public Product Get(string id)
{
return productRepositoryFactory
.GetRepository(Request.Url.ToString())
.GetById(id);
}
UPD: The following is an example implementation of IProductRepositoryFactory. Just implement your own decision-making logic that returns an appropriate instance of IProductRepository based on the URL:
public class ProductRepositoryFactory : IProductRepositoryFactory
{
public IProductRepository GetRepository(string url)
{
if (url.Contains("xml")) { return new XMLProductRepository(); }
if (url.Contains("sql")) { return new SQLProductRepository(); }
throw new ArgumentException("url");
}
}
I don't know where you got the code from, perhaps this question, but the two implementations of IProductRepository that you show have two purposes.
SQLProductRepository will read and write data from and to the database.
XMLProductRepository can read XML and maybe write files.
When running code in a unit test, you generally don't want to connect to a database, but you do sometimes want to use data in a unit test. That's where the XML repository comes in handy. You prepare a data set in XML files that you can commit to version control, you inject another implementation of the requested interface - namely one that reads the XML file - and you don't need a database anymore.
That's why you configure your DI container to inject the SQLProductRepository, while in unit tests you or the DI container will provide an XMLProductRepository when the application requests an IProductRepository.
Now if you say that your controller, your business logic, is to choose SQLProductRepository for one particular request, based on the URI, and XMLProductRepository for the other, then using IProductRepository for that purpose is wrong. That is a problem that should not be solved using your DI container.
Introduce two new interfaces instead and apply those to the repositories:
public interface ISqlProductRepository : IProductRepository
{
}
public interface IXmlProductRepository : IProductRepository
{
}
SQLProductRepository : ISqlProductRepository
XMLProductRepository : IXmlProductRepository
And register and inject those:
// Application startup
container.RegisterType<ISqlProductRepository, SQLProductRepository>();
container.RegisterType<IXmlProductRepository, XMLProductRepository>();
// Controller
private readonly ISqlProductRepository _sqlProductRepository;
private readonly IXmlProductRepository _xmlProductRepository;
public HomeController(ISqlProductRepository sqlProductRepository, IXmlProductRepository xmlProductRepository)
{
_sqlProductRepository = sqlProductRepository;
_xmlProductRepository = xmlProductRepository;
}
public ActionResult SqlMethod1()
{
// use _sqlProductRepository
}
public ActionResult XmlMethod2()
{
// use _xmlProductRepository
}
Of course now you can't inject XMLProductRepository for SQLProductRepository anymore, but that's a problem easily solved using mocking.
Anyway based on your current streak of questions, you're trying to learn something about unit testing and dependency injection. Please pick up a decent book and stop tying pieces together from blog posts, which hardly ever explain everything you need to know.

Resolve constructor argument with parameter from base class

I have a custom ASP.NET MVC controller that retrieves operations from the user service. I want to pass the operations property to the scenario service using dependency injection.
public abstract class BaseController : Controller {
protected IUserService userService;
public OperationWrapper operations { get; private set; }
public BaseController(IUserService userService) {
this.userService = userService;
this.operations = userService.GetOperations(HttpContext.Current.User.Identity.Name);
}
}
public abstract class ScenarioController : BaseController {
protected IScenarioService scenarioService;
public ScenarioController(IScenarioService scenarioService, IUserService userService)
: base(userService) {
this.scenarioService = scenarioService;
}
}
public class ScenarioService : IScenarioService {
private OperationWrapper operations;
public ScenarioService(OperationWrapper operations) {
this.repo = repo;
this.operations = operations;
}
}
Here is my Windsor installer.
public class Installer : IWindsorInstaller {
public void Install(IWindsorContainer container, IConfigurationStore store) {
container.Register(Classes.FromThisAssembly()
.BasedOn<IController>());
container.Register(Classes.FromThisAssembly()
.Where(x => x.Name.EndsWith("Service"))
.WithService.DefaultInterfaces()
.LifestyleTransient());
}
}
I pretty sure I've done something similar with Ninject a couple of years back. What do I need to add to the installer in order to make this work? Is it even possible?
There are a few of options here:
1. Use LifeStylePerWebRequest() and UsingFactoryMethod()
First, you could register an OperationWrapper as LifestylePerWebRequest() and inject it into both the BaseController and ScenarioService. Windsor will let you register the dependency with a factory method for creating it, which can in turn call other services which have been registered.
container.Register(Component.For<OperationWrapper>()
.LifestylePerWebRequest()
.UsingFactoryMethod(kernel =>
{
var userService = kernel.Resolve<IUserService>();
try
{
return userService.GetOperations(
HttpContext.Current.User.Identity.Name);
}
finally
{
kernel.ReleaseComponent(userService);
}
}));
So, every time Windsor is asked for an OperationWrapper, it will run that call against an instance if IUserService, giving it the Name of the current User. By binding the lifestyle to LifestylePerWebRequest(), you can verify that each request will get its own instance of the OperationWrapper and it won't bleed across requests.
(The only edge case you'd run into is one where a user becomes authenticated mid-request and the OperationWrapper needs to be adjusted as a result. If that's a normal-path use case, this may need some re-thinking.)
Then, modify your base controller to take that registered object in as a dependency:
public abstract class BaseController : Controller {
protected IUserService userService;
protected OperationWrapper operations;
public BaseController(IUserService userService, OperationWrapper operations) {
this.userService = userService;
this.operations = operations;
}
}
2. Use Method Injection
It looks like OperationWrapper is some sort of context object, and those can sometimes be injected into the method instead of into the constructor.
For instance, if your method was:
int GetTransactionId() { /* use OperationWrapper property */ }
You could just modify the signature to look like:
int GetTransactionId(OperationWrapper operations) { /* use arg */ }
In this situation, it makes sense to use it if a small-ish subset of your service's methods use that dependency. If the majority (or totality) of methods need it, then you should probably go a different route.
3. Don't use DI for OperationWrapper at all
In situations where you have a highly-stateful contextual object (which it seems like your OperationWrapper is), it frequently just makes sense to have a property whose value gets passed around. Since the object is based on some current thread state and is accessible from everywhere in any subclassed Controller, it may be right to just keep the pattern you have.
If you can't answer the question "What am I unable to do with OperationWrapper now that DI is going to solve for me?" with anything but "use the pattern/container," this may be the option for this particular situation.
You should set dependency resolver in Application_Start method of global.asax
System.Web.MVC.DependencyResolver.SetResolver(your windsor resolver)
Create a class that inherits from DefaultControllerFactory. Something like this will do:
public class WindsorControllerFactory : DefaultControllerFactory
{
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(
404,
String.Format(
CultureInfo.CurrentCulture,
"The controller for path '{0}' was not found or does not implement IController.",
requestContext.HttpContext.Request.Path
)
);
}
return (IController)_kernel.Resolve(controllerType);
}
public override void ReleaseController(IController controller)
{
Kernel.ReleaseComponent(controller);
}
private readonly IKernel _kernel;
private IKernel Kernel
{
get { return _kernel; }
}
}
In the Application_Start method of your MvcApplication class add the following:
var container = new WindsorContainer();
container.Install(FromAssembly.This());
ControllerBuilder.Current.SetControllerFactory(
new WindsorControllerFactory(container.Kernel)
);
This should work with your existing installer and get you to the point where Windsor will start resolving your dependencies for you. You might have to fill-in a few gaps, but you'll get the point.
I've borrowed heavily from: https://github.com/castleproject/Windsor/blob/master/docs/mvc-tutorial-intro.md
Be wary of using IDependencyResolver as it doesn't make provision for releasing what's resolved.

AuthorizeAttribute, constructors, and stopping dependency injection

I have this (simplified) controller setup:
[CustomAuthorizeAttribute]
public class MainController : Controller {}
public class AccountController : MainController
{
private IService _iService;
public AccountController()
{
_service = DependencyFactory.Resolve<IService>(SessionManager.ServiceKey)
}
public AccountController(IService service)
{
_service = service;
}
}
And CustomAuthorizeAttribute looks something like:
public CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool serviceKeyIsGood = CheckServiceKey(SessionManager.ServiceKey);
return serviceKeyIsGood;
}
}
The goal is to only have the account controller run if the user is authenticated, as defined by the presence of a "good" service key.
The problem I'm having is that the constructor for AccountController runs before OnAuthorize runs which causes the service to blow up (by design) since its service key is bad.
What's the best way to manage this? I'd like to take advantage of the simplicity of the CustomAuthorizeAttribute, and I have to avoid re-architecting the way our services are instantiated. (And the dependency factory is necessary as MVC complains about now having parameterless constructors.)
You can use injection of factorymethod instead of service itself:
[CustomAuthorizeAttribute]
public class MainController : Controller
public class AccountController : MainController
{
private Func<IService> _serviceFactory;
public AccountController()
{
_serviceFactory= DependencyFactory.Resolve<Func<IService>>(SessionManager.ServiceKey)
}
public AccountController(Func<IService> serviceFactory)
{
_serviceFactory= serviceFactory;
}
}
and use: to get service: service = _serviceFactory() when you need it.
PS: I recommend you to use standard methods for DI in MVC (controller factory or internal dependency resolver) to avoid code such _serviceFactory= DependencyFactory.Resolve<Func<IService>>(SessionManager.ServiceKey)

Using Ninject to setup services

First off, I'm new to Ninject, but whilst this question targets Ninject, it would seem to apply to DI in general.
I think I'm missing something here. Suggested solutions so far all seem to be horribly complex.
I had something like this:
public class MyController : Controller
{
private IMyService _Service;
public MyController()
:this(null)
{ }
public MyController(IMyService service)
{
_Service = service ?? new MyService(ModelState);
}
}
public IMyService
{}
public class MyService : IMyService
{
private ModelStateDictionary _Model;
public MyService(ModelStateDictionary model)
{
_Model = model;
}
}
And so I thought I'd go Ninject on it. And came up with this:
public class MyController : Controller
{
private IMyService _Service;
public MyController()
:this(null)
{
_Service = Locator.Kernel.Get<IMyService>(new Ninject.Parameters.ConstructorArgument("model", ModelState));
}
}
public class MyServiceModule : NinjectModule
{
public override Load()
{
Bind<IMyService>().To<MyService>(); //here
}
}
It seems to me though, I should be able to change the bit where it binds (marked here) so it knows at that point to get the modelstate, rather than when I want an instance in the constructor, which requires advance knowledge of the concrete service class.
Am I worrying needlessly or is there a better way of doing this?
Simon
Does MyService really need a ModelStateDictionary to be constructed?
I would look towards refactoring that, so that I was passing the ModelStateDictionary into the method I was calling, rather than requiring it for construction of the Service class.
If such a refactoring is unreasonable, you will probably want to add a layer of abstraction over the ModelStateDictionary
public interface IModelStateProvider {
ModelStateDictionary GetModelState();
}
And make an implementation of that interface that can retrieve the current context's ModelStateDictionary, then setup the binding of that interface and change your service class to take it in the constructor:
public class MyService : IMyService
{
private ModelStateDictionary _Model;
public MyService(IModelStateProvider modelStateProvider)
{
_Model = modelStateProvider.GetModelState();
}
}

Resources