如何配置Web Api 2以在单独的项目中查找控制器? (就像我以前在Web Api中所做的那样)

时间:2014-03-19 00:11:03

标签: c# asp.net-web-api asp.net-web-api2

我曾经将我的控制器放在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中这样做?

8 个答案:

答案 0 :(得分:29)

我刚刚确认这很好用。要检查的事项:

参考:您的主Web API项目是否引用了外部类库?

路由:您是否设置了可能会干扰外部控制器的路由?

保护级别:外部资源库中的控制器是public吗?

继承:外部库中的控制器是否继承自ApiController

版本控制:您的Web API项目和类库是否都使用相同版本的Web API库?

如果有帮助,我可以打包我的测试解决方案并将其提供给您。 另外,作为一个注意事项,您不需要告诉Web API使用您添加到Global.asax的行来查找控制器,系统会自动查找控制器,前提是您已将它们引用。

答案 1 :(得分:15)

应该按原样运作。检查表

  • 继承ApiController
  • 使用控制器结束控制器名称。例如。 ValuesController
  • 确保WebApi项目和类库项目引用相同的WebApi程序集
  • 尝试使用属性路由强制路由
  • Clean解决方案,手动删除bin个文件夹并重建
  • 删除Temporary ASP.NET Files个文件夹。 WebApi和MVC缓存控制器查找结果
  • 调用`config.MapHttpAttributeRoutes();确保框架考虑属性路由
  • 确保您正在调用的方法处理正确的HTTP Verb(如果它是GET Web方法,您可以通过浏览器URL调用,如果是POST则必须以其他方式制作Web请求)

这个控制器:

[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.config项目的MVC中使用strong>。