3

我有一个非常标准的 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 注释的内容[ActionName("GetChildren")]

但这并没有成功。

我在正确的轨道上吗?我如何在不添加另一个控制器的情况下做这样的事情?

4

5 回答 5

11

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

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

有一些方法可以修补 Http Routes 来管理这个,但我不认为 Web API 是这样设计的,它强制你遵循 REST 数据-by-entity-type 协议……否则为什么不直接使用用于 AJAX 调用的 .NET MVC 控制器?

于 2013-05-17T07:59:54.020 回答
3

正如 Chris 所说,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 调用者和维护您的软件的人员(包括您)一目了然。

这是一些属性路由信息:WebAPI 2 中的属性路由

于 2013-10-21T15:08:46.167 回答
0

Make your routes as follows:

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+" }
);

You can then have methods such as

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

Which you can call with /api/folders/getchildren/123. Just make sure that the parameter value in the method is folderID rather than id.

于 2013-05-17T07:52:12.197 回答
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)
    {
    }
于 2013-05-16T16:49:42.697 回答
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" }
        );
于 2013-05-16T16:35:50.813 回答