updated: read below in this post for a minimal solution
I have some newbie questions about an MVC4 solution with plugins. I googled around a bit and found
some good stuff, but it does not exactly fit my requirements, so I'm asking here for some advice.
It seems that the best solution for widget-like plugins in MVC is portable areas (in the MvcContrib package). I found the basic guidance here:
http://lostechies.com/erichexter/2009/11/01/asp-net-mvc-portable-areas-via-mvccontrib/
and some useful tips here:
http://geekswithblogs.net/michelotti/archive/2010/04/05/mvc-portable-areas-ndash-web-application-projects.aspx
More stuff in this post:
How to create ASP.NET MVC area as a plugin DLL?
That's all cool but sadly my requirements are a bit different:
unfortunately, I need a system where plugins are added and discovered dynamically, and this is not the case with portable areas, which must be referenced by the main MVC site project. I'd like to just upload something to the site and get it discover and use new components, so I'm going to use MEF for this.
fortunately, my plugins will not be like widgets, which might be very complex and heterogeneous; rather, they are components which must follow a common, shared pattern. Think of them like specialized editors: for each data type I'll offer a component with editing functions: new, edit, delete. So I was thinking of plugin-controllers which implement a common interface and provide actions like New, Edit, Delete and the like.
I must use MVC4 and in the future I'll have to add localization and mobile customizations.
I must avoid dependencies from complex frameworks and keep the code as simple as possible.
So, whenever I want to add a new data type for editing in this website I'd just like to drop a DLL in its plugins folder for the logic stuff (controller etc), and some views in the correct locations, to get the site discover and use the new editor.
Eventually I could include the views in the DLL itself (I found this: http://razorgenerator.codeplex.com , and this tutorial: http://www.chrisvandesteeg.nl/2010/11/22/embedding-pre-compiled-razor-views-in-your-dll/, which I suppose I could use with the codeplex razorgenerator as the code it refers to is not compatible with VS2012), but probably I'll have better keep them separated (also because of the localization and mobile-awareness requirements); I was thinking of adding an upload mechanism to my site admin area, where you can upload a single zip with the DLL with controllers and folders with views, and then let the server unzip and store files where required. This would allow me to easily modify views without having to deploy again the whole add-in.
So I started looking for MEF and MVC, but most of the posts refer to MVC2 and are not compatible. I had better luck with this, which is mainly focused on web API, but looks promising and simple enough:
http://kennytordeur.blogspot.it/2012/08/mef-in-aspnet-mvc-4-and-webapi.html
This essentially adds a MEF-based dependency resolver and controller factory to the "standard" MVC application. Anyway the sample in the post refers to a single-assembly solution, while I need to deploy several different plugins. So I slightly modified the code to use a MEF DirectoryCatalog (rather than an AssemblyCatalog) pointing to my plugins folder and then created a test MVC solution, with a single plugin in a class library.
Anyway, when I try loading the plugin controller the framework calls my factory GetControllerInstance with a null type, so that of course MEF cannot proceed to composition. Probably I'm missing something obvious, but I'm new to MVC 4 and any suggestion or useful (MVC4-compliant) link are welcome. Thanks!
Here is the essential code:
public static class MefConfig
{
public static void RegisterMef()
{
CompositionContainer container = ConfigureContainer();
ControllerBuilder.Current.SetControllerFactory(new MefControllerFactory(container));
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver =
new MefDependencyResolver(container);
}
private static CompositionContainer ConfigureContainer()
{
//AssemblyCatalog assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
DirectoryCatalog catalog = new DirectoryCatalog(
HostingEnvironment.MapPath("~/Plugins"));
CompositionContainer container = new CompositionContainer(catalog);
return container;
}
}
public class MefDependencyResolver : IDependencyResolver
{
private readonly CompositionContainer _container;
public MefDependencyResolver(CompositionContainer container)
{
_container = container;
}
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
var export = _container.GetExports(serviceType, null, null).SingleOrDefault();
return (export != null ? export.Value : null);
}
public IEnumerable GetServices(Type serviceType)
{
var exports = _container.GetExports(serviceType, null, null);
List createdObjects = new List();
if (exports.Any())
createdObjects.AddRange(exports.Select(export => export.Value));
return createdObjects;
}
public void Dispose()
{
}
}
public class MefControllerFactory : DefaultControllerFactory
{
private readonly CompositionContainer _compositionContainer;
public MefControllerFactory(CompositionContainer compositionContainer)
{
_compositionContainer = compositionContainer;
}
protected override IController GetControllerInstance(
System.Web.Routing.RequestContext requestContext, Type controllerType)
{
if (controllerType == null) throw new ArgumentNullException("controllerType");
var export = _compositionContainer.GetExports(controllerType, null, null).SingleOrDefault();
IController result;
if (null != export) result = export.Value as IController;
else
{
result = base.GetControllerInstance(requestContext, controllerType);
_compositionContainer.ComposeParts(result);
} //eelse
return result;
}
}
You can download the full test solution from here:
http://www.filedropper.com/mvcplugins
Edit: a first working minimal solution
Here are my findings, hope they can be useful for some other newbie starting with this stuff: I did not manage to succesfully run the framework quoted in the above reply, I suppose there must be something to be updated for VS2012 and MVC4. Anyway, I looked at the code and googled a bit more:
1) first of all, a source of confusion for me were the 2 different interfaces with the same name: IDependencyResolver. If I understand well, one (System.Web.Http.Dependencies.IDependencyResolver) is used for webapi, and another (System.Web.Mvc.IDependencyResolver) for generic DI. This post helped me here: http://lucid-nonsense.co.uk/dependency-injection-web-api-and-mvc-4-rc/.
2) also, a third component is the DefaultControllerFactory-derived controller factory, which is crucial to this post because it is the factory used for plugin-hosted controllers.
Here are my implementations for all these, slightly modified from several samples: first the HTTP resolver:
public sealed class MefHttpDependencyResolver : IDependencyResolver
{
private readonly CompositionContainer _container;
public MefHttpDependencyResolver(CompositionContainer container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public object GetService(Type serviceType)
{
if (serviceType == null) throw new ArgumentNullException("serviceType");
string name = AttributedModelServices.GetContractName(serviceType);
try
{
return _container.GetExportedValue(name);
}
catch
{
return null;
}
}
public IEnumerable GetServices(Type serviceType)
{
if (serviceType == null) throw new ArgumentNullException("serviceType");
string name = AttributedModelServices.GetContractName(serviceType);
try
{
return _container.GetExportedValues(name);
}
catch
{
return null;
}
}
public IDependencyScope BeginScope()
{
return this;
}
public void Dispose()
{
}
}
Then the MVC resolver, which is very similar, even if strictly not necessary for the dummy sample in this scenario:
public class MefDependencyResolver : IDependencyResolver
{
private readonly CompositionContainer _container;
public MefDependencyResolver(CompositionContainer container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public object GetService(Type type)
{
if (type == null) throw new ArgumentNullException("type");
string name = AttributedModelServices.GetContractName(type);
try
{
return _container.GetExportedValue(name);
}
catch
{
return null;
}
}
public IEnumerable GetServices(Type type)
{
if (type == null) throw new ArgumentNullException("type");
string name = AttributedModelServices.GetContractName(type);
try
{
return _container.GetExportedValues(name);
}
catch
{
return null;
}
}
}
And finally the controller factory:
[Export(typeof(IControllerFactory))]
public class MefControllerFactory : DefaultControllerFactory
{
private readonly CompositionContainer _container;
[ImportingConstructor]
public MefControllerFactory(CompositionContainer container)
{
if (container == null) throw new ArgumentNullException("container");
_container = container;
}
public override IController CreateController(RequestContext requestContext, string controllerName)
{
var controller = _container
.GetExports()
.Where(c => c.Metadata.Name.Equals(controllerName, StringComparison.OrdinalIgnoreCase))
.Select(c => c.Value)
.FirstOrDefault();
return controller ?? base.CreateController(requestContext, controllerName);
}
}
As for the sample controller, I created it into a class library project:
[Export(typeof(IController))]
[PartCreationPolicy(CreationPolicy.NonShared)]
[ExportMetadata("Name", "Alpha")]
public sealed class AlphaController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Hello, this is the PLUGIN controller!";
return View();
}
}
In the main project (the MVC site) I have a Plugins folder where I copy this DLL, plus a "standard" set of views in their folders for this controller's views.
This is the simplest possible scenario, and probably there is much more to find out and refine, but I needed to be simple to start with. Anyway, any suggestion is welcome.
I'm currently working on the same issue. I've found this solution:
Blog post: http://blog.longle.net/2012/03/29/building-a-composite-mvc3-application-with-pluggable-areas/
Source code: https://bitbucket.org/darincreason/mvcapplication8.web
Basically it loads assemblies from specified location and with some name pattern on web application startup:
AssemblyInfo.cs:
[assembly: PreApplicationStartMethod(
typeof(PluginAreaBootstrapper), "Init")]
PluginAreaBootstrapper.cs:
public class PluginAreaBootstrapper
{
public static readonly List<Assembly> PluginAssemblies = new List<Assembly>();
public static List<string> PluginNames()
{
return PluginAssemblies.Select(
pluginAssembly => pluginAssembly.GetName().Name)
.ToList();
}
public static void Init()
{
var fullPluginPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Areas");
foreach (var file in Directory.EnumerateFiles(fullPluginPath, "*Plugin*.dll", SearchOption.AllDirectories))
PluginAssemblies.Add(Assembly.LoadFile(file));
PluginAssemblies.ForEach(BuildManager.AddReferencedAssembly);
// Add assembly handler for strongly-typed view models
AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
}
private static Assembly AssemblyResolve(object sender, ResolveEventArgs resolveArgs)
{
var currentAssemblies = AppDomain.CurrentDomain.GetAssemblies();
// Check we don't already have the assembly loaded
foreach (var assembly in currentAssemblies)
{
if (assembly.FullName == resolveArgs.Name || assembly.GetName().Name == resolveArgs.Name)
{
return assembly;
}
}
return null;
}
}
But I believe you can create some directory observer which can dynamically load assemblies, so you don't even need to restart your web application.
In my opinion it meets your 1, 2 and 4 needs. It's very simple, doesn't require any frameworks, has minimal configuration, allows dynamic loading of the plugins and works with MVC 4.
This solution plugs assemblies into Area directory, but I believe you can quite easily tune it to play as you like using routing.
You can find more complete solutions, here, and more background here. Our requirements were also a DI so this will help a bit too, although not needed (first links provide solution for DI as well. Good luck with this, it's not hard. Also note that those are for MVC3 but easily convert/migrate to MVC 4
Related
Hi i am new to DI with unity. I am developing a custom Attribute. In that attribute I want to inject a dependency with help of Unity. But when use of that attribute in a class it shows exception. The code is:
public interface ITest
{
}
public class AAttrib : Attribute
{
ITest _test;
public AAttrib(ITest test)
{
_test = test;
}
}
public class Test : ITest
{
}
[AAttrib]
public class Example
{
// to do
}
the exception is:
There is no argument given that corresponds to the required formal
parameter 'test' of 'AAttrib.AAttrib(ITest)
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<ITest, Test>(new HierarchicalLifetimeManager());
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
the Unity resolver class is:
public class UnityResolver: IDependencyResolver
{
protected IUnityContainer _container;
public UnityResolver(IUnityContainer container)
{
if(container == null)
throw new ArgumentNullException("container");
this._container = container;
}
public void Dispose()
{
_container.Dispose();
}
public object GetService(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch (ResolutionFailedException r)
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
try
{
return _container.ResolveAll(serviceType);
}
catch (ResolutionFailedException)
{
return new List<object>();
}
}
public IDependencyScope BeginScope()
{
var child = _container.CreateChildContainer();
return new UnityResolver(child);
}
}
You cannot use Dependency Injection on Attributes, cause Attributes are Metainformation that extend the meta information of classes. And these meta information are generated during compile time
It is indeed not possible to use DI in attributes. There is however a nice clean workaround by using a decorator.
See this blog: https://blogs.cuttingedge.it/steven/posts/2014/dependency-injection-in-attributes-dont-do-it/
I tried this and I've been using it for quite some time now. You will be able to do exactly what you need with this.
(Blog has .net framework & .net core solutions)
Apologies for late entry.
Not sure if unity can let you do that. But PostSharp has a way of achieving this. I've never tried this as PostSharp wasn't an approved DI framework in my project. But I liked the solution.
Auto data contract
This doesn't answer your question but gives a different perspective to the solution that you are thinking.
You should avoid attributes. Attributes are good starting point but get in the way of application extension.
Attributes are hardcoding and is violation of at least two SOLID principles, Single Responsibility and Open/Closed principles. It should rather be done using Fluent APIs
I would rather replace AAttrib with a Fluent API.
Attribute Example
public class Person {
[StringLength(100)]
[RegularExpression("^([a-zA-Z0-9 .&'-]+)$", ErrorMessage = "Invalid First Name")]
public string FirstName { get; set; }
}
FluentValidation Example:
public class Person {
public string FirstName { get; set; }
}
public class PersonValidator : AbstractValidator<Person> {
public PersonValidator() {
RuleFor(x => x.FirstName).NotNull().WithMessage("Can't be null");
RuleFor(x => x.FirstName).Length(1, 100).WithMessage("Too short or long");
RuleFor(x => x.FirstName).Matches("^([a-zA-Z0-9 .&'-]+)$").WithMessage("Invalid First Name"));
}
}
This will essentially do the same thing that attribute is doing. With the right DI wiring in place. This can introduce great flexibility. Read other articles on wiring attributes with members.
There are several questions on Stack Overflow that are similar but not exactly what I'm looking for. I would like to do Ninject binding based on a runtime condition, that isn't pre-known on startup. The other questions on Stack Overflow for dynamic binding revolve around binding based on a config file or some such - I need to it to happen conditionally based on a database value while processing the data for a particular entity. E.g.,
public class Partner
{
public int PartnerID { get; set; }
public string ExportImplementationAssembly { get; set; }
}
public interface IExport
{
void ExportData(DataTable data);
}
Elsewhere, I have 2 dlls that implement IExport
public PartnerAExport : IExport
{
private readonly _db;
public PartnerAExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter A's data...
}
}
Then for partner B;
public PartnerBExport : IExport
{
private readonly _db;
public PartnerBExport(PAEntities db)
{
_db = db;
}
public void ExportData(DataTable data)
{
// export parter B's data...
}
}
Current Ninject binding is;
public class NinjectWebBindingsModule : NinjectModule
{
public override void Load()
{
Bind<PADBEntities>().ToSelf();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
}
}
So how do I set up the bindings such that I can do;
foreach (Partner partner in _db.Partners)
{
// pseudocode...
IExport exportModule = ninject.Resolve<IExport>(partner.ExportImplementationAssembly);
exportModule.ExportData(_db.GetPartnerData(partner.PartnerID));
}
Is this possible? It seems like it should be but I can't quite figure how to go about it. The existing binding configuration above works fine for static bindings but I need something I can resolve at runtime. Is the above possible or am I just going to have to bypass Ninject and load the plugins using old-school reflection? If so, how can I use that method to resolve any constructor arguments via Ninject as with the statically bound objects?
UPDATE: I've updated my code with BatteryBackupUnit's solution such that I now have the following;
Bind<PADBEntities>().ToSelf().InRequestScope();
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
.Configure(c => c.InRequestScope())
);
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.Modules.*.dll")
.SelectAllClasses()
.InheritedFrom<IExportService>()
.BindSelection((type, baseTypes) => new[] { typeof(IExportService) })
);
Kernel.Bind<IExportServiceDictionary>().To<ExportServiceDictionary>().InSingletonScope();
ExportServiceDictionary dictionary = KernelInstance.Get<ExportServiceDictionary>();
Instantiating the export implementations within 2 test modules works and instantiates the PADBEntites context just fine. However, all other bindings in my services layer now no longer work for the rest of the system. Likewise, I cannot bind the export layer if I change PADBEntities variable/ctor argument to an ISomeEntityService component. It seems I'm missing one last step in configuring the bindings to get this work. Any thoughts?
Error: "Error activating ISomeEntityService. No matching bindings are available and the type is not self-bindable"
Update 2: Eventually got this working with a bit of trial and error using BatteryBackupUnit's solution though I'm not too happy with the hoops to jump thought. Any other more concise solution is welcome.
I changed the original convention binding of;
Kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.BindDefaultInterfaces()
);
to the much more verbose and explicit;
Bind<IActionService>().To<ActionService>().InRequestScope();
Bind<IAuditedActionService>().To<AuditedActionService>().InRequestScope();
Bind<ICallService>().To<CallService>().InRequestScope();
Bind<ICompanyService>().To<CompanyService>().InRequestScope();
//...and so on for 30+ lines
Not my favorite solution but it works with explicit and convention based binding but not with two conventions. Can anyone see where I'm going wrong with the binding?
Update 3: Disregard the issue with the bindings in Update 2. It appears that I've found a bug in Ninject relating to having multiple binding modules in a referenced library. A change in module A, even though never hit via breakpoint will break a project explicitly using a different module B. Go figure.
It's important to note that while the actual "condition match" is a runtime condition, you actually know the possible set of matches in advance (at least on startup when building the container) - which is evidenced by the use of the conventions. This is what the conditional / contextual bindings are about (described in the Ninject WIKI and covered in several questions). So you actually don't need to do the binding at an arbitrary runtime-time, rather you just have to do the resolution/selection at an arbitrary time (resolution can actually be done in advance => fail early).
Here's a possible solution, which features:
creation of all bindings on startup
fail early: verification of bindings on startup (through instanciation of all bound IExports)
selection of IExport at an arbitrary runtime
.
internal interface IExportDictionary
{
IExport Get(string key);
}
internal class ExportDictionary : IExportDictionary
{
private readonly Dictionary<string, IExport> dictionary;
public ExportDictionary(IEnumerable<IExport> exports)
{
dictionary = new Dictionary<string, IExport>();
foreach (IExport export in exports)
{
dictionary.Add(export.GetType().Assembly.FullName, export);
}
}
public IExport Get(string key)
{
return dictionary[key];
}
}
Composition root:
// this is just going to bind the IExports.
// If other types need to be bound, go ahead and adapt this or add other bindings.
kernel.Bind(s => s.FromAssembliesMatching("PartnerAdapter.*.dll")
.SelectAllClasses()
.InheritedFrom<IExport>()
.BindSelection((type, baseTypes) => new[] { typeof(IExport) }));
kernel.Bind<IExportDictionary>().To<ExportDictionary>().InSingletonScope();
// create the dictionary immediately after the kernel is initialized.
// do this in the "composition root".
// why? creation of the dictionary will lead to creation of all `IExport`
// that means if one cannot be created because a binding is missing (or such)
// it will fail here (=> fail early).
var exportDictionary = kernel.Get<IExportDictionary>();
Now IExportDictionary can be injected into any component and just used like "required":
foreach (Partner partner in _db.Partners)
{
// pseudocode...
IExport exportModule = exportDictionary.Get(partner.ExportImplementationAssembly);
exportModule.ExportData(_db.GetPartnerData(partner.PartnerID));
}
I would like to do Ninject binding based on a runtime condition, that isn't pre-known on startup.
Prevent making runtime decisions during building of the object graphs. This complicates your configuration and makes your configuration hard to verify. Ideally, your object graphs should be fixed and should not change shape at runtime.
Instead, make the runtime decision at... runtime, by moving this into a proxy class for IExport. How such proxy exactly looks like, depends on your exact situation, but here's an example:
public sealed class ExportProxy : IExport
{
private readonly IExport export1;
private readonly IExport export2;
public ExportProxy(IExport export1, IExport export2) {
this.export1 = export1;
this.export2 = export2;
}
void IExport.ExportData(Partner partner) {
IExport exportModule = GetExportModule(partner.ExportImplementationAssembly);
exportModule.ExportData(partner);
}
private IExport GetExportModule(ImplementationAssembly assembly) {
if (assembly.Name = "A") return this.export1;
if (assembly.Name = "B") return this.export2;
throw new InvalidOperationException(assembly.Name);
}
}
Or perhaps you're dealing with a set of dynamically determined assemblies. In that case you can supply the proxy with a export provider delegate. For instance:
public sealed class ExportProxy : IExport
{
private readonly Func<ImplementationAssembly, IExport> exportProvider;
public ExportProxy(Func<ImplementationAssembly, IExport> exportProvider) {
this.exportProvider = exportProvider;
}
void IExport.ExportData(Partner partner) {
IExport exportModule = this.exportProvider(partner.ExportImplementationAssembly);
exportModule.ExportData(partner);
}
}
By supplying the proxy with a Func<,> you can still make the decision at the place where you register your ExportProxy (the composition root) where you can query the system for assemblies. This way you can register the IExport implementations up front in the container, which improves verifiability of the configuration. If you registered all IExport implementations using a key, you can do the following simple registration for the ExportProxy
kernel.Bind<IExport>().ToInstance(new ExportProxy(
assembly => kernel.Get<IExport>(assembly.Name)));
Does anyone have any example code for getting Umbraco MVC working with the Castle Windsor dependency injection framework? The problem I'm having is getting my surface controllers to use injectable parametised constructors. I know I'm doing something wrong but not sure what.
I have followed the (non-Umbraco) tutorial here - http://docs.castleproject.org/Windsor.Windsor-tutorial-part-four-putting-it-all-together.ashx - which basically means on App_Start I'm running this code:
var container = new WindsorContainer().Install(FromAssembly.This());
var controllerFactory = new MyCustomControllerFactory(container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
Code for MyCustomControllerFactory is below.
Also, my implementation of IWindsorInstaller contains the following:
container.Register(Classes.FromThisAssembly()
.BasedOn<SurfaceController>()
.LifestyleTransient());
The exception I'm getting is 'No component for supporting the service Umbraco.Web.Mvc.RenderMvcController was found', thrown by the GetControllerInstance method below when I call a surface controller with a parametised constructor:
public class TestSurfaceController : SurfaceController
{
public TestSurfaceController(INameService nameService)
{
....
}
}
If anyone has some example code which works I'd really appreciate it. I've wired up Ninject with Umbraco before with no trouble, but on this project I'm tied to Castle Windsor and getting nowhere fast! Thanks in advance.
MyCustomControllerFactory.cs:
public class MyCustomControllerFactory : DefaultControllerFactory
{
private readonly IKernel kernel;
public FastStartControllerFactory(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);
}
}
I believe your problem is here:
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
This is replacing the controller factory for ALL controllers, including the RenderMVCController, and Castle can't find a matching component for that type.
The trick is to use the FilteredControllerFactoryResolver, which lets Umbraco decide which controller to use based on some criteria that you provide (in this case, whether your container can resolve the controller type). Composition is not as clean as in a straight MVC app (IMHO), but it works.
Here's an (Umbraco 7.x) example of a filtered controller that implements the IFilteredControllerFactory interface:
public class FilteredControllerFactory : ControllerFactory, IFilteredControllerFactory
{
public bool CanHandle(RequestContext request)
{
Type controllerType = GetControllerType(request, request.RouteData.Values["controller"].ToString());
return ApplicationStartup.Container.Kernel.HasComponent(controllerType);
}
}
And the corresponding code to set up composition (using ApplicationEventHandler):
public class ApplicationStartup : ApplicationEventHandler
{
internal static IWindsorContainer Container;
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
base.ApplicationStarting(umbracoApplication, applicationContext);
Container = new WindsorContainer()
.Install(Configuration.FromAppConfig())
.Register(Classes.FromThisAssembly().BasedOn<IController>().LifestyleTransient());
FilteredControllerFactoriesResolver.Current.InsertType<FilteredControllerFactory>(0);
}
}
This approach should work both for route hijacking and for surface controllers.
Finally, note that if you also want to support injection into API controllers, you'll need to wire this up separately. For example:
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new CompositionRoot(Container.Kernel))
where CompositionRoot is your own Windsor composition root class.
The Gist here may also prove useful.
I've read Kristopher's answer and I've found it interesting, because I didn't know IFilteredControllerFactory and its use. Thanks for sharing.
Anyway, usually in my projects I have a lot of dll containing each its own controllers, so I prefer to register all the controllers in a more general way:
container.Register(
Classes
.FromAssemblyInDirectory(new AssemblyFilter(AssemblyDirectory))
.BasedOn<IController>()
.LifestyleTransient());
where
/// <summary>
/// Local Directory where are present all the assemblies
/// </summary>
static public string AssemblyDirectory
{
//Snippet code from: https://gist.github.com/iamkoch/2344638
get
{
var codeBase = Assembly.GetExecutingAssembly().CodeBase;
var uri = new UriBuilder(codeBase);
var path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
In this way also the Umbraco's RenderMVCController will be mapped and correctly resolved.
Recently I wrote a couple of articles about DI in a Umbraco app:
MVC Controller Factory
Properties Injection in MVC Filters
Hope it can help
I decided to clean this post up and I posted a sample project at ge.tt/3EwoZEd/v/0?c
Spent around 30 hours on this already and still can't figure it out... help would be really appreciated!
I have an ASP.NET Web API solution that uses this code: http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/ to implement "Basic HTTP authentication in ASP.NET Web API using Message Handlers". I'm new to IoC/DI and I'm trying to get this to work with Castle Windsor.
I've been trying a lot of different things but I get 1 of the following errors depending on what I did wrong:
"Looks like you forgot to register the http module Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule"
"Object reference not set to an instance of an object." for the PrincipalProvider in BasicAuthMessageHandler
"No component for supporting the service *.DummyPrincipalProvider was found"
Below is my code:
Global.asax.cs:
private static IWindsorContainer _container;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
var config = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");
IncludeErrorDetailPolicy errorDetailPolicy;
switch (config.Mode)
{
case CustomErrorsMode.RemoteOnly:
errorDetailPolicy
= IncludeErrorDetailPolicy.LocalOnly;
break;
case CustomErrorsMode.On:
errorDetailPolicy
= IncludeErrorDetailPolicy.Never;
break;
case CustomErrorsMode.Off:
errorDetailPolicy
= IncludeErrorDetailPolicy.Always;
break;
default:
throw new ArgumentOutOfRangeException();
}
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = errorDetailPolicy;
ConfigureWindsor(GlobalConfiguration.Configuration);
GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler()
{
PrincipalProvider = _container.Resolve<IProvidePrincipal>()
});
}
public static void ConfigureWindsor(HttpConfiguration configuration)
{
// Create / Initialize the container
_container = new WindsorContainer();
// Find our IWindsorInstallers from this Assembly and optionally from our DI assembly which is in abother project.
_container.Install(FromAssembly.This());
_container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));
//Documentation http://docs.castleproject.org/Windsor.Typed-Factory-Facility.ashx
// Set the WebAPI DependencyResolver to our new WindsorDependencyResolver
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;
}
Windsor Installer:
public class PrincipalsInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly().BasedOn<DelegatingHandler>());
container.Register(
Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
);
}
}
Modified DummyPrincipalProvider (from the original I got from the URL above):
public class DummyPrincipalProvider : IProvidePrincipal
{
private IUserRepository _userRepo;
public DummyPrincipalProvider(IUserRepository userRepo)
{
this._userRepo = userRepo;
}
public IPrincipal CreatePrincipal(string username, string password)
{
try
{
if (!this._userRepo.ValidateUser(username, password))
{
return null;
}
else
{
var identity = new GenericIdentity(username);
IPrincipal principal = new GenericPrincipal(identity, new[] { "User" });
if (!identity.IsAuthenticated)
{
throw new ApplicationException("Unauthorized");
}
return principal;
}
}
catch
{
return null;
}
}
}
WindsorDependencyResolver.cs:
internal sealed class WindsorDependencyResolver : IDependencyResolver
{
private readonly IWindsorContainer _container;
public WindsorDependencyResolver(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
}
public object GetService(Type t)
{
return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
}
public IEnumerable<object> GetServices(Type t)
{
return _container.ResolveAll(t).Cast<object>().ToArray();
}
public IDependencyScope BeginScope()
{
return new WindsorDependencyScope(_container);
}
public void Dispose()
{
}
}
WindsorDependencyScope.cs:
internal sealed class WindsorDependencyScope : IDependencyScope
{
private readonly IWindsorContainer _container;
private readonly IDisposable _scope;
public WindsorDependencyScope(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
_scope = container.BeginScope();
}
public object GetService(Type t)
{
return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
}
public IEnumerable<object> GetServices(Type t)
{
return _container.ResolveAll(t).Cast<object>().ToArray();
}
public void Dispose()
{
_scope.Dispose();
}
}
I assume IProvidePrincipal is your own implementation.
Best way, the only one IMHO, to use an IoC container is the Composition Root.
The entry point/composition root for web api has been well explained by ploeh's blog.
DelegatingHandler are not part of the "request resolving", so you may choose to resolve it within global asax Application_start where the container lives as private variable.
GlobalConfiguration.Configuration.MessageHandlers.Add(container.Resolve<BasicAuthMessageHandler>());
If you properly registered your handler and all its dependencies in the container, nothing else has to be done: handler instance you extracted from the container and added among MessageHandlers will have an IPrincipalProvider and (I)UserRepository. Keep in mind BasicAuthMessageHandler will act a singleton, so if you need a new instance of (I)UserRepository on each method call... you may consider TypedFactory to create your (I)UserRepository as late dependencies
Of course, any component starting from you top graph component have to be register in the container.
That's the easy way... in case you need somenthing more sophisticate, you may end up creating your "composition root" for DelegatingHandlers as well.
BTW: never, ever, doing somenthing like
UserRepository userRepo = new UserRepository();
or PrincipalProvider = new DummyPrincipalProvider()
none of the "Behaviour instance" should be created explicitly: container take care of providing right instance at the right time...
As per Jon Edit:
now DummyPrincipalProvider looks fine: just keep in mind since DummyPrincipalProvider is created among the message handler(act as singleton due to global registration), you are reusing always same instance.
Instead of your plumbing
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;
I rather use ploeh implementation(see above).
Your registration
container.Register(
Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
.UsingFactoryMethod(kernel => kernel.Resolve<DummyPrincipalProvider>())
);
should be replaced with
container.Register(
Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
);
that's wrong... container has to resolve it, not you explicitly
GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler());
stick with my configuration as above: BasicAuthMessageHandler resolved via container.
Let me know if it works.
PS: You registered the TypedFactory facility in the container, but you are not using it... just to let you know.
You registered DelegatingHandler(s) as Transient, but keep in mind they gonna be "singleton" by design: adding it to the MessageHandlers collection imply they gonna be reused on each request.
As per Jon Edit 2:
I added a sample on github. You should be able to build it and run it using NuGet Package Restore
Your issue about PerWebRequestdepends on the depencies of UserRepository on the NHibernate factory session creating session "PerWebRequest": you cannot resolve IPrincipalProvider->IUserRepository->ISession in Application_Start due to HttpContext. If you really need a IUserRepositry working w/ IPrincipalProvider dependency has to be to a IUserRepositoryFactory(TypedFactory) instead.
I tried to fix your sample using the typed factory and it works, but than I had an issue w/ NHibernate configuration and since I'm not an expert of that, I didn't go any further.
If you need help w/ the factory thing... LMK and I'll update my git sample using a factory within the DummyPrincipalProvider
I try to access my repository from a class for RSS service. So I used dependency injection for that.
Here is what I do in the NinjectControllerFactory:
ninjectKernel.Bind<IPostRepositoryFactory>().To<NinjectPostRepositoryFactory>().InSingletonScope();
Here is my IPostRepositoryFactory class:
public interface IPostRepositoryFactory
{
IPostRepository GetRepository();
}
public class NinjectPostRepositoryFactory : IPostRepositoryFactory
{
private readonly IKernel kernel;
public NinjectPostRepositoryFactory(IKernel kernel)
{
if (kernel == null)
throw new ArgumentNullException("kernel");
this.kernel = kernel;
}
public IPostRepository GetRepository()
{
return kernel.Get<IPostRepository>();
}
}
Here is the call from my controller:
public ActionResult Feed(int? page = 1)
{
var mgr = new SyndicationManager();
return mgr.GetFeedResult(page);
}
Here is the SyndicationManager class:
public class SyndicationManager
{
[Inject]
public IPostRepositoryFactory m_PostRepositoryFactory { get; set; }
private SiteConfiguration m_SiteConfiguration;
public SyndicationManager()
{
m_SiteConfiguration = SiteManager.CurrentConfiguration;
}
public ActionResult GetFeedResult(int? page = 1)
{
IPostRepository repository = m_PostRepositoryFactory.GetRepository();
var feed = new SyndicationFeed(m_SiteConfiguration.Name,
m_SiteConfiguration.Description,
new Uri(SiteManager.GetBaseUrl()));
So I started debugging from my Feed action controller. Then accessing GetFeedResult and there is the problem: error is that my m_PostRepositoryFactory is always null.
Any help is greatly appreciated.
Why aren't you using constructor injection? It makes it easier to find dependencies of your classes and all resolves will fail directly if any of the dependencies are missing.
Just use the ninject.mvc3 nuget package to configure ASP.NET MVC to use dependency injection for the controllers.
And I don't see the use of a singleton factory to find the repository? Why can't you resolve the repository interface directly?
#Jehof is correct. ninject will not resolve any dependencies when you create objects yourself. But as I said: Don't use the kernel directly, configure MVC3+NInject correctly instead.
http://nuget.org/packages/Ninject.MVC3/2.2.2.0
I´m not an expert on Ninject, but i use Unity as DependencyInjection-Framework. I think the problem is that you instantiate SyndicationManager using its default constructor.
You need to get a reference to the SyndicationManager by resolving it from the Ninject-Kernel, otherwise the dependencies won´t be injected.
public ActionResult Feed(int? page = 1)
{
IKernel kernel = // get the kernel from somewhere
var mgr = kernel.Get<SyndicationManager>();
return mgr.GetFeedResult(page);
}