Using IoC in extension methods
Asked Answered
I

3

21

I am working on an ASP MVC 3 app and I'm writing a custom html helper. It's nothing special or hugely complex, but it will need an instance of an interface from structure map. I know I can simply call into structuremaps' object factory from inside the method, but since the rest of the app uses IoC rather than service location I'd like to keep it that way.

Is there a way to inject interfaces into extension methods from inside and asp net mvc app?

UPDATE

An example of what I'm doing might help:

public static class ShowUrl
{
    public static string ForShow(this UrlHelper url, int showId)
    {
        var service = ObjectFactory.GetInstance<IPerformanceService>();

        var showName = service.GetPerformanceTitle(showId);

        return url.Action(MVC.Performance.Details(showId, showName.ToFriendlyUrl()));
    }
}

Which is used like this:

<a href='<%= Url.ForShow(1)%>'>

Essentially I am trying to build a URL with a slug from an entity id. Maybe I'm just going about this in a really daft way.

Ichthyoid answered 6/7, 2011 at 14:50 Comment(1)
Are you using the MVC DependencyResolver?Delayedaction
B
7

There is no way to inject dependencies into an extension method.

For ASP.NET MVC helpers, you are going to have to do some sort of service location - whether you bury that with some sort of abstraction is up to you.

Berni answered 6/7, 2011 at 19:31 Comment(2)
You can inject dependencies into an extension method, simply by passing the dependencies in as method argument (method injection). It is however not really convenient, especially when you need to pass in multiple dependencies.Venality
Good point. I had originally included some demo code to show exactly that, but realized the end result wasn't any prettier.Berni
O
21

I would not recommend doing this. Extension methods are generally best used for simple, well-known operations directly on a type. If your extension method is dependent on having an instance of another type, it is likely that it shouldn't be an extension method to begin with.

Consider making an actual service class that performs this functionality, and injecting it where it's needed. If you really need this in an extension method, consider wrapping the functionality your extension method requires in another static class/method, and avoid using any kind of injection or location.

Sharing some code might shed more light on your specific situation.

Ozzy answered 6/7, 2011 at 15:28 Comment(0)
B
7

There is no way to inject dependencies into an extension method.

For ASP.NET MVC helpers, you are going to have to do some sort of service location - whether you bury that with some sort of abstraction is up to you.

Berni answered 6/7, 2011 at 19:31 Comment(2)
You can inject dependencies into an extension method, simply by passing the dependencies in as method argument (method injection). It is however not really convenient, especially when you need to pass in multiple dependencies.Venality
Good point. I had originally included some demo code to show exactly that, but realized the end result wasn't any prettier.Berni
D
7

You should NOT be calling structuremap directly in your extension method. Also, you should create a testable version that takes an IPerformanceService argument like below:

public static class ShowUrl
{
    public static string ForShow(this UrlHelper url, int showId)
    {
        //Use the MVC DependencyResolver NOT Structuremap directly (DependencyResolver is using structuremap)
        return url.ForShow(showId, DependencyResolver.Current.GetService<IPerformanceService>())
    }

    //For Unit Testing
    public static string ForShow(this UrlHelper url, int showId, IPerformanceService performanceService)
    {
        var showName = performanceService.GetPerformanceTitle(showId);
        return url.Action(MVC.Performance.Details(showId, showName.ToFriendlyUrl()));
    }
}

Now you can pass in a concrete implementation of IPerformanceService in your unit test method.

Assert.Equal("TheUrl", url.ForShow(8, new PerformanceService());

More info on mocking UrlHelper: ASP.NET MVC: Unit testing controllers that use UrlHelper

Donetsk answered 4/9, 2011 at 23:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.