I have been stuck with this issue and couldn't take it out of my head. Hence, ended up putting in some heavy hours solving it. But hopefully it is worth it.
Because of this line in the implementation of the ContainerManager class which you put in the initialize pipeline:
container.Install(FromAssembly.InDirectory(new AssemblyFilter(Path.GetDirectoryName(Uri.UnescapeDataString((new UriBuilder(Assembly.GetExecutingAssembly().CodeBase)).Path)), "BigWebsite*.dll")));
the described error was getting thrown from this line :
return (IController)kernel.Resolve(controllerType);
Weirdly, most of the blog/tutorials show this example for implementing Castle Windsor for MVC.
The fix is to have this instead:
And everything else works fine from here. No need to implement extra pipeline to inject you "mvc area" implementation dll into the pipeline or modify existing implementation.
THE CONTEXT:
I am implementing a MVC solution for an existing Sitecore 8.0 implementation which uses Castle Windsor for it's dependency resolver. Let's say a a tiny microsite. I had to implement a SPEAK app as per one of the requirements. Below are the 2 most important things behind why I ran into this issue in the first place:
I needed to call a WebApi from my SPEAK app.
2. I decided to take MVC Area approach for my "tiny microsite" on a completely different sets of dlls
For example the dlls for my "tiny microsite" are MyTinyApp.Web.dll, MyTinyApp.Business.dll whereas the main website's dlls are BigWebsite.Web.dll, BigWebsite.Business.dll etc.
For example the dlls for my "tiny microsite" are MyTinyApp.Web.dll, MyTinyApp.Business.dll whereas the main website's dlls are BigWebsite.Web.dll, BigWebsite.Business.dll etc.
WHY MVC AREA:
The reason I took the MVC Area approach was to completely separate my "tiny microsite" so that I don't have to touch any of the code from "BigWebsite" implementation (Or it can also be that the code base for the "Big Website" was unavailable to me .. imagine whatever floats your boat).THE PROBLEM:
After I implemented my MVC Area project on dll called "MyTinyApp.Web.dll" for my "tiny microsite) upon trying to call the WebApi I started getting bellow error:
From the error it's clear that the routing got resolved without any issue. But Castle Windsor for some weird reason decided to step in like "hai .. new controller .. i need to resolve this" which I would be cool with until it couldn't and threw the bizarre error that doen't make sense to begin with.
I have never told Castle Windsor to resolve any of my stuff for "MyTinyApp.Web.dll" and the exception was getting thrown from BigWebsite.Web.dll.
WEIRD.
THE SOLUTION:
1. Create a processor in one of your project specific config file like below:
<pipelines>
<initialize>
<processor
patch:before="processor[@type='Sitecore.Mvc.Pipelines.Loader.InitializeGlobalFilters,
Sitecore.Mvc']"
type="MyTinyApp.CastleWindsor.Pipelines.Initialize.InitializeWindsorControllerFactory,
MyTinyApp.CastleWindsor" />
</initialize>
</pipelines>
2. Create a settings to get the assembly name associated with Big Website's dependency resolver.
<setting
name="BigWebsiteDependancyResolverAssembly"
value="BigWebsite.Web.DependencyResolution.ContainerManager,BigWebsite.Web"
/>
3. Implement the ControllerFactory for TinyApp:
public class InitializeWindsorControllerFactory
{
public virtual void
Process(PipelineArgs args)
{
string assemblyAndClass =
ConfigHelper.GetValue("BigWebsiteDependancyResolverAssembly");
Type resolverType = Type.GetType(assemblyAndClass);
IWindsorContainer icontainer =
(IWindsorContainer)(resolverType.GetProperty("Container").GetValue(null));
icontainer.Register(Classes.FromAssemblyNamed("oblog.client.mvc").BasedOn<IController>().LifestyleTransient());
}
}
And waalaaa .. Double Rainbow and Unicorn,
The trick here was to get it through reflection.
Thus I do not have to touch the BigWebsite codebase at all so I can avoid deployment headache for it. Resolving though reflection makes it completely independent to any other dlls.
"This is mainly intended for future me." but seriously CastleWindsor WTF !!!!
So one of my genius colleagues figured out that original implementation of ControllerFactory in BigWebsite.Web project(csproj) had flaw in it.
So it was originally like below:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public WindsorControllerFactory(IKernel kernel)
{
this.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);
}
}
UPDATE:
So one of my genius colleagues figured out that original implementation of ControllerFactory in BigWebsite.Web project(csproj) had flaw in it.
Here's his post:
So it was originally like below:
public class WindsorControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public WindsorControllerFactory(IKernel kernel)
{
this.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);
}
}
Because of this line in the implementation of the ContainerManager class which you put in the initialize pipeline:
container.Install(FromAssembly.InDirectory(new AssemblyFilter(Path.GetDirectoryName(Uri.UnescapeDataString((new UriBuilder(Assembly.GetExecutingAssembly().CodeBase)).Path)), "BigWebsite*.dll")));
the described error was getting thrown from this line :
return (IController)kernel.Resolve(controllerType);
Weirdly, most of the blog/tutorials show this example for implementing Castle Windsor for MVC.
The fix is to have this instead:
try
{
return (IController)kernel.Resolve(controllerType);
}
catch (Exception ex)
{
//
do something
return base.GetControllerInstance(requestContext, controllerType);
}
And everything else works fine from here. No need to implement extra pipeline to inject you "mvc area" implementation dll into the pipeline or modify existing implementation.
Hope it helps someone facing the same issue save time so that he/she can utilize it properly to dress up like wookie.
Comments
Post a Comment