具有两个GET操作的WebApi控制器

时间:2013-03-28 12:04:41

标签: c# asp.net-mvc-4 asp.net-web-api

我希望有两个不同的GET操作来查询数据,名称和ID,

我有这些路线:

        config.Routes.MapHttpRoute(
            name: "ActionApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "ActionApiByName",
            routeTemplate: "api/{controller}/{action}/{name}",
            defaults: new { name = RouteParameter.Optional }
        );

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );

以及控制器中的这些操作:

    [HttpGet]
    public CompanyModel CompanyId(Guid id)
    {
          //Do something
    }


    [HttpGet]
    public CompanyModel CompanyName(string name)
    {
            //Do something
    }

这样的调用:http://localhost:51119/api/companies/CompanyId/3cd97fbc-524e-47cd-836c-d709e94c5e1e可以运行并进入'CompanyId'方法,

http://localhost:51119/api/companies/CompanyName/something的类似调用让我找不到404

但是这个: 'http://localhost:51119/api/companies/CompanyName/?name=something'工作正常

任何人都可以解释这种行为吗?我做错了什么?

1 个答案:

答案 0 :(得分:10)

Web API路由选择器无法知道URL末尾的字符串是否为GUID。因此,不是为适当的GET操作选择正确的路线。

为了选择正确的路线,您需要为GUID uri模板添加路线约束。

    public class GuidConstraint : IHttpRouteConstraint
    {
        public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, IDictionary<string, object> values,
                          HttpRouteDirection routeDirection)
        {
            if (values.ContainsKey(parameterName))
            {
                string stringValue = values[parameterName] as string;

                if (!string.IsNullOrEmpty(stringValue))
                {
                    Guid guidValue;

                    return Guid.TryParse(stringValue, out guidValue) && (guidValue != Guid.Empty);
                }
            }

            return false;
        }
    }

然后,将约束添加到将处理GUID的路由。

config.Routes.MapHttpRoute(
            name: "ActionApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional },
            constraints: new { id = new GuidConstraint() }  // Added
        );

由于此路由比一般的“字符串”路由更具体,因此需要将其放置在要解析名称的路径上方。

这应该适当地路由到行动。

希望这有帮助。