C# WebApi–;控制器继承–;方法的新版本

C# WebApi–;控制器继承–;方法的新版本,c#,asp.net-mvc,asp.net-web-api,asp.net-mvc-routing,asp.net-web-api-routing,C#,Asp.net Mvc,Asp.net Web Api,Asp.net Mvc Routing,Asp.net Web Api Routing,我使用WebAPI2。我在version1中提供客户机方法: http://localhost/version1/api/base http://localhost/version1/api/values 它是地雷控制员: [RoutePrefix("version1")] public class ValuesController : ApiController { [Route("api/base")] public string GetBaseMethod()

我使用WebAPI2。我在version1中提供客户机方法:

http://localhost/version1/api/base 
http://localhost/version1/api/values
它是地雷控制员:

[RoutePrefix("version1")]
public class ValuesController : ApiController
{
    [Route("api/base")]
    public string GetBaseMethod()
    {
        return "bbb";
    }

    [Route("api/values")]
    public string GetVersion1()
    {
        return "aaa";
    }   
}
现在,我想以version2方法提供客户机:

  • /version2/api/base(方法与version1相同)
  • /version2/api/values(方法已更改,现在它返回int,而不是string,但地址必须与version1:/api/values中的地址相同)
我有第二个继承控制器:

[RoutePrefix("version2")]
public class Values2Controller : ValuesController
{
    [Route("api/values")]
    public int GetVersion2()
    {
        return 5;
    }
}
我已在WebApiConfig.cs中启用属性路由继承:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );          
    }
}

public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
    protected override IReadOnlyList<IDirectRouteFactory> GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
    {
        return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>(inherit: true);
    }
}
公共静态类WebApiConfig
{
公共静态无效寄存器(HttpConfiguration配置)
{
config.maphttpAttribute路由(新的CustomDirectRouteProvider());
config.Routes.MapHttpRoute(
名称:“DefaultApi”,
routeTemplate:“api/{controller}/{id}”,
默认值:新建{id=RouteParameter.Optional}
);          
}
}
公共类CustomDirectRouteProvider:DefaultDirectRouteProvider
{
受保护的重写IReadOnlyList GetActionRouteFactorys(HttpActionDescriptor actionDescriptor)
{
返回actionDescriptor.GetCustomAttributes(继承:true);
}
}
结果:

http://localhost/version1/api/base

  • 它起作用了
http://localhost/version2/api/base

  • 它起作用了
http://localhost/version1/api/values

  • 它起作用了
http://localhost/version2/api/values

  • 它不起作用。我有错误
{ “消息”:“发生错误。”, “ExceptionMessage”:“找到多个与请求匹配的操作:\r\n类型上的nGetVersion2” WebApplication1.Controller.Values2Controller\r\n类型上的版本1 WebApplication1.Controller.Values2Controller“, “异常类型”:“System.InvalidOperationException”, “StackTrace”:“w System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)\r\n w System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n w System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext,CancellationToken CancellationToken)\r\n w System.Web.Http.Dispatcher.HttpControllerDispatcher.d_u1.MoveNext() }

我能做什么?


我相信这是同样的问题。您需要“api/{controller}/{action}/{id}”

我可以重新创建您的问题。只有当我将原始的GetVersion1虚拟化,将返回类型更改为更一般的对象,然后在继承的类中重写它时,我才能使用不同的变体

像这样:

[RoutePrefix("version1")]
public class ValuesController : ApiController {
    [Route("api/base")]
    public string GetBaseMethod() {
        return "bbb";
    }

    [Route("api/values")]
    public virtual object GetVersion1() {
        return "aaa";
    }
}

[RoutePrefix("version2")]
public class Values2Controller : ValuesController {

    public override object GetVersion1() {
        return 5;
    }
}
一旦存在冲突的路由属性并启用了路由继承,它就会像您所指出的那样失败

这让我思考。如果您打算使用继承,那么为什么不将其作为路由处理呢。因此,我最终决定以您的例子为例:

这将允许我在将来的版本中更改基础返回值,而不会发生路由冲突

结果:

http://localhost/version1/api/base

  • 它有效。=>“bbb”
http://localhost/version2/api/base

  • 它有效。=>“bbb”
http://localhost/version1/api/values

  • 它有效。=>“aaa”
http://localhost/version2/api/values

  • 它有效。=>五,

您好,您找到解决问题的方法了吗?我面临着同样的问题……这个问题有解决方法吗?我相信有几个问题:1。您应该让基类的方法是虚拟的,这样您就可以在实现基类2的类中重写它。您应该只在基类上具有
Route
属性,在实现基类的类中再次指定它会导致冲突。还需要注意的是,您只在基类的虚拟方法上指定
Route
属性。在重写它们的类上指定它们会导致冲突。如何停止从version2访问GetBaseMethod?我想让用户知道此方法在version2上不可用。
[RoutePrefix("version1")]
public class ValuesController : ApiController {
    [Route("api/base")]
    public virtual HttpResponseMessage GetBaseMethod() {
        return Request.CreateResponse("bbb");
    }

    [Route("api/values")]
    public virtual HttpResponseMessage GetVersion1() {
        return Request.CreateResponse("aaa");
    }
}

[RoutePrefix("version2")]
public class Values2Controller : ValuesController {

    public override HttpResponseMessage GetVersion1() {
        return Request.CreateResponse(5);
    }
}