【问题标题】:How to disable REST convention from interfering with my ApiController如何禁止 REST 约定干扰我的 ApiController
【发布时间】:2018-02-28 02:12:07
【问题描述】:

这是我的api配置类:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}"
        );
    }
}

这是我的 api 控制器类:

public class RoleController : ApiController
{

    // Some action that works fine...
    // Another action that works fine...

    public Result Delete([FromBody]int RoleID)
    {
        return RoleBL.Delete(RoleID);
    }
}

我正在使用POST 调用我的操作,它们运行良好。 但是,当我尝试使用 POST 调用 Delete 操作时,出现以下错误:

405 方法不允许

请求的资源不支持 http 方法“POST”。

显然,这是因为 ApiController 强制执行 REST 约定 它期望 DELETE 动词代表 Delete 动作。

现在,如何禁用此 REST 约定约束 并以经典的方式写下我的动作?

【问题讨论】:

  • 这叫做Convention over Configuration,你不能禁用它,你甚至不应该尝试。要么遵循 REST,要么不使用 REST 名称。

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


【解决方案1】:

您可以使用HttpPostAttribute 强制执行仅接受POST 的操作:

public class RoleController : ApiController
{       
    [HttpPost]
    public Result Delete([FromBody]int RoleID)
    {
        return RoleBL.Delete(RoleID);
    }
}

【讨论】:

  • 请不要将POST 转至DELETE 资源。对你的 api 的消费者来说是多么可怕的事情
  • @Camilo 不要那样做。然后发布您自己的答案。
  • @Alex 我曾使用POST 而不是DELETE 开发应用程序,因为DELETE 被防火墙策略阻止,所以有时您没有太多选择。
  • @Alex 不,在动词和状态码上全力以赴是一种享受吗?如果您想从 HTML 表单或其他方式调用您的 API,您将必须接受 POST。
  • @Alex 在每个人都可以访问路由器配置的初创公司中,这可能很不错;在其他环境中并非如此。
【解决方案2】:

您可能希望保留 REST 约定,同时允许某些客户端(如 HTML 表单)正确使用您的操作。
因此,您可以使用HttpPostAttribute 和HttpDeleteAttribute 或AcceptVerbsAttribute(允许多个动词)的组合来允许多个动词:

public class RoleController : ApiController
{       
    [HttpPost, HttpDelete]
    // OR
    [AcceptVerbs("DELETE", "POST")
    public Result Delete([FromBody]int RoleID)
    {
        return RoleBL.Delete(RoleID);
    }
}

【讨论】:

  • 好的,有没有我可以继承的另一种类型的控制器类不支持休息?
  • 我不想使用 REST,只想使用没有魔法动词和魔法动作名称的经典方法
  • 使用这种方法你不必?只是POST 到Role/Delete/123(这让我感觉很不舒服)
  • @Dusan 不,它不应该这样使用。您必须明确说出您想要支持的动词或更改操作名称使其与 HTTP 动词不匹配,例如 DeleteRole、DeleteEntity 等
【解决方案3】:

如果您不想要魔术动词和魔术动作名称,您可以使用路由属性。 删除config.Routes.MapHttpRoute并设置:

config.MapHttpAttributeRoutes();

现在您必须手动设置路线:

[RoutePrefix("~/Role")]
public class RoleController : ApiController
{

    [HttpPost]
    [Route("~/Delete")]
    public Result Delete([FromBody]int RoleID)
    {
        return RoleBL.Delete(RoleID);
    }
}

【讨论】:

    【解决方案4】:

    在你的情况下,我会停止使用任何类型的 REST 约定。

    除了在 Role 控制器上使用 Delete 方法,您还可以使用 DeleteRole 方法并允许在其上进行 POST。这样,任何事情都不会干扰您想做的事情。如果这不是您需要的,没有什么会强迫您构建 REST api。

    您仍然可以做几件事来构建一个不错的 api。

    例如,您可以返回一个 IHttpActionResult

    您的方法可能如下所示:

    public class RoleController : ApiController
    {       
        [HttpPost]
        public IHttpActionResult DeleteRole([FromBody]int RoleID)
        {
            if ( RoleID <= 0 )
            {
                  return BadRequest();
            }
    
            var deleteResult = RoleBL.Delete(RoleID);
            return Ok(deleteResult);
        }
    }
    

    您仍然返回相同的对象,但它使用适当的 http 代码包装在一个对象中,因此您处理结果的代码不会有太大变化。

    【讨论】:

      猜你喜欢
      • 2014-10-23
      • 2019-10-18
      • 2015-10-18
      • 1970-01-01
      • 2015-04-21
      • 1970-01-01
      • 2012-07-05
      • 2013-05-29
      • 2013-05-23
      相关资源
      最近更新 更多