Не удается внедрить зависимости в 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 ответов:
есть лучшее решение, которое работает правильно здесь
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):
- добавить ссылку на "Microsoft.Практика.Единство.dll " [я на версии 3.0.0.0, добавлено через NuGet]
- добавить ссылку на " Unity.Веб-API.dll " [я на версии 0.10.0.0, добавлен через NuGet]
- Регистрация сопоставлений типов с помощью контейнер-аналогичен коду в Bootstrapper.cs, который добавляется в ваш проект Unity.Проект веб-API.
- в контроллерах, которые наследуют от класса 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