WebApi添加另一个Get方法

时间:2013-05-16 15:41:06

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

我有一个非常标准的WebApi,可以执行一些基本的CRUD操作。

我正在尝试添加一些不同类型的查找,但我不太确定它是如何完成的。

这是我目前的FoldersController

public class FoldersController : ApiBaseController
{
    //using ninject to pass the unit of work in
    public FoldersController(IApiUnitOfWork uow)
    {
        Uow = uow;
    }

    // GET api/folders
    [HttpGet]
    public IEnumerable<Folder> Get()
    {
        return Uow.Folders.GetAll();
    }

    // GET api/folders/5
    public Folder Get(int id)
    {
        return Uow.Folders.GetById(id);
    }

    // POST api/folders
    public HttpResponseMessage Post(Folder folder)
    {
        Uow.Folders.Add(folder);
        Uow.Commit();

        var response = Request.CreateResponse(HttpStatusCode.Created, folder);

        // Compose location header that tells how to get this Folder
        response.Headers.Location = new Uri(Url.Link(WebApiConfig.DefaultRoute, new { id = folder.Id }));

        return response;
    }

    // PUT api/folders
    public HttpResponseMessage Put(Folder folder)
    {
        Uow.Folders.Update(folder);
        Uow.Commit();
        return new HttpResponseMessage(HttpStatusCode.NoContent);
    }

    // DELETE api/folders/5
    public HttpResponseMessage Delete(int id)
    {
        Uow.Folders.Delete(id);
        Uow.Commit();

        return new HttpResponseMessage(HttpStatusCode.NoContent);
    }
}

我想要做的是添加一个看起来像这样的方法

public IEnumerable<Folder> GetChildFolders(int folderID)
{
     return Uow.Folders.GetChildren(folderID);
}

由于我已经有了标准的Get方法,我不太清楚如何这样做。

我最初认为我可以添加一条新路线......像

这样的东西
routes.MapHttpRoute(
        name: "ActionAndIdRoute",
        routeTemplate: "api/{controller}/{action}/{id}",
        defaults: null,
        constraints: new { id = @"^/d+$" } //only numbers for id
        );

只需在我的方法[ActionName("GetChildren")]

中添加类似ActionName注释的内容

但是没有飞过。

我是否在正确的轨道上?如何在不添加其他控制器的情况下执行此类操作?

5 个答案:

答案 0 :(得分:11)

你可能不喜欢这个答案,但我觉得这是正确的答案。 WebAPI被设计为每个实体类型只有5个调用,GET(一个项目/列表项),POST,PUT和DELETE。这允许REST URL,例如Folders / Get / 5,Folders / Get等。

现在,在您的场景中,您需要 ChildFolders ,我可以理解它们不是不同的对象,但它们在REST(ChildFolders / Get)等方面是不同的实体。我觉得这应该是另一个WebAPI控制器。

有一些方法可以修补Http路由来管理这个,但我不认为这是Web API的设计工作方式,它强制您遵循REST数据逐个实体类型的协议......否则为什么不只是使用.NET MVC控制器进行AJAX调用吗?

答案 1 :(得分:3)

正如克里斯所说,WebAPI背后的想法是遵循REST模式。考虑到这一点,由您决定您的域如何映射到该模式。如果子文件夹文件夹并使用相同的内部逻辑,那么将Get放入FoldersController可能非常有意义。如果没有,或者如果要在子文件夹上执行所有REST方法,则创建ChildFoldersController可能更有意义。

既然您的应用程序组织合理,您就可以考虑路由。 WebAPI现在支持属性路由。如果您将此行添加到WebApiConfig.Register - config.MapHttpAttributeRoutes(); - 就像这样:

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

然后,您可以将路线放在行动本身上:

[HttpGet]
[Route("folders/{folderID}/children")] // <-- notice the route here
public IEnumerable<Folder> GetChildFolders(int folderID)
{
     return Uow.Folders.GetChildren(folderID);
}

现在,所有对路径“folders / {folderID}”的REST调用都将使用默认路由,而任何包含“/ children”的路由都会触发该操作。它还使调用的行为对API的调用者非常清楚。

您仍然可以使用正常的路由模式执行此操作:

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

// folder children route
config.Routes.MapHttpRoute(
    name: "FolderChildrenApi",
    routeTemplate: "api/folders/{folderID}/children",
    defaults: new { controller = "Folders", action = "GetChildFolders" }
);

如果您有其他具有子级的资源,您也可以将控制器作为变量留在该自定义路由中,并且您仍然可以将该操作放在一个单独的控制器中,该控制器也处理对路径“childFolders / {folderID}”的调用。

路由非常灵活。只需确保设计它,以便对api呼叫者和维护软件的人(包括您)一目了然。

以下是一些属性路由信息:Attribute Routing in WebAPI 2

答案 2 :(得分:0)

一种方法是编写特定于GetChildFolders操作的新路由。

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

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

答案 3 :(得分:0)

操作是在WebApi控制器中包含两个Get方法的好方法 以下是我为了执行不同的操作而执行的操作,以及针对某些操作的可选额外ID参数:

WebApiConfig.cs内我有以下内容:

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

并在控制器中:

    [ActionName("DefaultAction")]
    public AdGetResponse Get(int id)
    {
        ...
    }

    [ActionName("AnotherAction")]
    public HttpResponseMessage GetAnotherAction(int id, int actionId)
    {
    }

答案 4 :(得分:0)

按如下方式制作路线:

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

config.Routes.MapHttpRoute(
    name: "DefaultApiPlusActionAndFolderid",
    routeTemplate: "api/{controller}/{action}/{folderID}",
    defaults: null,
    constraints: new { action = @"[a-zA-Z]+", folderID = @"\d+" }
);

然后您可以使用

等方法
[ActionName("GetChildren")]
public IEnumerable<Folder> GetChildFolders(int folderID)
{
     return Uow.Folders.GetChildren(folderID);
}

您可以使用/api/folders/getchildren/123致电。 只需确保方法中的参数值是folderID而不是id。