ASP.NET MVC and the Managed Extensibility Framewok on NuGet

imageIf you search on my blog, there’s a bunch of posts where I talk about ASP.NET MVC and MEF. And what’s cool: these posts are the ones that are actually being read quite often. I’m not sure about which bloggers actually update their posts like if it was software, but I don’t. Old posts are outdated, that’s the convention when coming to my blog. However I recently received a on of questions if I could do something with ASP.NET MVC 3 and MEF. I did, and I took things seriously.

I’m not sure if you know MefContrib. MefContrib is a community-developed library of extensions to the Managed Extensibility Framework (MEF). I decided to wear my bad-ass shoes and finally got around installing a Windows-friendly Git client and decided to just contribute an ASP.NET MVC + MEF component to MefContrib. And while I was at it, I created some NuGet packages for all MefContrib components.

Let’s see how easy it is to use ASP.NET MVC and MEF…

Here’s the sample code I used: MefMvc.zip (698.58 kb)

Obtaining MefContrib.MVC3 in an ASP.NET MVC application

Here’s the short version of this blog post section for the insiders: Install-Package MefContrib.MVC3

Assuming you have already heard something about NuGet, let’s get straight to business. Right-click your ASP.NET MVC project in Visual Studio and select “Add Library Package Reference…”. Search for “MefContrib.MVC3”. Once found, click the “Install” button.

This action will download and reference the new MefContrib.Web.Mvc assembly I contributed as well as the MefContrib package.

How to get started?

You may notice a new file “AppStart_MefContribMVC3.cs” being added to your project. This one is executed at application start and wires all the MEF-specific components into ASP.NET MVC 3. Need something else than our defaults? Go ahead and customize this file. Are you happy with this code block? Continue reading…

You may know that MEF is cool as ICE and thus works with Import, Compose and Export. This means that you can now start composing your application using [Import] and [Export] attributes, MefContrib will do the rest. In earlier posts I did, this also meant that you should decorate your controllers with an [Export] attribute. Having used this approach on many projects, most developers simply forget to do this at the controller model. Therefore, MefContrib.Web.Mvc  uses the ConventionCatalog from MefContrib to automatically export every controller it can find. Easy!

To prove it works, open your FormsAuthenticationService class and add an ExportAttribute to it. Like so:

1 [Export(typeof(IFormsAuthenticationService))] 2 public class FormsAuthenticationService : IFormsAuthenticationService 3 { 4 // ... 5 }

Do the same for the AccountMembershipService class:

1 [Export(typeof(IMembershipService))] 2 public class AccountMembershipService : IMembershipService 3 { 4 // ... 5 }

Now open up the AccountController and lose the Initialize method. Yes, just delete it! We’ll tell MEF to resolve the IFormsAuthenticationService and IMembershipService. You can even choose how you do it. Option one is to add properties for both and add an ImportAttribute there:

1 public class AccountController : Controller 2 { 3 [Import] 4 public IFormsAuthenticationService FormsService { get; set; } 5 6 [Import] 7 public IMembershipService MembershipService { get; set; } 8 9 // ... 10 }

The other option is to use an ImportingConstructor:

1 public class AccountController : Controller 2 { 3 public IFormsAuthenticationService FormsService { get; set; } 4 public IMembershipService MembershipService { get; set; } 5 6 [ImportingConstructor] 7 public AccountController(IFormsAuthenticationService formsService, IMembershipService membershipService) 8 { 9 FormsService = formsService; 10 MembershipService = membershipService; 11 } 12 }

Now run your application, visit the AccountController and behold: dependencies have been automatically resolved.

Conclusion

There’s two conclusions to make: MEF and ASP.NET MVC3 are now easier than ever and available through NuGet. Second: MefContrib is now also available on NuGet, featuring nifty additions like the ConventionCatalog and AOP-style interception.

Enjoy! Here’s the sample code I used: MefMvc.zip (698.58 kb)

Need domain registration?

This is an imported post. It was imported from my old blog using an automated tool and may contain formatting errors and/or broken images.

Leave a Comment

avatar

11 responses

  1. Avatar for Corey Gaudin
    Corey Gaudin February 1st, 2011

    Maarten,

    Thank you so much for this! Thanks to all of the people that contributed to the MefContrib project also! This is really awesome! It is a much cleaner way to do this than what I had previously with MVC3 and MEF using the Dependency Resolver since I would always forget an export somewhere. This is much easier and nicer.

    Quick question: I have been playing with this reverting to this solution than what I had and it works really well. However, I noticed that by default all classes are set as NonShared Exports. This makes alot of sense, because Controllers need to be non-shared to be useful in an MVC application. It also makes alot of sense with Repository classes since having a shared context between 1000s of users would be very feasible or practical. However, there are some cases where some classes just make sense as a Shared Export. How do you accomplish this using this framework? I have tried the markup PartCreationPolicy(CreationPolicy.Shared) on the Exported Classes and the framework does not honor this. It will create a new version every time. Is there any way to do this in the existing framework released? Am I missing something? I can of course fix my problem using static members in the class instance to get around this problem, but in some cases it is far cleaner to just mark the entire class as a Shared Export. Any ideas?

    Thanks again Maarten for making my job easier. I was wondering why this wasnt a built in feature consider its MEF. But this is a better solution to have it as a NuGet package supported by cool people.

    Corey Gaudin

  2. Avatar for Corey Gaudin
    Corey Gaudin February 1st, 2011

    Quick Correction to above:

    It also makes alot of sense with Repository classes since having a shared context between 1000s of users *WOULDNT* be very feasible or practical.

    Sorry.

  3. Avatar for Andy Worral
    Andy Worral February 16th, 2011

    Maarten,

    I have to admit I am not terribly familiar with MEFContrib yet but I was wondering if you could help me out.

    I have been previously using a different implementation of MEF with MVC3 to be able to load Controllers from outside dlls via a custom ControllerFactory. Is there any way to implement this ability just using the DependencyResolver?

    I assume I will still have to override CreateController in order to point at the other dll?

    Its all a little black boxy for me until I grab the source and read through it a bit more.

    Thanks for any pointers!

    Andy

  4. Avatar for maartenba
    maartenba February 16th, 2011

    FYI: Working on master container support...

  5. Avatar for maartenba
    maartenba February 16th, 2011

    You can do exactly the same with MEF + MefContrib, this one just gives you teh functionaility you mention out of the box without having to setup anything specific.

  6. Avatar for Andy Worral
    Andy Worral February 16th, 2011

    I did do a quick test using the new MEfContrib.MVC3 from nuget and it seemed that however the ControllerFactory was looking for an exported Controller that it didn't see the ones in my separate dlll.

    The base namespace in the other dll is different perhaps that is causing the issue? The controller in the other dll still has the XXXX.Areas.MyArea.DoSomethingController as the namespace just the XXXX is different. As I was saying I haven't looked through the code to see how this implementation looks for exported Controllers and selects one. Or if it is just using the original ControllerFactory's implementation to find the Contoller and then using MEF to instantiate it with its dependencies.

    Do you have an example at all of the MefContrib.MVC3 working with a controller from another assembly?

    Hopefully I'll get a chance to dig through the code a bit more today.

    Thanks again

  7. Avatar for Corey Gaudin
    Corey Gaudin March 24th, 2011

    Maarten,

    Where would you add a line to add an export without the [Export] Attribute?

    I tried adding something in the AppStart_MefContribMVC3 to do dependencyResolver.Build<ITestObject>(new TestObject()); and dependencyResolver.Container.ComposeExportedValue<ITestObject>(new TestObject) and it errored out with a Object Reference null (because the Container was still null at this point).

    I moved it to the ApplicationStart in Global.cs, and while it didnt error adding in that part, it does not import in that value to the controllers. Its as if it isnt adding that part as a export.

  8. Avatar for maartenba
    maartenba March 24th, 2011

    What type of export do you want to add? Controllers? Controller exports are registered by convention over at AppStart_MefContribMVC3.Start() in the new ConventionCatalog(new MvcApplicationRegistry()). Check the MefContrib sources if you want to do something similar with other classes.

  9. Avatar for Corey Gaudin
    Corey Gaudin March 24th, 2011

    No. I want to do just a regular object and I dont want to do it by convention. I just want to add that object in like the above. container.ComposeExportedValue<ISomeObject>(new SomeObject()); before the first controller is instantiated so that it can import in the ISomeObject. I havent found a place I can do this and it works yet.

  10. Avatar for tom thorp
    tom thorp April 9th, 2011

    First, let me say, I like the concepts and implementation of your package. But I'm also having a problem AppStart_MefContribMVC3.

    The line -
    var dependencyResolver = new CompositionDependencyResolver(catalog);
    has an internal exception of -
    Message - Object reference not set to an instance of an object.
    Stack Trace -
    at MefContrib.Web.Mvc.Internal.WcfOperationContext.get_Current()
    at MefContrib.Web.Mvc.CurrentRequestContext.get_Items()
    at MefContrib.Web.Mvc.CompositionDependencyResolver.get_Container()

    It appears because of that, framework does not resolve any controllers.

    Can you suggestion something or point me to where I could download the source to your package.

  11. Avatar for Jason Alban
    Jason Alban April 13th, 2011

    I am having the same issue as tom thorp above.