ASP.NET Web API中的自定义方法名称

Jus*_*tin 109 c# asp.net-web-api asp.net-web-api-routing

我正在从WCF Web API转换为新的ASP.NET MVC 4 Web API.我有一个UsersController,我想要一个名为Authenticate的方法.我看到了如何进行GetAll,GetOne,Post和Delete的示例,但是如果我想在这些服务中添加额外的方法呢?例如,我的UsersService应该有一个名为Authenticate的方法,它会传入用户名和密码,但是它不起作用.

public class UsersController : BaseApiController
{
    public string GetAll()
    {
        return "getall!";
    }

    public string Get(int id)
    {
        return "get 1! " + id;
    }

    public User GetAuthenticate(string userName, string password, string applicationName)
    {
        LogWriter.Write(String.Format("Received authenticate request for username {0} and password {1} and application {2}",
            userName, password, applicationName));

        //check if valid leapfrog login.
        var decodedUsername = userName.Replace("%40", "@");
        var encodedPassword = password.Length > 0 ? Utility.HashString(password) : String.Empty;
        var leapFrogUsers = LeapFrogUserData.FindAll(decodedUsername, encodedPassword);

        if (leapFrogUsers.Count > 0)
        {
            return new User
            {
                Id = (uint)leapFrogUsers[0].Id,
                Guid = leapFrogUsers[0].Guid
            };
        }
        else
            throw new HttpResponseException("Invalid login credentials");
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以浏览到myapi/API /用户/它会调用GETALL,我可以浏览到myapi/API /用户/ 1,它会调用获取,但如果我叫myapi/API /用户/验证?用户名= {0} &password = {1}然后它会调用Get(NOT Authenticate)和错误:

参数字典包含非空类型"System.Int32"的方法"System.String获取(的Int32)"在"Navtrak.Services.WCF.NavtrakAPI.Controllers.UsersController"的参数的"id"一个空条目.可选参数必须是引用类型,可空类型,或者声明为可选参数.

如何调用自定义方法名称,例如Authenticate?

Dar*_*rov 131

默认情况下,路由配置遵循RESTFul约定,这意味着它只接受Get,Post,Put和Delete操作名称(在global.asax =>中查看路由,默认情况下它不允许您指定任何操作名称=>它使用HTTP动词来分派).因此,当您向您发送GET请求时,/api/users/authenticate基本上是调用Get(int id)操作并且传递id=authenticate明显崩溃,因为您的Get操作需要一个整数.

如果您想拥有与标准动作名称不同的动作名称,您可以在global.asax以下位置修改路线定义:

Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { action = "get", id = RouteParameter.Optional }
);
Run Code Online (Sandbox Code Playgroud)

现在,您可以导航/api/values/getauthenticate以验证用户身份.

  • 有没有办法让它仍然使用Get(id),Get()Put,Delete,Post同时仍允许其他操作? (19认同)
  • 此处更重要的一点是,使用这种路由样式,必须使用属性来指定允许的HTTP方法(例如[HttpGet])。 (2认同)

sky*_*dev 86

这是迄今为止我提出的最佳方法,即在支持常规REST方法的同时引入额外的GET方法.将以下路由添加到WebApiConfig:

routes.MapHttpRoute("DefaultApiWithId", "Api/{controller}/{id}", new { id = RouteParameter.Optional }, new { id = @"\d+" });
routes.MapHttpRoute("DefaultApiWithAction", "Api/{controller}/{action}");
routes.MapHttpRoute("DefaultApiGet", "Api/{controller}", new { action = "Get" }, new { httpMethod = new HttpMethodConstraint(HttpMethod.Get) });
routes.MapHttpRoute("DefaultApiPost", "Api/{controller}", new {action = "Post"}, new {httpMethod = new HttpMethodConstraint(HttpMethod.Post)});
Run Code Online (Sandbox Code Playgroud)

我用下面的测试类验证了这个解决方案.我能够成功点击下面控制器中的每个方法:

public class TestController : ApiController
{
    public string Get()
    {
        return string.Empty;
    }

