Как настроить Web Api 2 для поиска контроллеров в отдельном проекте? (так же, как я делал в Web Api)
Я использовал для размещения контроллеров в отдельном проекте библиотеки классов в Mvc Web Api. Раньше я добавлял следующую строку в мой веб-проект api global.asax для поиска контроллеров в отдельном проекте:
ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");
Мне никогда не приходилось выполнять какую-либо другую конфигурацию, кроме добавления вышеприведенной строки. Это всегда срабатывало для меня.
Однако я не могу использовать вышеуказанный метод, чтобы сделать то же самое в WebApi2. Это просто не работает. Проект WebApi2 по-прежнему пытается найти контроллеры в своей собственной папке диспетчера проектов.
- Предоставление небольшого сводного обновления через 2 месяца (Поскольку я начал щедрость на этом):
Я создал решение WebApiOne, у него есть 2 проекта, первый - проект WebApi, а второй - библиотека классов для контроллеров. Если я добавлю ссылку на проект библиотеки классов контроллеров в проект WebApi, все будет работать так, как ожидалось. то есть, если я перейду к http://mydevdomain.com/api/values, я могу увидеть правильный вывод.
Теперь я создаю второй проект под названием WebApiTwo, у него есть 2 проекта, первый - проект WebApi2, а второй - библиотека классов для контроллеров. Если я добавлю ссылку на проект библиотеки классов контроллеров в проект WebApi2, он не будет работать должным образом. то есть, если я перехожу к http://mydevdomain.com/api/values, я получаю "Тип не найден, который соответствует контроллеру с именем" values".
для первого проекта я вообще не выполняю никаких пользовательских настроек, у меня нет:
ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");
в моем global.asax, и я не реализовал какие-либо пользовательские решения, предложенные StrathWeb в двух своих блогах, поскольку я думаю, что он больше не применим; потому что все работает только путем добавления ссылки проекта контроллера на проект WebApi.
Итак, я бы ожидал, что все будут работать одинаково для WebApi2... но это не так. Кто-нибудь действительно пытался сделать это в WebAPi2?
Ответы
Ответ 1
Я только что подтвердил, что это работает отлично. Что нужно проверить:
Ссылки: Связан ли ваш основной проект веб-API с внешней библиотекой классов?
Маршрутизация: Установили ли вы какие-либо маршруты, которые могут мешать внешним контроллерам?
Уровень защиты: Являются ли контроллеры во внешней библиотеке public
?
Наследование: Выполняют ли контроллеры во внешней библиотеке от ApiController
?
Версии: Являются ли оба проекта веб-API и библиотека классов одинаковой версией библиотек веб-API?
Если это поможет, я могу упаковать свое тестовое решение и сделать его доступным для вас.
Кроме того, в качестве отправной точки вам не нужно указывать веб-API, чтобы найти контроллеры с линией, добавленной в Global.asax
, система автоматически находит контроллеры, если вы ссылаетесь на них.
Ответ 2
Он должен работать так, как есть. Контрольный список
- Наследовать
ApiController
- Введите имя контроллера с помощью контроллера. Например.
ValuesController
- Убедитесь, что проект проекта WebApi и библиотеки классов ссылаются на те же сборки WebApi
- Попробуйте использовать маршруты с помощью маршрутизации атрибутов
-
Clean
, вручную удалите папки bin
и перестройте
- Удалить папки
Temporary ASP.NET Files
. Результат поиска контроллера кэша WebApi и MVC
- Вызов `config.MapHttpAttributeRoutes(); для обеспечения того, чтобы структура учитывала маршруты атрибутов
- Убедитесь, что метод, который вы вызываете, предназначен для обработки правильного HTTP-глагола (если это веб-метод GET, вы можете вызывать через URL-адрес браузера, если это POST, вам нужно создать веб-запрос)
Этот контроллер:
[RoutePrefix("MyValues")]
public class AbcController : ApiController
{
[HttpGet]
[Route("Get")]
public string Get()
{
return "Ok!";
}
}
соответствует этому URL:
http://localhost/MyValues/Get
(обратите внимание, что в маршруте нет /api/
, потому что он не указан в RoutePrefix
.
Кэширование поиска контроллера:
Это контроллер контроллера по умолчанию. Вы увидите в исходном коде, что он кэширует результат поиска.
/// <summary>
/// Returns a list of controllers available for the application.
/// </summary>
/// <returns>An <see cref="ICollection{Type}" /> of controllers.</returns>
public override ICollection<Type> GetControllerTypes(IAssembliesResolver assembliesResolver)
{
HttpControllerTypeCacheSerializer serializer = new HttpControllerTypeCacheSerializer();
// First, try reading from the cache on disk
List<Type> matchingTypes = ReadTypesFromCache(TypeCacheName, IsControllerTypePredicate, serializer);
if (matchingTypes != null)
{
return matchingTypes;
}
...
}
Ответ 3
Выполнялся в том же сценарии, и @justmara установил меня по правильному пути. Здесь, как выполнить силовую нагрузку зависимых сборок от @justmara, ответьте:
1) Переопределить класс DefaultAssembliesResolver
public class MyNewAssembliesResolver : DefaultAssembliesResolver
{
public virtual ICollection<Assembly> GetAssemblies()
{
ICollection<Assembly> baseAssemblies = base.GetAssemblies();
List<Assembly> assemblies = new List<Assembly>(baseAssemblies);
var controllersAssembly = Assembly.LoadFrom(@"Path_to_Controller_DLL");
baseAssemblies.Add(controllersAssembly);
return baseAssemblies;
}
}
2) В разделе конфигурации замените значение по умолчанию новой реализацией
config.Services.Replace(typeof(IAssembliesResolver), new MyNewAssembliesResolver());
Я объединил этот синтаксис вместе с помощью указателей из этого блога:
http://www.strathweb.com/2013/08/customizing-controller-discovery-in-asp-net-web-api/
Как уже говорили другие, вы знаете, если вы столкнулись с этой проблемой, если вы вынуждаете контроллер загружать, напрямую ссылаясь на него. Другим способом является, например, результат CurrentDomain.GetAssemblies()
и посмотреть, находится ли ваша сборка в списке.
Кроме того: если вы являетесь владельцем собственного хостинга с использованием компонентов OWIN, вы будете сталкиваться с этим. При тестировании следует помнить, что DefaultAssembliesResolver НЕ будет работать до тех пор, пока не будет отправлен первый запрос WebAPI (мне потребовалось некоторое время, чтобы понять это).
Ответ 4
Вы уверены, что ваша ссылка на сборку была загружена ПЕРЕД вызовом службы IAssembliesResolver?
Попробуйте вставить какой-нибудь фиктивный код в ваше приложение, что-то вроде
var a = new MyClassLibraryProject.Controllers.MyClass();
в режиме настройки (но не забывайте, что компилятор может "оптимизировать" этот код и полностью удалить его, если "а" никогда не используется).
У меня была аналогичная проблема с порядком загрузки сборки. Завершены с зависимыми от нагрузки сбоями при запуске.
Ответ 5
Вам нужно сообщить webapi/mvc, чтобы загрузить вашу сборку. Вы делаете это с разделом компиляции/сборки в вашем web.config.
<compilation debug="true" targetFramework="4.5.2">
<assemblies>
<add assembly="XYZ.SomeAssembly" />
</assemblies>
</compilation>
Просто. Вы можете сделать это с кодом, как предложил @user1821052, но эта версия web.config будет иметь тот же эффект.
Ответ 6
Помимо уже сказанного:
Убедитесь, что у вас нет двух контроллеров с одинаковым именем в разных пространствах имен.
Просто был случай, когда один контроллер (foo.UserApiController) должен быть частично перенесен в новое пространство имен (bar.UserApiController) и URI. Старый контроллер был сопоставлен по соглашению с /userapi, новый был маршрутизирован атрибутом через RoutePrefix["api/users"]
. Новый контроллер не работал, пока я не переименовал его в bar.UserFooApiController.
Ответ 7
При использовании AttributeRouting легко забыть украшать ваши методы с помощью атрибута Route
, особенно если вы используете атрибут RoutePrefix
в классе контроллера. Кажется, что ваша сборка контроллера не была захвачена конвейером веб-api.
Ответ 8
Если ваша библиотека классов построена с помощью EF
, то убедитесь, что у вас есть строка соединения, указанная в App.config
для проекта библиотеки классов, И в Web.config
для вашего веб-API MVC
.