如何传递代表一个动作方法参数的两个不同的查询字符串参数?

时间:2010-02-22 23:21:57

标签: .net asp.net-mvc actionmethod

我有一个像下面这样的动作方法

public JsonResult Index(string version)
{
   .. do stuff, return some data v1 or v2. Default = v2.
}

因此,此操作方法返回一些数据,可以将其格式化为Version 1Version 2(无论输出是什么......只知道它们在逻辑上不同)。

因此,当用户想要调用访问此资源时,请执行以下操作:

http://www.blah.com/api/Index
没什么太难的。

他们也可以这样做......

http://www.blah.com/api/Index?version=1.0

但是,是否可以使用户可以使用查询字符串参数versionv

eg. http://www.blah.com/api/Index?v=1.0 

这将填充ActionMethod中的version参数。可能的?

3 个答案:

答案 0 :(得分:3)

我猜你可以使用动作过滤器操作动作方法参数。

基本上只需检查QueryString集合中的“v”,如果存在,请将其放入ActionParameters集合中。

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var version = filterContext.HttpContext.Request.QueryString["v"];
    if (!string.IsNullOrEmpty(version))
        filterContext.ActionParameters["version"] = version;
}

HTHS,
查尔斯

编辑:让它更通用......

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")];

答案 1 :(得分:0)

处理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
}

答案 2 :(得分:0)

只是为这个旧问题添加更多内容......您可以在这里结合使用这些技术,因此通过更改@ 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.
            }
        }