    public string Get(int id)
    {
        return string.Empty;
    }

    public string GetAll()
    {
        return string.Empty;
    }

    public void Post([FromBody]string value)
    {
    }

    public void Put(int id, [FromBody]string value)
    {
    }

    public void Delete(int id)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

我确认它支持以下请求:

GET /Test
GET /Test/1
GET /Test/GetAll
POST /Test
PUT /Test/1
DELETE /Test/1
Run Code Online (Sandbox Code Playgroud)

注意如果您的额外GET操作不以"Get"开头,您可能希望向该方法添加HttpGet属性.

  • 这根本不适用于我.当我尝试进行基本GET时收到错误消息. (4认同)

Kin*_*xit 21

我是进入MVC4世界的日子.

为了它的价值,我有一个SitesAPIController,我需要一个自定义方法,可以调用如下:

http://localhost:9000/api/SitesAPI/Disposition/0
Run Code Online (Sandbox Code Playgroud)

使用不同的值为最后一个参数获取具有不同配置的记录.

最后为我工作的是:

SitesAPIController中的方法:

// GET api/SitesAPI/Disposition/1
[ActionName("Disposition")]
[HttpGet]
public Site Disposition(int disposition)
{
    Site site = db.Sites.Where(s => s.Disposition == disposition).First();
    return site;
}
Run Code Online (Sandbox Code Playgroud)

这在WebApiConfig.cs中

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

// this i added
config.Routes.MapHttpRoute(
    name: "Action",
    routeTemplate: "api/{controller}/{action}/{disposition}"
 );
Run Code Online (Sandbox Code Playgroud)

只要我将{disposition}命名为{id}我遇到了:

{
"Message": "No HTTP resource was found that matches the request URI 'http://localhost:9000/api/SitesAPI/Disposition/0'.",
"MessageDetail": "No action was found on the controller 'SitesAPI' that matches the request."
}
Run Code Online (Sandbox Code Playgroud)

当我将它重命名为{disposition}时,它开始工作了.显然,参数名称与占位符中的值匹配.

随意编辑此答案,使其更准确/解释.

  • 感谢kinjal先生这个提示. (2认同)

小智 14

默认情况下,Web Api需要api/{controller}/{id}形式的URL来覆盖此默认路由.您可以使用以下两种方式之一设置路由.

第一种选择:

在WebApiConfig.cs中添加以下路由注册

config.Routes.MapHttpRoute(
    name: "CustomApi",
    routeTemplate: "api/{controller}/{action}/{id}",
    defaults: new { id = RouteParameter.Optional }
);
Run Code Online (Sandbox Code Playgroud)

使用HttpGet和参数装饰你的动作方法,如下所示

[HttpGet]
public HttpResponseMessage ReadMyData(string param1,
                        string param2, string param3)

