Url.Action返回带有路由attrubute的webapi操作的错误URL

时间:2018-12-30 14:37:27

标签: asp.net asp.net-web-api url-routing asp.net-mvc-routing

我对Url.Action()的行为有疑问;

我有一个webapi,其中所有控制器都需要显式的路由前缀属性,而所有操作都需要一个路由属性。

我在WebApiConfig.cs中注册了路由

 var constraintResolver = new DefaultInlineConstraintResolver()
            {
                ConstraintMap =
                {
                    ["apiVersion"] = typeof( ApiVersionRouteConstraint )
                }
            };
            config.MapHttpAttributeRoutes(constraintResolver);

我目前已注释掉下面的行,但是(因为)它没有更改错误的行为:

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

我的控制器如下:

 [RoutePrefix("api/v{version:apiVersion}/programs")]
 public class ProgramsController : ApiController
 {
    [HttpGet, Route("{telemetryKey}/versions/latest")]
    public async Task<LatestVersionResponse> GetLatestVersionInfo(Guid telemetryKey)
    {
        // serious business logic
    }

 }

我希望'@Url.Action("GetLatestVersionInfo", "Programs", new { telemetryKey = Guid.Parse("43808405-afca-4abb-a92a-519489d62290") })'

应返回/api/v1/programs/43808405-afca-4abb-a92a-519489d62290/versions/latest

但是,我却得到/Programs/GetLatestVersionInfo?telemetryKey=43808405-afca-4abb-a92a-519489d62290。因此,我的routeprefix和route属性将被忽略。

Swagger正确地发现了我的路线,并且我可以验证对预期路线的请求是否正常运行-只是Url.Action()令人困惑。

enter image description here

有什么问题...?

2 个答案:

答案 0 :(得分:0)

尝试以下操作:

命名您的路线:

[HttpGet, Route("{telemetryKey}/versions/latest", Name="LatestVersionInfoRoute")]
    public async Task<LatestVersionResponse> GetLatestVersionInfo(Guid telemetryKey)
    {
        // serious business logic
    }

使用Url.Link方法:

@Url.Link("LatestVersionInfoRoute", new { telemetryKey = Guid.Parse("43808405-afca-4abb-a92a-519489d62290") })

答案 1 :(得分:0)

好吧,看来有些错误。

错误的助手: 我应该使用Url.HttpRouteUrl从剃刀视图生成API链接(Url.Link用于从API控制器内部生成链接)

与aspnet-api-versioning 库冲突 由于某种原因(也许是错误?),我在控制器上使用的前缀(apiVersion变量)破坏了URL帮助器机制。

目前,我已经放弃了aspnet-api-versioning库,但是在他们的github仓库上创建了一个问题,以防万一它是一个错误。

由于我真的很讨厌创建和维护魔术字符串的想法,因此我采取了以下方法-每个控制器都有一个公共静态类,其中包含路由名称的const值:

[RoutePrefix("api/v1/developers")]
public class DevelopersController : ApiController
{
    [HttpGet, Route("{developerId}/programs", Name = Routes.GetPrograms)]
    public async Task<IEnumerable<Program>> GetPrograms(Guid developerId){}

    public static class Routes
    {
        public const string GetPrograms = nameof(DevelopersController) +"."+ nameof(DevelopersController.GetPrograms);
    }
}

现在可以从剃须刀控制器以简单且相对安全的方式使用它:

@Url.HttpRouteUrl(DevelopersController.Routes.GetPrograms, new { developerId = /* uniquest of guids */})

比魔术弦好。我还为控制器添加了一堆单元测试,可以验证每个路由的唯一性和正确性,以及路由类仅包含其所包含操作的路由。