Как я могу передать два разных параметра строки запроса, которые представляют один параметр метода действия?

StackOverflow https://stackoverflow.com/questions/2315046

  •  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.
            }
        }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top