简体   繁体   English

WebApi添加另一个Get方法

[英]WebApi adding another Get Method

I have a pretty standard WebApi that does some basic CRUD operations. 我有一个非常标准的WebApi,可以执行一些基本的CRUD操作。

I'm trying to add some different kind of lookups but am not quite sure how it's suppose to be done. 我正在尝试添加一些不同类型的查找,但我不太确定它是如何完成的。

Here's my FoldersController currently 这是我目前的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);
    }
}

what I would like to do is add a method that looks something like this 我想要做的是添加一个看起来像这样的方法

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

Since I already have the standard Get method in there, i'm not quite sure how to do so. 由于我已经有了标准的Get方法,我不太清楚如何这样做。

I initially thought I could just add a new route..something like 我最初以为我可以添加一条新路线......就像

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

And the just add something like an ActionName annotation to my method [ActionName("GetChildren")] 只需在我的方法[ActionName("GetChildren")]添加类似ActionName注释的内容

but that didn't fly. 但那并没有飞。

Am I on the right track? 我是在正确的轨道上吗? How do I do something like this without adding another controller? 如何在不添加其他控制器的情况下执行此类操作?

You may not like this answer, but I feel it's the right one. 你可能不喜欢这个答案,但我觉得这是正确的答案。 WebAPI was designed to only have 5 calls, GET (one item / list items), POST, PUT and DELETE per entity type. WebAPI被设计为每个实体类型只有5个调用,GET(一个项目/列表项),POST,PUT和DELETE。 This allows for REST URLs, such as Folders/Get/5, Folders/Get etc. 这允许REST URL,例如Folders / Get / 5,Folders / Get等。

Now, in your scenario, you're wanting ChildFolders , which I can understand aren't different objects, but they are different entities in terms of REST (ChildFolders/Get) etc. I feel this should be another WebAPI controller. 现在,在您的场景中,您想要ChildFolders ,我可以理解它们不是不同的对象,但它们在REST(ChildFolders / Get)等方面是不同的实体。我觉得这应该是另一个WebAPI控制器。

There's ways of patching up the Http Routes to manage for this, but I don't feel it's how Web API was designed to work and it enforces you to follow REST data-by-entity-type protocols... otherwise why not just use .NET MVC Controllers for your AJAX calls? 有一些方法可以修补Http路由来管理这个,但我不觉得Web API是如何工作的,它强制你遵循REST数据逐个实体类型的协议......否则为什么不使用用于AJAX调用的.NET MVC控制器?

The idea behind WebAPI is to follow REST patterns, as Chris said. 正如克里斯所说,WebAPI背后的想法是遵循REST模式。 With that in mind, it's up to you to decide how your domain maps to that pattern. 考虑到这一点,由您决定您的域如何映射到该模式。 If child-folders are folders and use the same internal logic then maybe it makes perfect sense to put that Get in your FoldersController. 如果子文件夹文件夹并使用相同的内部逻辑,那么将Get放入FoldersController可能是完全合理的。 If not, or if you want to perform all the REST methods on child folders, it may make more sense to create a ChildFoldersController. 如果没有,或者如果要在子文件夹上执行所有REST方法,则创建ChildFoldersController可能更有意义。

Now that your app is organized sensibly, you can think about routing. 既然您的应用程序是明智的,那么您可以考虑路由。 WebAPI now supports attribute routing. WebAPI现在支持属性路由。 If you add this line to your WebApiConfig.Register -- config.MapHttpAttributeRoutes(); 如果将此行添加到WebApiConfig.Register - config.MapHttpAttributeRoutes(); -- like so: - 像这样:

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

You can then put your route on the action itself: 然后,您可以将路线放在行动本身上:

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

Now all your REST calls to the path "folders/{folderID}" will work using the default route, while any gets on that route that include "/children" will hit that action. 现在,所有对路径“folders / {folderID}”的REST调用都将使用默认路由,而任何包含“/ children”的路由都会触发该操作。 It also makes the call's behavior very clear to the caller of your API. 它还使调用的行为对API的调用者非常清楚。

You can also still do this with the normal routing pattern: 您仍然可以使用正常的路由模式执行此操作:

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

You could also leave controllers as a variable in that custom route, if you have other resources that have children, and you can still put that action in a separate controller that also handles calls to the route "childFolders/{folderID}". 您还可以将控制器作为变量保留在该自定义路由中,如果您有其他具有子级的资源,您仍然可以将该操作放在一个单独的控制器中,该控制器也处理对路径“childFolders / {folderID}”的调用。

Routing is very flexible. 路由非常灵活。 Just make sure to design it so that it makes sense at a glance for both the api callers and the people maintaining your software (including you). 只需确保设计它,以便对api呼叫者和维护软件的人(包括您)一目了然。

Here's some attribute routing info: Attribute Routing in WebAPI 2 这是一些属性路由信息: WebAPI 2中的属性路由

One way is to write a new route specific to the GetChildFolders action. 一种方法是编写特定于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" }
        );

Actions are a great way to have two Get methods inside a WebApi controller. 操作是在WebApi控制器中包含两个Get方法的好方法。
Here is what I do in order to have different actions, and also an optional extra ID parameter for some of the actions: 以下是我为了执行不同的操作而执行的操作,以及针对某些操作的可选额外ID参数:

Inside WebApiConfig.cs I have the following: WebApiConfig.cs里面我有以下内容:

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

and in the controller: 并在控制器中:

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

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

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 . 您可以使用/api/folders/getchildren/123进行调用。 Just make sure that the parameter value in the method is folderID rather than id. 只需确保方法中的参数值是folderID而不是id。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM