经过多次尝试和阅读文章后,我决定将我的问题放在这里。我想要的是:我正在研究应用程序的 api 版本控制。 .NET Core 支持的版本格式(Microsoft.AspNetCore.Mvc.Versioning
package) 是 Major.Minor,这就是我想在我从事的项目中使用的。我想要的是一个后备版本,以防客户端未指定次要版本。
我正在使用 .NET core 2.2,并使用api-version
标头中指定。相应的 API 版本控制配置如下所示:
services.AddApiVersioning(options => {
options.ReportApiVersions = true;
options.ApiVersionReader = new HeaderApiVersionReader("api-version");
options.ErrorResponses = new ApiVersioningErrorResponseProvider();
});
我每个版本都有以下两个控制器:(为了解决这个问题,控制器被简化了):
[ApiVersion("1.0")]
[Route("api/[controller]")]
public class ValueControllerV10 : Controller
{
[HttpGet(Name = "collect")]
public String Collect()
{
return "Version 1.0";
}
}
[ApiVersion("1.1")]
[Route("api/[controller]")]
public class ValueControllerV11 : Controller
{
[HttpGet(Name = "collect")]
public String Collect()
{
return "Version 1.1";
}
}
如果客户指定api-version=1.0
然后使用 ValueControllerV10。当然,如果客户指定api-version=1.1
,然后按预期使用 ValueControllerV11。
现在我的问题来了。如果客户指定api-version=1
(因此只有主要版本而没有次要版本),则使用ValueControllerV10。这是因为ApiVersion.Parse("1")
等于ApiVersion.Parse("1.0")
, 如果我没有记错的话。但在这种情况下我想要的是调用给定主要版本的最新版本,在我的示例中为 1.1。
我的尝试:
First:指定[ApiVersion("1")]
at ValueControllerV11
[ApiVersion("1")]
[ApiVersion("1.1")]
[Route("api/[controller]")]
public class ValueControllerV11 : Controller
{
[HttpGet(Name = "collect")]
public String Collect()
{
return "Version 1.1";
}
}
它不起作用,它导致
AmbiguousMatchException: The request matched multiple endpoints
为了解决这个问题,我想出了第二种方法:
Second:使用自定义IActionConstraint
。为此,我遵循了这些文章:
- https://stevenknox.net/aspnet-core-mvc-action-priority-using-actionconstraints/ https://stevenknox.net/aspnet-core-mvc-action-priority-using-actionconstraints/
- https://www.strathweb.com/2017/06/using-iactionconstraints-in-asp-net-core-mvc/ https://www.strathweb.com/2017/06/using-iactionconstraints-in-asp-net-core-mvc/
然后我创建了以下类:
[AttributeUsage(AttributeTargets.Method)]
public class HttpRequestPriority : Attribute, IActionConstraint
{
public int Order
{
get
{
return 0;
}
}
public bool Accept(ActionConstraintContext context)
{
var requestedApiVersion = context.RouteContext.HttpContext.GetRequestedApiVersion();
if (requestedApiVersion.MajorVersion.Equals(1) && !requestedApiVersion.MinorVersion.HasValue)
{
return true;
}
return false;
}
}
并用于ValueControllerV11
:
[ApiVersion("1")]
[ApiVersion("1.1")]
[Route("api/[controller]")]
public class ValueControllerV11 : Controller
{
[HttpGet(Name = "collect")]
[HttpRequestPriority]
public String Collect()
{
return "Version 1.1";
}
}
嗯,它解决了AmbiguousMatchException
,但会覆盖默认行为Microsoft.AspNetCore.Mvc.Versioning
打包所以如果客户端使用api-version 1.1
,然后她得到 404 Not Found 返回,根据执行情况这是可以理解的HttpRequestPriority
Third: Using MapSpaFallbackRoute
in Startup.cs
, 有条件的:
app.MapWhen(x => x.GetRequestedApiVersion().Equals("1") && x.GetRequestedApiVersion().MinorVersion == null, builder =>
{
builder.UseMvc(routes =>
{
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new {controller = nameof(ValueControllerV11), action = "Collect"});
});
});
app.UseMvc();
也不起作用,没有任何影响。名字MapSpaFallbackRoute
也给我一种感觉,这不是我需要使用的......
所以我的问题是:当未指定次要版本时,如何引入后备“使用最新”行为api-version
?提前致谢!