Как я могу передать два разных параметра строки запроса, которые представляют один параметр метода действия?
-
22-09-2019 - |
Вопрос
у меня есть метод действия, подобный следующему
public JsonResult Index(string version)
{
.. do stuff, return some data v1 or v2. Default = v2.
}
Итак, этот метод действия возвращает некоторые данные, которые можно отформатировать как Version 1
или Version 2
(какой бы результат это ни был...просто знайте, что они схематически разные).
Итак, когда пользователь хочет получить доступ к этому ресурсу, он делает следующее:
http://www.blah.com/api/Index
ничего слишком сложного.
они тоже могут это сделать...
http://www.blah.com/api/Index?version=1.0
НО, можно ли сделать так, чтобы пользователь мог использовать параметры строки запроса version
или v
eg. http://www.blah.com/api/Index?v=1.0
и это заполнит параметр версии в ActionMethod.Возможный?
Решение
Я предполагаю, что вы могли бы манипулировать параметрами метода действия, используя фильтр действий.
По сути, просто проверьте наличие буквы «v» в QueryString
коллекцию, и если она существует, бросить ее в ActionParameters
коллекция.
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var version = filterContext.HttpContext.Request.QueryString["v"];
if (!string.IsNullOrEmpty(version))
filterContext.ActionParameters["version"] = version;
}
ХТХ,
Чарльз
РЕДАКТИРОВАТЬ:Сделав это немного более общим...
public class QueryStringToActionParamAttribute : ActionFilterAttribute
{
private string _queryStringName;
private string _actionParamName;
public QueryStringToActionParamAttribute(string queryStringName, string actionParamName)
{
_queryStringName = queryStringName;
_actionParamName = actionParamName;
}
public override void OnActionExecuting(ActionExecutedContext filterContext)
{
var queryStringValue = filterContext.HttpContext.Request.QueryString[_queryStringName];
if (!string.IsNullOrEmpty(queryStringValue))
{
filterContext.ActionParameters[_actionParamName] = queryStringValue;
}
}
}
Тогда вы могли бы назвать это так:
[QueryStringToActionParam("v", "version")];
Другие советы
Альтернативный способ управления версиями API — это фактически иметь разные версии контроллера для каждой версии API, таким образом вам не нужно выполнять всю проверку каждого номера версии в каждом методе действия.Каждый контроллер применим только к одной версии API.
Для меня это более чистое (IMO) управление версиями во время маршрута, а не во время действия.Вы можете сделать это с помощью ограничения маршрутизации, чтобы проверить номер версии.
В приведенном ниже примере контроллеры V10 и V20 могут быть направлены только в том случае, если ограничение маршрута пройдено, т.е.заголовок присутствовал, если его нет, используется значение по умолчанию (v2).:
routes.MapRoute(
"EmployeeListingv1",
"employees",
new { controller = "V10Employees", action = "Index" }, // Parameter defaults
new { ApiV = new ApiVersionConstraint(ApiVersion.Version10) }
);
routes.MapRoute(
"EmployeeListingv2",
"employees",
new { controller = "V20Employees", action = "Index" }, // Parameter defaults
new { ApiV = new ApiVersionConstraint(ApiVersion.Version20) }
);
Вы можете сделать это, используя строку запроса, чтобы передать версию, как вы сейчас это делаете, и просто перейти к ограничению маршрута, однако мне было проще поддерживать использование дополнительного заголовка в запросе.(это также более «RESTful», если не вдаваться в подробности всей этой дискуссии).Отсутствие заголовка означает версию API по умолчанию (последнюю).
Пример ограничения версии API:
/// <summary>
/// Enable routing of requests to controllers based on the
/// API version contained in the header.
/// </summary>
public class ApiVersionConstraint : IRouteConstraint
{
const string VersionHeader = "X-MY-API-NAME-HERE-VERSION";
private ApiVersion _version = ApiVersion.Unsupported;
public ApiVersionConstraint(ApiVersion version)
{
this._version = version;
}
#region IRouteConstraint Members
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
string vers = string.Empty;
if (httpContext.Request.Headers[VersionHeader] != null)
{
vers = httpContext.Request.Headers[VersionHeader];
}
else
{
vers = "2.0"; // set default here.
}
ApiVersion fromHeader = ApiVersion.Unsupported;
switch (vers)
{
case "1.0":
{
fromHeader = ApiVersion.Version10;
break;
}
case "2.0":
{
fromHeader = ApiVersion.Version20;
break;
}
default:
{
fromHeader = ApiVersion.Unsupported;
break;
}
}
return fromHeader == _version;
}
#endregion
}
Просто чтобы добавить что-то еще к этому старому вопросу...Вы можете комбинировать методы здесь и поддерживать выбор версии по заголовку запроса ИЛИ строке запроса, изменив проверку в ответе @Rosstified, включив в нее проверку QueryString:
if (httpContext.Request.Headers[VersionHeader] != null) {
vers = httpContext.Request.Headers[VersionHeader];
} else {
if (httpContext.Request.QueryString["v"] != null) {
vers = httpContext.Request.QueryString["v"];
} else {
vers = "1.0"; // set default here.
}
}