0
votes

I am trying to create an ASP.NET MVC project with Castle Windsor and dependency injection. Everything is working fine expect the following:

Global.asax

Container = new WindsorContainer();
Container.Install(new WebInstaller(), new LoggingInstaller());

var customControllerFactory = new CustomControllerFactory(Container);
ControllerBuilder.Current.SetControllerFactory(customControllerFactory);

Webinstaller to register the Castle classes:

string connectionStr = GetConnectionString("MainModel");
container.Register(Component.For(typeof(MainModelContainer)).DependsOn(new { 
          connectionString = connectionStr }).LifestylePerWebRequest());
container.Register(Classes.FromAssemblyContaining<MemberQueries>().InNamespace("User.EF.Queries").WithService.DefaultInterfaces().LifestylePerWebRequest());
container.Register(Classes.FromAssemblyContaining<HomeController>().BasedOn<IController>().LifestylePerWebRequest());

//PROBLEM that doesn't work
container.Register(Classes.FromAssemblyContaining<HomeController>().BasedOn<IAddMessage>().LifestylePerWebRequest());

HomeController

public IAddMessage AddMessage { get; set; }
private readonly IMemberQueries _memberContract;

public HomeController(IMemberQueries memberContract)
{
  _memberContract = memberContract;
}

public ActionResult Index()
{
   //PROBLEM AddMessage is Null and is not resolved automaticaly
   AddMessage.Add("Test", MessageTypes.message);
   return View("Index");
}

IAddMessage Implementation

public class CustomMessage : IAddMessage
{
    private IController Controller { get; set; }

    public CustomMessage(IController controller)
    {
        Controller = controller;
    }

    public void Add(string text, MessageTypes messageTypes)
    {
        //TODO
    }
}

IAddMessage Interface

public interface IAddMessage
{
    void Add(string text, MessageTypes messageTypes);
}

The problem is, that the IAddMessage property is null, because the container can't resolve the IController dependency in the CustomMessage constructor. But I don't know how to resolve this Problem.

The internal error message in the Castle container shows this:

Some dependencies of this component could not be statically resolved. 'User.Web.UI.Helper.Messages.CustomMessage' is waiting for the following dependencies: - Service 'System.Web.Mvc.IController' which was not registered.

I looked a lot in the web but I can't find any working hints or Solution for my problem.

2
I don't know if this will help find a solution so I am not marking as answer. The kernel will attempt to resolve IController when it registers the CustomMessage implementation of IAddMessage via constructor parameter. Perhaps IController is out of scope or needs to be registered first.Ross Bush

2 Answers

1
votes

The problem is that you haven't registered the IController-dependency. I suppose you're thinking that you did that with the following line:

container.Register(Classes.FromAssemblyContaining<HomeController>().BasedOn<IController>().LifestylePerWebRequest());

This might seem like you're doing that, but what you're actually doing is registering all the classes that implement this interface. So, when you ask the container for a HomeController, it will know how to resolve that, however, if you ask it for an IController, it won't know whether to create a HomeController or whatever other controller.

What you probably want is the current active controller. In order to do this, you would probably have to inherit from the CustomControllerFactory and save the created controller in the request scope. Then you can retrieve it from the request scope inside your CustomMessage class.

You can check the following thread to see how to do that: Asp.net mvc 3- get the current controller instance (not just name)

0
votes

With the Help from Kenneth I've found the Solution which looks like:

private const string CurrentControllerIndexName = "CurrentControllerItem";

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));
        }

        var controller = (IController)this._container.Resolve(controllerType);
        //I am Using the Context not the current Session!
        if(HttpContext.Current.Items.Contains(CurrentControllerIndexName))
        {
            HttpContext.Current.Items.Remove(CurrentControllerIndexName);
        }

        HttpContext.Current.Items.Add(CurrentControllerIndexName, controller);

        return controller;
    }

public static IController GetCurrentController()
{
    if(HttpContext.Current.Items.Contains(CurrentControllerIndexName))
    {
        return (IController) HttpContext.Current.Items[CurrentControllerIndexName];
    }

    throw  new Exception("No Controller found in the Current HttpContext");
 }

I've extendet the "DefaultControllerFactory" and I am using the HttpContext to store the current Used Controller in the Current HttpRequest, that works fine now.

the CustomMessage now looks like:

public class CustomMessage : IAddMessage
{
   public CustomMessage()
   {
   }

   public void Add(string text, MessageTypes messageTypes)
   {
       Controller controller = (Controller)CustomControllerFactory.GetCurrentController();
       //TODO
   } 
}

and my Castle Register

...
container.Register(Classes.FromAssemblyContaining<HomeController>().BasedOn<IController>().LifestylePerWebRequest());
container.Register(Component.For<IAddMessage>().ImplementedBy<CustomMessage>());
...

That works fine now.