Не удается внедрить зависимости в ASP.NET контроллер Web API с использованием Unity


кто-нибудь имел какой-либо успех, используя контейнер IoC для внедрения зависимостей в ASP.NET контроллеры WebAPI? Кажется, я не могу заставить его работать.

вот что я сейчас делаю.

в своем global.ascx.cs:

    public static void RegisterRoutes(RouteCollection routes)
    {
            // code intentionally omitted 
    }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        IUnityContainer container = BuildUnityContainer();

        System.Web.Http.GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
            t =>
            {
                try
                {
                    return container.Resolve(t);
                }
                catch (ResolutionFailedException)
                {
                    return null;
                }
            },
            t =>
            {
                try
                {
                    return container.ResolveAll(t);
                }
                catch (ResolutionFailedException)
                {
                    return new System.Collections.Generic.List<object>();
                }
            });

        System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container)); 

        BundleTable.Bundles.RegisterTemplateBundles();
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer().LoadConfiguration();

        return container;
    }

мой контроллер завод:

public class UnityControllerFactory : DefaultControllerFactory
            {
                private IUnityContainer _container;

                public UnityControllerFactory(IUnityContainer container)
                {
                    _container = container;
                }

                public override IController CreateController(System.Web.Routing.RequestContext requestContext,
                                                    string controllerName)
                {
                    Type controllerType = base.GetControllerType(requestContext, controllerName);

                    return (IController)_container.Resolve(controllerType);
                }
            }

Он никогда не выглядит в моем файле unity для разрешения зависимостей, и я получаю сообщение об ошибке:

ошибка при попытка создать контроллер типа 'PersonalShopper.Сервисы.Веб-API.Контроллеры.ShoppingListController'. Убедитесь, что контроллер имеет открытый конструктор без параметров.

at Система.Сеть.Http.Диспетчер.DefaultHttpControllerActivator.Создать (HttpControllerContext controllerContext, тип controllerType) в системе.Сеть.Http.Диспетчер.DefaultHttpControllerFactory.CreateInstance (HttpControllerContext controllerContext, HttpControllerDescriptor контроллер-дескриптор) в системе.Сеть.Http.Диспетчер.DefaultHttpControllerFactory.CreateController (HttpControllerContext controllerContext, String controllerName) в системе.Сеть.Http.Диспетчер.HttpControllerDispatcher.SendAsyncInternal (HttpRequestMessage запрос, cancellationToken CancellationToken ) в системе.Сеть.Http.Диспетчер.HttpControllerDispatcher.SendAsync (HttpRequestMessage запрос, cancellationToken CancellationToken)

11 79

11 ответов:

разобрался.

на ApiControllers, MVC 4 использует

есть лучшее решение, которое работает правильно здесь

http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

вы можете взглянуть на единство.Пакет WebApi NuGet, который будет сортировать все это, а также обслуживать компоненты IDisposable.

посмотреть

http://nuget.org/packages/Unity.WebAPI

или

http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package

Microsoft создали пакет для этого.

выполните следующую команду из консоли диспетчера пакетов.

install-package Unity.сеть САШ.Веб-API

Если у вас уже установлен Unity, он спросит, хотите ли вы перезаписать App_Start\UnityConfig.цезий. Ответьте нет и продолжайте.

нет необходимости менять какой-либо другой код и DI (с unity) будет работать.

У меня была та же ошибка, и я искал в интернете решения пару часов. В конце концов оказалось, что мне нужно было зарегистрировать Unity, прежде чем я вызывал WebApiConfig.Реестр. Моя глобальная.asax теперь выглядит как

public class WebApiApplication : System.Web.HttpApplication
{
   protected void Application_Start()
   {
       UnityConfig.RegisterComponents();
       AreaRegistration.RegisterAllAreas();
       GlobalConfiguration.Configure(WebApiConfig.Register);
       FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
       RouteConfig.RegisterRoutes(RouteTable.Routes);
       BundleConfig.RegisterBundles(BundleTable.Bundles);
   }
}

для меня это решило проблему, что Unity не смог решить зависимости в моих контроллерах

в недавнем RC я обнаружил, что больше нет метода SetResolver. Чтобы включить как IOC для контроллера, так и webapi, я использую Unity.WebApi (NuGet) и следующий код:

