如何配置Web Api 2寻找控制器在一个单独的项目?(就像我过去在Web Api中所做的那样)

本文关键字:Api Web 项目 过去 配置 何配置 寻找 控制器 一个 单独 | 更新日期: 2023-09-27 17:51:00

我曾经把我的控制器放在Mvc Web Api的一个单独的类库项目中。我过去常常在我的web api项目的全局文件中添加以下代码行。在单独的项目中查找控制器:

ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");

我从来没有做过任何其他配置,除了添加上面的行。这对我来说一直很有效。

然而,我无法使用上述方法在WebApi2中做同样的事情。这根本行不通。WebApi2项目仍然尝试在它自己的项目的controllers文件夹中找到控制器。

—在2个月后给出一些总结更新(当我开始赏金时):

我已经创建了一个WebApiOne解决方案,它有2个项目,第一个是WebApi项目,第二个是控制器类库。如果我将对控制器类库项目的引用添加到WebApi项目中,一切都如预期的那样工作。例如,如果我去http://mydevdomain.com/api/values,我可以看到正确的输出。

我现在已经创建了第二个名为webapittwo的项目,它有2个项目,第一个是WebApi2项目,第二个是控制器类库。如果我将控制器类库项目的引用添加到WebApi2项目,它不会像预期的那样工作。即,如果我去http://mydevdomain.com/api/values我得到"没有类型被发现,匹配的控制器名为'值'。"

对于第一个项目,我根本没有做任何自定义设置,我没有:

ControllerBuilder.Current.DefaultNamespaces.Add("MyClassLibraryProject.Controllers");

在我的全局。asax,我没有实现StrathWeb在他的两篇博客文章中提出的任何自定义解决方案,因为我认为它不再适用;因为只要把控制器项目的引用添加到WebApi项目中就可以了。

所以我希望所有的工作相同的WebApi2…但事实并非如此。有没有人真的尝试过在WebAPi2中这样做?

如何配置Web Api 2寻找控制器在一个单独的项目?(就像我过去在Web Api中所做的那样)

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

References:你的主Web API项目引用外部类库吗?

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

保护级别:控制器是否在外部库public ?

Inheritance: Do the controllers in the external library from ApiController ?

Versioning:你的Web API项目和类库都使用相同版本的Web API库吗?

如果有帮助的话,我可以把我的测试解决方案打包给你。另外,需要注意的是,您不需要告诉Web API使用添加到Global.asax的行来查找控制器,只要您引用了控制器,系统就会自动查找控制器。

应该是这样的。清单

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

[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;
    }
...
}

我遇到了同样的情况,@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组件自托管,您将遇到此问题。测试时要记住,DefaultAssembliesResolver在第一个WebAPI请求提交之前不会启动(我花了一段时间才意识到这一点)。

你确定你引用的程序集是在IAssembliesResolver服务被调用之前加载的吗?尝试在应用程序中插入一些虚拟代码,例如

var a = new MyClassLibraryProject.Controllers.MyClass();

中的配置方法(但不要忘记,编译器可以"优化"这段代码并完全删除它,如果"a"从不使用)。我也有类似的装配装载顺序问题。最终在启动时与力加载相关的组件。

你需要告诉webapi/mvc加载你引用的程序集。你可以通过web.config中的编译/汇编部分来完成。

<compilation debug="true" targetFramework="4.5.2">
  <assemblies>
    <add assembly="XYZ.SomeAssembly" />
  </assemblies>
</compilation>

就是这么简单。您可以按照@user1821052建议的方式使用代码来完成,但是这个web。配置版本将具有相同的效果。

除了已经说过的:

确保在不同的命名空间中没有两个同名的控制器。

刚刚有一个控制器(foo.UserApiController)应该部分迁移到一个新的命名空间(bar.UserApiController)和URI的情况。旧的控制器按照约定映射到/userapi,新的控制器通过RoutePrefix["api/users"]进行属性路由。直到我将它重命名为bar。userfooapicontroller,新控制器才开始工作。

当使用AttributeRouting时,很容易忘记用Route属性来装饰你的方法,特别是当你在控制器类上使用RoutePrefix属性时。看起来你的控制器组件没有被web api管道接起。

如果你的类库是用EF构建的,那么确保你在App.config中为类库项目指定了连接字符串,在Web.config中为你的Web API MVC项目指定了