 {

// your code here

}
Run Code Online (Sandbox Code Playgroud)

对于调用上面的方法url将如下所示

HTTP://本地主机:[yourport]/API /迈德特/ ReadMyData参数1 =值1&参数2 =值2&参数3 =值3

第二个选项 向Controller类添加路由前缀,并使用HttpGet装饰您的操作方法,如下所示.在这种情况下,无需更改任何WebApiConfig.cs.它可以有默认路由.

[RoutePrefix("api/{controller}/{action}")]
public class MyDataController : ApiController
{

[HttpGet]
public HttpResponseMessage ReadMyData(string param1,
                        string param2, string param3)

{

// your code here

}

}
Run Code Online (Sandbox Code Playgroud)

对于调用上面的方法url将如下所示

HTTP://本地主机:[yourport]/API /迈德特/ ReadMyData参数1 =值1&参数2 =值2&参数3 =值3


Dar*_*eal 10

如果您将ASP.NET 5ASP.NET MVC 6一起使用,那么大多数答案都无法正常工作,因为您通常会让MVC为您创建适当的路由集合(使用默认的RESTful约定),这意味着你不会随意找到任何Routes.MapRoute()编辑电话.

该文件ConfigureServices()调用的方法Startup.cs将使用内置于ASP.NET 5中的依赖注入框架注册MVC:这样,当您ApplicationBuilder.UseMvc()稍后在该类中调用时,MVC框架将自动将这些默认路由添加到您的应用程序.我们可以通过查看UseMvc()框架源代码中的方法实现来了解引擎背后发生的事情:

public static IApplicationBuilder UseMvc(
    [NotNull] this IApplicationBuilder app,
    [NotNull] Action<IRouteBuilder> configureRoutes)
{
    // Verify if AddMvc was done before calling UseMvc
    // We use the MvcMarkerService to make sure if all the services were added.
    MvcServicesHelper.ThrowIfMvcNotRegistered(app.ApplicationServices);

    var routes = new RouteBuilder
    {
        DefaultHandler = new MvcRouteHandler(),
        ServiceProvider = app.ApplicationServices
    };

    configureRoutes(routes);

    // Adding the attribute route comes after running the user-code because
    // we want to respect any changes to the DefaultHandler.
    routes.Routes.Insert(0, AttributeRouting.CreateAttributeMegaRoute(
        routes.DefaultHandler,
        app.ApplicationServices));

    return app.UseRouter(routes.Build());
}
Run Code Online (Sandbox Code Playgroud)

这样做的好处是框架现在可以处理所有艰苦工作,遍历所有Controller的操作并设置其默认路由,从而为您节省一些冗余工作.

不好的是,关于如何添加自己的路线的文档很少或根本没有.幸运的是,您可以通过使用基于约定的方法和/或基于属性的方法(也称为属性路由)轻松地做到这一点.

公约为基础

在您的Startup.cs类中,替换为:

app.UseMvc();
Run Code Online (Sandbox Code Playgroud)

有了这个:

app.UseMvc(routes =>
            {
                // Route Sample A
                routes.MapRoute(
                    name: "RouteSampleA",
                    template: "MyOwnGet",
                    defaults: new { controller = "Items", action = "Get" }
                );
                // Route Sample B
                routes.MapRoute(
                    name: "RouteSampleB",
                    template: "MyOwnPost",
                    defaults: new { controller = "Items", action = "Post" }
                );
            });
Run Code Online (Sandbox Code Playgroud)

基于属性的

关于MVC6的一个好处是,您还可以通过使用适当的和/或/ template参数来装饰Controller类和/或Action方法,从而在每个控制器的基础上定义路由,例如:RouteAttributeHttpGetHttpPost

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc;

namespace MyNamespace.Controllers
{
    [Route("api/[controller]")]
    public class ItemsController : Controller
    {
        // GET: api/items
        [HttpGet()]
        public IEnumerable<string> Get()
        {
            return GetLatestItems();
        }

        // GET: api/items/5
        [HttpGet("{num}")]
        public IEnumerable<string> Get(int num)
        {
            return GetLatestItems(5);
        }       

        // GET: api/items/GetLatestItems
        [HttpGet("GetLatestItems")]
        public IEnumerable<string> GetLatestItems()
        {
            return GetLatestItems(5);
        }

        // GET api/items/GetLatestItems/5
        [HttpGet("GetLatestItems/{num}")]
        public IEnumerable<string> GetLatestItems(int num)
        {
            return new string[] { "test", "test2" };
        }

        // POST: /api/items/PostSomething
        [HttpPost("PostSomething")]
        public IActionResult Post([FromBody]string someData)
        {
            return Content("OK, got it!");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

该控制器将处理以下请求:

 [GET] api/items
 [GET] api/items/5
 [GET] api/items/GetLatestItems
 [GET] api/items/GetLatestItems/5
 [POST] api/items/PostSomething
Run Code Online (Sandbox Code Playgroud)

另请注意,如果使用两种方法,基于属性的路由(定义时)将覆盖基于约定的路径,并且它们都将覆盖由其定义的默认路由UseMvc().

有关详细信息,您还可以在我的博客上阅读以下帖子.


And*_*rew 9

有关命名操作的详细讨论,请参阅此文章.它还显示您可以使用[HttpGet]属性,而不是使用"get"为操作名称添加前缀.

http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api