How can I reuse the same controller class using different constructor arguments

I have a controller that takes some dependency as a constructor argument:

public class AccountsController : ApiController
{
    public AccountsController(IAccountsService accountService)
    {
        this.accountService = accountService;
    }
    // actions
}

public interface IAccountsService
{
    IEnumerable<AccountDto> GetAccounts(string userName);
}

To solve this dependency, I use the Unity.WebApi package:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // other configuration
        config.DependencyResolver = new UnityDependencyResolver(myContainer);
    }
}

I have two different implementations IAccountsService, and I would like to expose them both using the same controller class. In terms of routing, I would like to use different paths at the controller level and the same basic path structure for actions and parameters.

My way is to inherit two controllers from AccountsControllerand register them in UnityContainerto use different implementations IAccountsService.

public class Accounts1Controller : AccountsController
{
    public Accounts1Controller([Dependency("Service1")]IAccountsService accountService) :
        base(accountService) { }
}

public class Accounts2Controller : AccountsController
{
    public Accounts2Controller([Dependency("Service2")]IAccountsService accountService) :
        base(accountService) { }
}

Is there an easier way to do this?

- ( DI - Unity ).

+4
1

:

, :

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

config.Routes.MapHttpRoute(
    name: "DefaultApi2",
    routeTemplate: "api2/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

Unity URL- :

//Map IAccountsService to AccountsService1 with name Service1
container.RegisterType<IAccountsService, AccountsService1>("Service1");

//Map IAccountsService to AccountsService2 with name Service2
container.RegisterType<IAccountsService, AccountsService2>("Service2");

//At composition time, map IAccountsService to appropriate
//service based on Url
container.RegisterType<IAccountsService>(new InjectionFactory(c =>
{
    var pathAndQuery = HttpContext.Current.Request.Url.PathAndQuery;

    if(pathAndQuery.StartsWith("/api2"))
        return c.Resolve<IAccountsService>("Service2");
    else if(pathAndQuery.StartsWith("/api"))
        return c.Resolve<IAccountsService>("Service1");

    throw new Exception("Unexpected Url");
}));

UPDATE:

, Self-Hosting, HttpContext.Current null.

, IHttpControllerActivator. , HttpRequestMessage.

IHttpControllerActivator:

public class MyControllerActivator : IHttpControllerActivator
{
    public IHttpController Create(
        HttpRequestMessage request,
        HttpControllerDescriptor controllerDescriptor,
        Type controllerType)
    {
        if (controllerType == typeof (ValuesController))
        {
            var pathAndQuery = request.RequestUri.PathAndQuery;

            IAccountsService svc;

            if (pathAndQuery.StartsWith("/api2"))
                svc = new Service2();
            else if (pathAndQuery.StartsWith("/api"))
                svc = new Service1();
            else 
                throw new Exception("Unexpected Url");

            return new ValuesController(svc);
        }

        throw new Exception("Unexpected Controller Type");
    }
}

.

, DI (, , Pure DI), .

, DependencyResolver, .

+2

Source: https://habr.com/ru/post/1657253/


All Articles