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();
}
}
Related
In broader terms what I am trying to achieve with Autofac is to pass the dependant (a.k.a. parent) object to its dependencies.
For example:
interface IDependency {}
class Dependant
{
IDependency Dependency { get; set; }
}
class ConcreteDependency : IDependency
{
ConcreteDependency(Dependant dependant) { /* ... */ }
}
I am hoping this could work, because Dependant breaks the dependency loop using property injection (meaning you can create an instance of Dependant, before having to resolve IDependency). Whilst, if both classes used ctor-injection this wouldn't be possible.
Specifically, I am trying to inject the current ASP.NET MVC controller instance to one of its dependencies.
Take a look at:
public abstract class ApplicationController : Controller
{
public ILogger Logger { get; set;}
}
public class SomeController : ApplicationController
{
[HttpPost]
public ActionResult Create(FormCollection formData)
{
// something fails...
this.Logger.Log("Something has failed.");
}
}
public interface ILogger
{
public void Log(string message);
}
public class TempDataLogger : ILogger
{
private ControllerBase controller;
public NullLogger(ControllerBase controller)
{
this.controller = controller;
}
public void Log(string message)
{
this.controller.TempData["Log"] = message;
}
}
In plain English the above code uses TempData as a way of "logging" messages (maybe to print it out in a nice way in view-layout or something...).
Simple enough all controllers are registered in Autofac:
builder.RegisterControllers(typeof(MvcApplication).Assembly)
.PropertiesAutowired(); // not strictly necessary
But then, how can I tweak the ILogger registration below to make it work?
builder.RegisterType<TempDataLogger>()
.As<ILogger>()
.InstancePerRequest();
Is this even possible in Autofac?
Thank you.
In case anyone else is interested, the solution below is the closest I was able to get so far:
builder.RegisterControllers(typeof(MvcApplication).Assembly)
.PropertiesAutowired() // not strictly necessary
.OnActivating(e => ((ApplicationController)e.Instance).Logger = new TempDataLogger((ApplicationController)e.Instance));
... and therefore, no need to;
builder.RegisterType<TempDataLogger>()
.As<ILogger>()
.InstancePerRequest();
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.
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)
I have this interface:
public interface IUserProfileService
{
// stuff
}
Implemented by:
public class UserProfileService : IUserProfileService
{
private readonly string m_userName;
public UserProfileService(string userName)
{
m_userName = userName;
}
}
I need this injected into a controller like this:
public class ProfilesController : BaseController
{
private readonly IUserProfileService m_profileService;
public ProfilesController(IUserProfileService profileService)
{
m_profileService = profileService;
}
}
I don't know how I can register this interface and its implementation into Ninject container so that userName param is passed in when the Ninject inits an instance of this service.
Any ideas how I can achieve this?
The technical ninject answer is to use constructor arguments like so:
Bind<IUserProfileService>().To<UserProfileService>().WithConstructorArgument("userName", "karl");
Of course you need to figure out where "karl" comes from. It really depends on your app. Maybe its a web app and it's on the HttpContex? I don't know. If it gets rather complicated then you might want to write a IProvider rather than doing a regular binding.
One alternative is to inject a factory and create your dependency using Create(string userName).
public class UserProfileServiceFactory
{
public IUserProfileService Create(string userName)
{
return new UserProfileService(userName);
}
}
It might seem off to have to create another class but the benefits mostly comes when UserProfileService takes in additional dependencies.
The trick is to not inject the username in that class. You call this class a service so it would probably work transparantly with multiple users. I see two solutions:
Inject an abstraction into the service that represents the current user:
public class UserProfileService : IUserProfileService
{
private readonly IPrincipal currentUser;
public UserProfileService(IPrincipal currentUser)
{
this.currentUser = currentUser;
}
void IUserProfileService.SomeOperation()
{
var user = this.currentUser;
// Do some nice stuff with user
}
}
Create an implementation that is specific to the technology you are working with, for instance:
public class AspNetUserProfileService : IUserProfileService
{
public AspNetUserProfileService()
{
}
void IUserProfileService.SomeOperation()
{
var user = this.CurrentUser;
// Do some nice stuff with user
}
private IPrincipal CurrentUser
{
get { return HttpContext.Current.User; }
}
}
If you can, go with option one.
Greetings
On all my controllers I recycle the same code that wraps my models and to accesses the service layer -- and I'm tired for copy / pasting it into each controller:
private IProjectService _service;
public New()
{
_service = new ProjectService(new ModelValidation(this.ModelState));
}
public New(IProjectService service)
{
_service = service;
}
Is there someplace where I can place this where all my controllers access it?
You could put in a base controller class that all your other controllers inherit from:
public class BaseController : Controller
{
protected IProjectService Service { get; private set; }
public New()
{
Service = new ProjectService(new ModelValidation(this.ModelState));
}
public New(IProjectService service)
{
Service = service;
}
}
Alternatively, you could read up on dependency injection and look at using an IOC container to inject these dependencies.
Welcome to the wonderful world of code smells. You have found one without even knowing what it was. Whenever you think to yourself. "There has to be a better way." There is. In this case a base class would go a long way toward solving your problem.
Controller base class?
Create a base controller, and derive your controllers from it.
public class BaseController : Controller
{
protected IProjectService _service;
public New()
{
_service = new ProjectService(new ModelValidation(this.ModelState));
}
public New(IProjectService service)
{
_service = service;
}
}
public class MyController : BaseController
{
public ActionResult Index()
{
}
}