我曾经将我的控制器放在Mvc Web Api中的一个单独的类库项目中。我曾经在我的web 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我得到“没有找到与名为'值'的控制器匹配的类型。”
对于第一个项目,我根本没有做任何自定义设置,我没有:
ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");
在我的global.asax中,我没有在他的两篇博文中实现StrathWeb提出的任何自定义解决方案,因为我认为它不再适用了;因为所有工作只是通过将控制器项目的引用添加到WebApi项目。
所以我希望所有人都能为WebApi2工作......但事实并非如此。有没有人真的尝试在WebAPi2中这样做?
答案 0 :(得分:29)
我刚刚确认这很好用。要检查的事项:
参考:您的主Web API项目是否引用了外部类库?
路由:您是否设置了可能会干扰外部控制器的路由?
保护级别:外部资源库中的控制器是public
吗?
继承:外部库中的控制器是否继承自ApiController
?
版本控制:您的Web API项目和类库是否都使用相同版本的Web API库?
如果有帮助,我可以打包我的测试解决方案并将其提供给您。
另外,作为一个注意事项,您不需要告诉Web API使用您添加到Global.asax
的行来查找控制器,系统会自动查找控制器,前提是您已将它们引用。
答案 1 :(得分:15)
应该按原样运作。检查表
ApiController
ValuesController
Clean
解决方案,手动删除bin
个文件夹并重建Temporary ASP.NET Files
个文件夹。 WebApi和MVC缓存控制器查找结果这个控制器:
[RoutePrefix("MyValues")]
public class AbcController : ApiController
{
[HttpGet]
[Route("Get")]
public string Get()
{
return "Ok!";
}
}
匹配此网址:
http://localhost/MyValues/Get
(请注意路线中没有/api/
,因为RoutePrefix
中未指定。{/ p>
控制器查找缓存: This is default controller resolver。您将在源代码中看到它缓存查找结果。
/// <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;
}
...
}
答案 2 :(得分:9)
遇到了同样的情况,@ justmara让我走上了正确的道路。这是如何从@ justmara的答案中完成从属程序集的强制加载:
1)覆盖DefaultAssembliesResolver类
public class MyNewAssembliesResolver : DefaultAssembliesResolver
{
public override 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组件进行自托管,则会遇到此问题。测试时请记住,在提交第一个WebAPI请求之前,DefaultAssembliesResolver不会启动(我花了一些时间才意识到这一点)。
答案 3 :(得分:7)
在调用IAssembliesResolver服务之前,您确定已加载引用的程序集吗? 尝试在您的应用程序中插入一些虚拟代码,例如
var a = new MyClassLibraryProject.Controllers.MyClass();
在配置方法中(但不要忘记,编译器可以&#34;优化&#34;此代码并完全删除它,如果&#34; a&#34;从未使用过)。 我对装配装载订单有类似的问题。在启动时使用强制加载相关组件结束。
答案 4 :(得分:5)
您需要告诉webapi / mvc加载您的引用程序集。您可以使用web.config中的编译/程序集部分执行此操作。
<compilation debug="true" targetFramework="4.5.2">
<assemblies>
<add assembly="XYZ.SomeAssembly" />
</assemblies>
</compilation>
这很简单。您可以使用@ user1821052建议的方式使用代码,但此web.config版本将具有相同的效果。
答案 5 :(得分:2)
除了已经说过的话:
确保在不同的名称空间中没有两个同名的控制器。
只是应该将一个控制器(foo.UserApiController)部分迁移到新的命名空间(bar.UserApiController)和URI。旧控制器按惯例映射到/ userapi,新控制器通过RoutePrefix["api/users"]
进行属性路由。在我将其重命名为bar.UserFooApiController。
答案 6 :(得分:1)
使用AttributeRouting时,很容易忘记使用Route
属性修饰方法,尤其是在控制器类上使用RoutePrefix
属性时。看来你的控制器组件没有被web api管道选中。
答案 7 :(得分:0)
如果您的类库是使用EF
构建的,那么请确保您在类库项目的App.config
中指定了连接字符串 AND 在您的Web API Web.config
项目的MVC
中使用strong>。