public static class Bootstrapper
{
    public static void Initialise()
    {
        var container = BuildUnityContainer();

        GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);

        ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new ControllerActivator()));
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        container.Configure(c => c.Scan(scan =>
        {
            scan.AssembliesInBaseDirectory();
            scan.With<UnityConfiguration.FirstInterfaceConvention>().IgnoreInterfacesOnBaseTypes();
        }));

        return container;
    }
}

public class ControllerActivator : IControllerActivator
{
    IController IControllerActivator.Create(RequestContext requestContext, Type controllerType)
    {
        return GlobalConfiguration.Configuration.DependencyResolver.GetService(controllerType) as IController;
    }
}

Я также использую UnityConfiguration (также из NuGet) для магии IoC. ;)

прочитав ответы, мне все равно пришлось много копаться, чтобы приземлиться на этом gotcha, так что здесь это на благо сверстников: Это все, что вам нужно сделать в ASP.NET 4 Web API RC (по состоянию на 8 августа '13):

  1. добавить ссылку на "Microsoft.Практика.Единство.dll " [я на версии 3.0.0.0, добавлено через NuGet]
  2. добавить ссылку на " Unity.Веб-API.dll " [я на версии 0.10.0.0, добавлен через NuGet]
  3. Регистрация сопоставлений типов с помощью контейнер-аналогичен коду в Bootstrapper.cs, который добавляется в ваш проект Unity.Проект веб-API.
  4. в контроллерах, которые наследуют от класса ApiController, создайте параметризованные конструкторы, которые имеют свои типы параметров в качестве сопоставленных типов

и вот, вы получаете зависимости, введенные в ваш конструктор без другой строки кода!

примечание: Я получил эту информацию из одного из комментариев в этой блог его автора.

У меня было такое же исключение, и в моем случае у меня был конфликт между двоичными файлами MVC3 и MVC4. Это мешало моим контроллерам правильно регистрироваться в моем контейнере IOC. Проверьте свою паутину.config и убедитесь, что он указывает на правильные версии MVC.

эта проблема возникает из-за регистрации контроллеров с Unity. Я решил это с помощью регистрации по соглашению, как показано ниже. Пожалуйста, отфильтруйте любые дополнительные типы по мере необходимости.

    IUnityContainer container = new UnityContainer();

    // Do not register ApiControllers with Unity.
    List<Type> typesOtherThanApiControllers
        = AllClasses.FromLoadedAssemblies()
            .Where(type => (null != type.BaseType)
                           && (type.BaseType != typeof (ApiController))).ToList();

    container.RegisterTypes(
        typesOtherThanApiControllers,
        WithMappings.FromMatchingInterface,
        WithName.Default,
        WithLifetime.ContainerControlled);

также В приведенном выше примере используется AllClasses.FromLoadedAssemblies(). Если вы смотрите на загрузку сборок из базового пути, это может работать не так, как ожидалось в проекте веб-API с использованием Unity. Пожалуйста, взгляните на мой ответ на другой вопрос, связанный с этим. https://stackoverflow.com/a/26624602/1350747

у меня была такая же проблема при использовании Unity.NuGet-пакет веб-API. Проблема заключалась в том, что пакет никогда не добавлял вызов UnityConfig.RegisterComponents() в мой глобальный.асакс.

глобальные.асакс.CS должен выглядеть так:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        UnityConfig.RegisterComponents();
        ...
    }
}

краткое резюме для ASP.NET Web API 2.

установить Unity от NuGet.

создать новый класс под названием UnityResolver:

using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;

public class UnityResolver : IDependencyResolver
{
    protected IUnityContainer container;

    public UnityResolver(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            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);
    }

    public void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        container.Dispose();
    }
}

создать новый класс под названием UnityConfig:

public static class UnityConfig
{
    public static void ConfigureUnity(HttpConfiguration config)
    {
        var container = new UnityContainer();
        container.RegisterType<ISomethingRepository, SomethingRepository>();
        config.DependencyResolver = new UnityResolver(container);
    }
}

Редактировать App_Start - > WebApiConfig.cs

public static void Register(HttpConfiguration config)
{
    UnityConfig.ConfigureUnity(config);
    ...

теперь это будет работать.

исходный источник, но немного изменен: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection