EDIT
The particular part that I am confused about is the error.
5) Injection of dependency ModelStateDictionary into parameter dictionary of constructor of type ModelStateDictionary
ModelStateDictionary has a constructor that accepts a ModelStateDictionary object. Is this why / where the error is occurring? If so, how do I resolve it as ModelStateDictionary is not a n object that I can directly modify.
Original
I've been trying to get dependency injection setup to work on for my controllers on in an asp.net mvc app. But I end up with a cyclic dependency on the System.Web.Mvc.ModelStateDictionary. I've done some searching ... here and here and others and I've tried some of the suggestions like creating a property (maybe I just don't know where to place them) instead of passing it through the constructor. However it seems to me that ninject is having a problem with the System.Web.Mvc.ModelStateDictionary class or definition. I get the following error ...
Activation path:
5) Injection of dependency ModelStateDictionary into parameter dictionary of constructor of type ModelStateDictionary
4) Injection of dependency ModelStateDictionary into parameter modelState of constructor of type ModelStateWrapper
3) Injection of dependency IValidationDictionary into parameter validationDictionary of constructor of type ProjectService
2) Injection of dependency IProjectService into parameter prjService of constructor of type ProjectController
1) Request for ProjectController
My classes are pretty much defined as follows. I have obviously removed some of the extraneous stuff ...
public class ProjectController : Controller
{
private IProjectService _prjService;
private IMembershipService _membershipService;
public ProjectController(IProjectService prjService,IMembershipService membershipService )
{
_membershipService = membershipService;
_prjService = prjService;
}
}
public class ProjectService : ServiceBase, IProjectService
{
public ProjectService(IValidationDictionary validationDictionary) : base(validationDictionary) { }
}
public class ServiceBase
{
private readonly IValidationDictionary _validationDictionary;
public IValidationDictionary ValidationDictionary { get { return _validationDictionary; } }
public ServiceBase(IValidationDictionary validationDictionary)
{
_validationDictionary = validationDictionary;
}
}
public interface IProjectService
{
// interface has other properties
IValidationDictionary ValidationDictionary { get; }
}
public class ModelStateWrapper : IValidationDictionary
{
private ModelStateDictionary _modelState;
public ModelStateWrapper(ModelStateDictionary modelState)
{
_modelState = modelState;
}
public ModelStateWrapper()
{
}
public void AddError(string key, string errorMessage)
{
_modelState.AddModelError(key, errorMessage);
}
public bool IsValid
{
get { return _modelState.IsValid; }
}
}
The definition of ModelStateDictionary is as follows ... at least as far as I think it pertains to this problem.
[Serializable]
public class ModelStateDictionary : IDictionary<string, ModelState>, ICollection<KeyValuePair<string, ModelState>>, IEnumerable<KeyValuePair<string, ModelState>>, IEnumerable
{
public ModelStateDictionary();
public ModelStateDictionary(ModelStateDictionary dictionary);
}
The bindings I've set up for ninject are as follows ...
kernel.Bind<IMembershipService>().To<AuthMembershipService>();
kernel.Bind<IProjectService>().To<ProjectService>();
kernel.Bind<IValidationDictionary>().To<ModelStateWrapper>();
Please let me know if I can provide any more information ... I initially tried to use structuremap but couldn't make the DI work ... I seem to have at least got ninject set up and working for the most part.
Thanks,
Ninject chooses the constructor with the most parameters it knows how to create by default. In this case the second constructor is choosen. This would result in a stackoverflow since it would have to create a ModelStateWrapper to inject into the ModelStateWrapper and andother to inject into the second one, ......
Unless there is a really good reason for the second construcotr you should simply delete it. Otherwise you have to give here enough information that we can understand why there is this second constructor.
Related
I am building the asp.net WebAPI project and have used Autofac as IOC. Now i am doing constructor based injection and calls the various methods of the business class from the controller class.
Now i want to pass some additional data into the business class via the public property IncomingUser such as this one :-
My interface looks like this :-
public interface IUserManager
{
string IncomingUser { set; get; }
Task<List<String>> GetUserPofiles(string Name);
}
This readonly property IncomingUser will be used inside various methods defined under the class UserManager.
public class UserManager : IUserManager
{
public string IncomingUser { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public async Task<List<String>> GetUserPofiles(string Name)
{
......Business Logic for the method......
}
}
From the API controller, i am setting the DI like this :-
public class myAPIController : ApiController
{
IUserManager _Manager;
public myAPIController(IUserManager Mang)
{
_Manager = Mang;
}
}
Please suggest, how should i set the property IncomingUser from the API controller class with the help of autofac DI or another way.
I have a service layer with the following classes / intefaces (IServices is an empty interface):
public interface IForoChanService<T> : IService
{
T GetById(int id);
IQueryable SearchBy(Expression<Func<T, bool>> predicate);
IEnumerable<T> GetAll();
int Create(T entity);
void CreateMany(IEnumerable<T> entities);
void Delete(T entity);
void Delete(int id);
void DeleteMany(IEnumerable<T> entities);
void Update(T entity);
}
Then I have an abstract class implementing that signature generically:
public abstract class ForoChanServiceBase<T> : IForoChanService<T> where T : EntityBase
{
public T GetById(int id)
{
return ChanDbContext.Set<T>().Find(id);
}
//all the other methods as well
}
And finally the concrete classes:
public class CategoryService : ForoChanServiceBase<Category>
{
}
I am trying to use AutoFac to inject those services (many: category, client, etc) in the constructor: I have a base controller:
public abstract class ForoChanBaseController: Controller
{
protected ForoChanServiceBase<Post> PostService { get; private set; }
protected ForoChanServiceBase<Comment> CommentService { get; private set; }
protected ForoChanServiceBase<Category> CategoryService { get; private set; }
protected ForoChanBaseController()
{
}
protected ForoChanBaseController(
ForoChanServiceBase<Post> postService,
ForoChanServiceBase<Comment> commentService,
ForoChanServiceBase<Category> categoryService)
{
PostService = postService;
CommentService = commentService;
CategoryService = categoryService;
}
}
And I am setting autofac like this:
public static void ConfigureIoc()
{
var builder = new ContainerBuilder();
builder.RegisterType<CommentService>().As<ForoChanServiceBase<Comment>>().InstancePerRequest();
builder.RegisterType<CategoryService>().As<ForoChanServiceBase<Category>>().InstancePerRequest();
builder.RegisterType<PostService>().As<ForoChanServiceBase<Post>>().InstancePerRequest();
builder.Build();
}
The problem is that I am having is when in the controller I need to use any service method that guy (CategoryService) is null:
public ActionResult Create()
{
var p = new PostFormNewVm
{
Categories = CategoryService.GetAll().Select(c => new CategoryVm { Id = c.Id, Title = c.Title })
};
return View(p);
}
Besides this error do am I doing something wrong? I can't make it work.
I tried with the inteface as well.
Your ForoChanBaseController contains multiple constructors, which is an anti-pattern. Because of the existence of this default constructor, there is a derived class that uses this constructor instead of the overloaded one, which is causing the dependencies to be null.
Although this default ctor is the cause for you to post the question here, there are more -less obvious problems- with your design:
Although you can remove the default constructor, prevent having this base class at all. Bases classes are often big Single Responsibility Principle violations and are either used to stuff in cross-cutting concerns or other utility functions. By having this base class derived types are forced to require dependencies that they might not even use at all. This complicates your code and complicates testing.
Since you have the IForoChanService<T> interface, consumers should not depend on the ForoChanServiceBase base class. As a matter of fact, the same advise as before holds: this base class should probably not exist at all.
The IForoChanService<T> is big generic tool box of methods where consumers only use one or two of those methods at a time. This means you are violating the Interface Segregation Principle.
IForoChanService<T> implementations are likely to violate the Liskov Substitution Principle, since there will be implementations that don't allow entities to be deleted. This will cause call to Delete to fail with an exception, instead of the Delete to not exist for that entity.
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 a controller and I want to use Dependency Injection with constructor,this is my code
private readonly IHomeService _iHomeService;
public HomeController(IHomeService iHomeService)
{
_iHomeService = iHomeService;
}
public HomeController()
{
}
When I remove Constructor without any parameter(Second Constructor),I see this error :
No parameterless constructor defined
and When I use Constructor without any parameter,I see my private field is null(_iHomeService = null) because program use constructor without parameter.
How can I resolve this problem for Dependency Injection?
Well, to do dependency injection youll need to either use a framework or use controller factory .
try ninject
public class HomeController : Controller
{
private readonly IWelcomeMessageService welcomeMessageService;
public HomeController(IWelcomeMessageService welcomeMessageService)
{
this.welcomeMessageService = welcomeMessageService;
}
public void Index()
{
ViewModel.Message = this.welcomeMessageService.TodaysWelcomeMessage;
return View();
}
}
public class WelcomeMessageServiceModule : NinjectModule
{
public override void Load()
{
this.Bind<IWelcomeMessageService>().To<WelcomeMessageService>();
}
}
The framework will take control on the controller instance creation and pass the constractor params
It sounds like you are expecting, automatically, the HomeService class to be instantiated and injected into the Controller.
Using an IoC framework like Ninject or StructureMap will do that for you - once you've set it up.
If you don't want to use an IoC framework, you'll need to manually instantiate the HomeService in your constructor.
ASP.NET uses a ControllerFactory to instantiate your controllers on-demand. This class requires that your controller has a parameterless constructor that it can use to create an instance of it.
You'll need to use a dependency injection framework to create your controllers and inject the required dependencies. ASP.NET has some dependency injection capability, but I understand that it is flawed. I suggest using Castle Windsor to manage your dependency injection. It integrates very well with ASP.NET, and there's a tutorial on integrating it here.
If you go down this route, you'd end up with an installer for your controllers and service:
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<IController>().LifestyleTransient());
container.Register(Component.For<IHomeService>.ImplementedBy<HomeService>());
}
}
..and a new ControllerFactory to create them:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel _kernel;
public WindsorControllerFactory(IKernel kernel)
{
_kernel = kernel;
}
public override void ReleaseController(IController controller)
{
_kernel.ReleaseComponent(controller);
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
if (controllerType == null)
{
throw new HttpException(404, string.Format("The controller for path '{0}' could not be found.", requestContext.HttpContext.Request.Path));
}
return (IController) _kernel.Resolve(controllerType);
}
}
Finally, you'd create a container and set a new controller factory:
var container = new WindsorContainer().Install(new Installer());
var controllerFactory = new WindsorControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
You could also use Ninject or StructureMap.
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();
}
}