有没有办法在 URL 路径段中使用参数 ASP Net/ASP Net Core
Is there a way to work with parameters in URL path segments in ASP Net/ASP Net Core
最近我读了 article 关于 URL 及其部分以及标准中定义的内容。
关于参数有一个有趣的部分。通常,您通过以下方式之一传递参数:
- 在URL路径中作为一个段;
- 在URL查询字符串中;
- 在请求正文中;
- 在请求头中;
但是,根据这篇文章,还有另一种方法 - 在 URL 路径段中传递参数,用分号将它们与段分开:
parameters – talking about parameters, these can also appear after the path but before the query string, also separated from the rest of the URL and from each other by ; characters e.g.:
http://www.blah.com/some/crazy/path.html;param1=foo;param2=bar
我以前从未遇到过这种方法,文章中提到它很少使用。
.NET 是否受支持,特别是 ASP.NET 或 ASP.NET Core?
我真的不在乎这种奇怪的查询参数格式是否标准。如果您自己尝试一下,您会发现 ASP.NET Core 不支持该格式。它仍然被认为是一个段并且一旦被解析,如果它没有被任何路由模式匹配,响应只是 404
.
为了支持那种奇怪的格式(我在你的问题中谈论的是原始格式,而不是你评论中的另一种更奇怪的格式),理论上 你可以使用自定义 QueryStringValueProviderFactory
。默认的从 Request.Query
创建 QueryStringValueProvider
。在您的自定义请求中,您可以根据您自己的一组参数创建一个 QueryStringValueProvider
,这些参数可以从原始请求 URL 中解析。然而,这种方式并不那么容易,因为您的请求在模型绑定阶段(价值提供者用于构建请求模型和操作参数)已经太晚了。因为为时已晚,所以您的请求路径甚至与任何路由模式都不匹配,因此管道将被短路并响应 404.
从技术上讲,要遵循该方法,您需要以某种方式使其首先到达模型绑定阶段(这意味着使请求像分号分隔的查询参数不存在一样工作)。我认为可以删除路由过程中的最后一段(如果它包含任何分号)。然而,这当然并不容易。那种方式实在是太复杂了
在这里我想介绍另一种更简单(并且有效)的方法。我们可以使用中间件来解析 URL 并在请求进入 MVC 管道之前自行构建查询字符串(如果有的话,可能附加到现有的标准查询字符串中)。
就这么简单:
//an extension method for conveniently registering your middleware later
public static class ComplexQueryStringMiddlewareExtensions
{
public static IApplicationBuilder UseComplexQueryStringMiddleware(this IApplicationBuilder appBuilder)
{
return appBuilder.Use((context, next) => {
var path = context.Request.Path;
var semicolonSepParameters = path.Value.Split(';');
//the first part is always the correct path
context.Request.Path = semicolonSepParameters[0];
semicolonSepParameters = semicolonSepParameters.Skip(1).Where(e => !string.IsNullOrWhiteSpace(e)).ToArray();
if (semicolonSepParameters.Length > 0)
{
var appendedQueryString = string.Join("&", semicolonSepParameters);
//in case there is some standard query string as well
if (context.Request.Query != null && context.Request.Query.Count > 0)
{
appendedQueryString = context.Request.QueryString + "&" + appendedQueryString;
} else
{
appendedQueryString = "?" + appendedQueryString;
}
context.Request.QueryString = new Microsoft.AspNetCore.Http.QueryString(appendedQueryString);
}
return next();
});
}
}
现在在 Startup.Configure
方法中,确保你的中间件注册放在 UseRouting
之前(如果有的话):
app.UseComplexQueryStringMiddleware();
//if this exists (which is usually by the default generated code)
//this must be after the above
app.UseRouting();
//of course the UseEndpoints is always at the end
现在您的 http://www.blah.com/some/crazy/path.html;param1=foo;param2=bar
应该像 http://www.blah.com/some/crazy/path.html?param1=foo¶m2=bar
一样工作了。您甚至可以将这两种格式混合在一起,例如 http://www.blah.com/some/crazy/path.html;param1=foo;param2=bar?param3=ok¶m4=yes
.
最近我读了 article 关于 URL 及其部分以及标准中定义的内容。 关于参数有一个有趣的部分。通常,您通过以下方式之一传递参数:
- 在URL路径中作为一个段;
- 在URL查询字符串中;
- 在请求正文中;
- 在请求头中;
但是,根据这篇文章,还有另一种方法 - 在 URL 路径段中传递参数,用分号将它们与段分开:
parameters – talking about parameters, these can also appear after the path but before the query string, also separated from the rest of the URL and from each other by ; characters e.g.:
http://www.blah.com/some/crazy/path.html;param1=foo;param2=bar
我以前从未遇到过这种方法,文章中提到它很少使用。 .NET 是否受支持,特别是 ASP.NET 或 ASP.NET Core?
我真的不在乎这种奇怪的查询参数格式是否标准。如果您自己尝试一下,您会发现 ASP.NET Core 不支持该格式。它仍然被认为是一个段并且一旦被解析,如果它没有被任何路由模式匹配,响应只是 404
.
为了支持那种奇怪的格式(我在你的问题中谈论的是原始格式,而不是你评论中的另一种更奇怪的格式),理论上 你可以使用自定义 QueryStringValueProviderFactory
。默认的从 Request.Query
创建 QueryStringValueProvider
。在您的自定义请求中,您可以根据您自己的一组参数创建一个 QueryStringValueProvider
,这些参数可以从原始请求 URL 中解析。然而,这种方式并不那么容易,因为您的请求在模型绑定阶段(价值提供者用于构建请求模型和操作参数)已经太晚了。因为为时已晚,所以您的请求路径甚至与任何路由模式都不匹配,因此管道将被短路并响应 404.
从技术上讲,要遵循该方法,您需要以某种方式使其首先到达模型绑定阶段(这意味着使请求像分号分隔的查询参数不存在一样工作)。我认为可以删除路由过程中的最后一段(如果它包含任何分号)。然而,这当然并不容易。那种方式实在是太复杂了
在这里我想介绍另一种更简单(并且有效)的方法。我们可以使用中间件来解析 URL 并在请求进入 MVC 管道之前自行构建查询字符串(如果有的话,可能附加到现有的标准查询字符串中)。
就这么简单:
//an extension method for conveniently registering your middleware later
public static class ComplexQueryStringMiddlewareExtensions
{
public static IApplicationBuilder UseComplexQueryStringMiddleware(this IApplicationBuilder appBuilder)
{
return appBuilder.Use((context, next) => {
var path = context.Request.Path;
var semicolonSepParameters = path.Value.Split(';');
//the first part is always the correct path
context.Request.Path = semicolonSepParameters[0];
semicolonSepParameters = semicolonSepParameters.Skip(1).Where(e => !string.IsNullOrWhiteSpace(e)).ToArray();
if (semicolonSepParameters.Length > 0)
{
var appendedQueryString = string.Join("&", semicolonSepParameters);
//in case there is some standard query string as well
if (context.Request.Query != null && context.Request.Query.Count > 0)
{
appendedQueryString = context.Request.QueryString + "&" + appendedQueryString;
} else
{
appendedQueryString = "?" + appendedQueryString;
}
context.Request.QueryString = new Microsoft.AspNetCore.Http.QueryString(appendedQueryString);
}
return next();
});
}
}
现在在 Startup.Configure
方法中,确保你的中间件注册放在 UseRouting
之前(如果有的话):
app.UseComplexQueryStringMiddleware();
//if this exists (which is usually by the default generated code)
//this must be after the above
app.UseRouting();
//of course the UseEndpoints is always at the end
现在您的 http://www.blah.com/some/crazy/path.html;param1=foo;param2=bar
应该像 http://www.blah.com/some/crazy/path.html?param1=foo¶m2=bar
一样工作了。您甚至可以将这两种格式混合在一起,例如 http://www.blah.com/some/crazy/path.html;param1=foo;param2=bar?param3=ok¶m4=yes
.