Recently I have read an article about URL and its parts and what is defined in the standard. There is an interesting part about parameters. Usually, you pass parameters in one of the following ways:
However, according to the article there is one more way - to pass parameters in the URL path segments separating them from the segment with a semicolon:
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
I have never encountered this approach before and the article mentions that it is rarely used. Is is supported in .NET, particularly in ASP.NET or ASP.NET Core?
I don't really care if the kind of weird format for query parameters is standard or not. If you try it yourself, you'll see that ASP.NET Core does not support that format. It's still considered a segment and once parsed, if it's not matched by any route patterns, the response is simply 404
.
To support that kind of weird format (I talk about the original format in your question, not another even weirder format in your comment), theoretically you can use a custom QueryStringValueProviderFactory
. The default one creates the QueryStringValueProvider
from Request.Query
. In your custom one, you can create a QueryStringValueProvider
from your own set of parameters which can be parsed from the raw request URL. However this way is not that easy because it's too late for your request to come at the model binding phase (where the value providers are used to build up the request model as well as the action parameters). Because it's too late so your request path does not even match with any route pattern so the pipeline will be short-circuited with a response of 404.
Technically to follow that approach, you need to somehow make it reach the model binding phase first (meaning make the request work as if the semicolon-separated query parameters didn't exist). I think it's possible to remove the last segment (if it contains any semicolon) inside the routing process. However it's of course not easy. That way is simply too complicated.
Here I would like to introduce another simpler (and working) approach. We can use a middleware to parse the URL and build-up the query string (maybe appended to the existing standard query string if any) ourselves before the request coming into the MVC pipeline.
It's just simple like this:
//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();
});
}
}
Now inside the Startup.Configure
method, ensure that your middleware registration is placed before UseRouting
(if any):
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
Now your http://www.blah.com/some/crazy/path.html;param1=foo;param2=bar
should work just like http://www.blah.com/some/crazy/path.html?param1=foo¶m2=bar
. You can even mix the 2 formats together like http://www.blah.com/some/crazy/path.html;param1=foo;param2=bar?param3=ok¶m4=yes
.