【问题标题】:Multiple HttpRoute in ASP.NET MVC 4ASP.NET MVC 4 中的多个 HttpRoute
【发布时间】:2012-11-22 05:27:16
【问题描述】:

我正在尝试在 Web API 中创建一个 RouteConfig,它允许以下模式:

模式:

/api/{controller}
/api/{controller}/{id} (int, optional)

/api/{controller}/{action}
/api/{controller}/{action}/{id} (int, optional)

用例:

/api/profile/ (get all profiles)
/api/profile/13 (get profile number 13)

/api/profile/sendemail/ (send email to all profiles)
/api/profile/sendmail/13 (send email to profile number 13)

我正在尝试以下内容:

routes.MapHttpRoute(
    name: "ControllerAndID",
    routeTemplate: "api/{controller}/{id}",
    defaults: null,
    constraints: new { id = @"^\d+$" } // Dekkar heiltölur eingöngu í id parameter
);

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

我得到的错误是:

找到多个与请求匹配的操作: \r\nMinarSidur.Models.DataTransfer.UserProfileDTO sendmail(System.String) 关于类型 MinarSidur.Controllers.ProfileController\r\nMinarSidur.Models.DataTransfer.UserProfileDTO 类型 MinarSidur.Controllers.ProfileController 上的 sendpaycheck(System.String)

你能帮我完成这个吗?

【问题讨论】:

    标签: asp.net-mvc-4 routes asp.net-web-api


    【解决方案1】:

    您的异常实际上是在抱怨 Profile 控制器上这两种方法之间存在冲突:

    • 发送工资单(字符串)
    • 发送邮件(字符串)

    不是 Get 和 Get(?);虽然这也是一个问题。

    确实,在执行 RPC 操作以进行更改或触发操作时,您应该使用 POST 动词。通过这样做,您上面提到的路由问题应该得到解决。

    更新

    您是否考虑过以资源为中心的方法来解决您的问题?在所有情况下,资源都是“配置文件”,并且它似乎具有唯一的 id x。它似乎还有另外两个可能的唯一 ID 的电子邮件和 ssn?

    如果这些是您可以接受的网址

    http://localhost/api/profile
    http://localhost/api/profile/x
    http://localhost/api/profile/?email=myemail@x.com
    http://localhost/api/profile/?ssn=x
    

    你可以使用:

    public class ProfileController : ApiController
    {
        public string Get(int id)
        {
            return string.Format("http://localhost/api/profile/{0}", id);
        }
    
        public string Get([FromUri] string email = null, [FromUri] int? ssn = null)
        {
            if (!string.IsNullOrEmpty(email))
            {
                return string.Format("http://localhost/api/profile/?email={0}", email);
            }
    
            if (ssn.HasValue)
            {
                return string.Format("http://localhost/api/profile/?ssn={0}", ssn.Value);
            }
    
            return "http://localhost/api/profile";
        }
    }
    

    仅使用标准 webapi 路由:

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

    但是

    如果您确实想继续使用 /email 和 /ssn,您可能会遇到电子邮件问题......特别是“。”在电子邮件地址中,这可能会混淆路由引擎...要使其正常工作,您必须在尾部加上斜杠,即http://localhost/api/profile/email/me@me.com/ 我想您会发现http://localhost/api/profile/email/me@me.com 不起作用。

    这支持:

    http://localhost/api/profile
    http://localhost/api/profile/x
    http://localhost/api/profile/email/myemail@x.com/
    http://localhost/api/profile/ssn/x
    

    我会尝试这个并使用(注意,使用名称 rpcId 来区分路线):

    public class ProfileController : ApiController
    {
        public string Get(int id)
        {
            return string.Format("http://localhost/api/profile/{0}", id);
        }
    
        public string Get()
        {
            return "http://localhost/api/profile";
        }
    
        [HttpGet]
        public string Ssn(int rpcId)
        {
            return string.Format("http://localhost/api/profile/ssn/{0}", rpcId);
    
        }
    
        [HttpGet]
        public string Email(string rpcId)
        {
            return string.Format("http://localhost/api/profile/email/{0}", rpcId);
    
        }
    }
    

    然后我的路由将是:

           config.Routes.MapHttpRoute(
             name: "ProfileRestApi",
             routeTemplate: "api/profile/{id}",
             defaults: new { id = RouteParameter.Optional, Controller = "Profile" }
             );
    
    
            config.Routes.MapHttpRoute(
                name: "PrfileRpcApi",
                routeTemplate: "api/profile/{action}/{rpcId}",
                defaults: new { Controller = "Profile" }
            );
    

    【讨论】:

    • 我知道,很抱歉。我们将触发操作用作 POST,但这只是一个示例。实际用例是查找:/api/profile/email/foo@bar.com/api/profile/ssn/1234。在那里,我想通过电子邮件和 ssn 查找个人资料。
    • @Gaui 的 ssn 与配置文件 ID 不同? /api/profile/1 和 /api/profile/ssn/1 一样吗?
    • @Gaui 在这种情况下,我建议您考虑使用查询字符串进行电子邮件查找。即localhost/api/profile localhost/api/profile/x localhost/api/profile/?email=myemail@x.com OR localhost/api/profile localhost/api/profile/x 并且只测试 x - 如果它可以解析为 int 使用它作为 id 否则必须是电子邮件并使用它。 (但正如我在回复电子邮件中所说的那样,它可能很难做到,因为它会破坏路线)。
    【解决方案2】:

    规则重叠。路由中Id的验证会不会是很大的损失?您仍然可以在 Get 操作中将 Id 参数作为 int 参数。如果是这种情况,我认为您可以完全删除 ControllerAndID,然后只使用与您的所有用例匹配的第二个。

    【讨论】:

    • 好的,谢谢。所有方案都有效,除了: /api/profile/13 其中 13 是整数。是否也可以在单个 Get(string id) 函数中使用这种情况,并进行一些 String.IsNullOrEmpty(id)) 验证?
    • 不应该是Get(int id)吗?
    • 不,在这种情况下它必须是字符串,因为我正在使用一个社会安全号码,它可以从零开始。
    • 啊,明白了,/api/profile/ 也将映射到这个 Get,如果 string.isnullorempty(id) 重定向到 GetAll 是公平的,那应该为你做。或者您可以有另一条路线,其中 id 不是可选的,但这可能会更复杂。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-07
    • 1970-01-01
    • 2014-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多