ASP.NET Web API 中的自定义方法名称
本文关键字:自定义方法 NET Web API ASP | 更新日期: 2023-09-27 18:26:38
我正在从WCF Web API转换为新的 ASP.NET MVC 4 Web API。我有一个用户控制器,我想要一个名为身份验证的方法。我看到了如何执行 GetAll、GetOne、Post 和 Delete 的示例,但是如果我想在这些服务中添加额外的方法怎么办?例如,我的用户服务应该有一个名为身份验证的方法,他们在其中传递用户名和密码,但它不起作用。
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");
}
}
我可以浏览到 myapi/api/users/它会调用 GetAll,我可以浏览到 myapi/api/users/1 并且它会调用 Get,但是如果我调用 myapi/api/users/authenticate?username={0}&password={1},那么它将调用 Get (NOT Authenticate( 并出错:
参数字典包含不可为空类型"System.Int32"的参数"id"的空条目,用于"Navtrak.Services.WCF.NavtrakAPI.Controllers.UsersController"中的方法"System.String Get(Int32("。可选参数必须是引用类型、可为 null 的类型或声明为可选参数。
如何调用自定义方法名称(如身份验证(?
默认情况下,路由配置遵循 RESTFul 约定,这意味着它只接受 Get、Post、Put 和 Delete 操作名称(查看 global.asax => 中的路由,默认情况下它不允许您指定任何操作名称 =>它使用 HTTP 动词进行调度(。因此,当您向/api/users/authenticate
发送 GET 请求时,您基本上是在调用 Get(int id)
操作并传递id=authenticate
这显然会崩溃,因为您的 Get 操作需要一个整数。
如果要使用与标准操作名称不同的操作名称,可以在 global.asax
中修改路由定义:
Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "get", id = RouteParameter.Optional }
);
现在,您可以导航到/api/users/getauthenticate
以对用户进行身份验证。
这是我迄今为止想出的最好的方法,可以在支持普通 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)});
我用下面的测试类验证了这个解决方案。 我能够在下面的控制器中成功命中每种方法:
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)
{
}
}
我已验证它是否支持以下请求:
GET /Test
GET /Test/1
GET /Test/GetAll
POST /Test
PUT /Test/1
DELETE /Test/1
请注意,如果额外的 GET 操作不是以"Get"开头,则可能需要向该方法添加 HttpGet 属性。
我进入MVC4世界的日子。
对于它的价值,我有一个SitesAPIController,我需要一个自定义方法,可以这样调用:
http://localhost:9000/api/SitesAPI/Disposition/0
最后一个参数使用不同的值来获取具有不同配置的记录。
最终对我有用的是:
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;
}
这是在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}"
);
只要我将 {处置} 命名为 {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."
}
当我将其重命名为{处置}时,它开始工作。 因此,显然参数名称与占位符中的值匹配。
随意编辑此答案以使其更准确/解释性。
Web API 需要 api/{controller}/{id} 形式的 URL 来覆盖此默认路由。 您可以使用以下两种方式之一设置路由。
第一个选项:
在 WebApiConfig 中添加以下路由注册.cs
config.Routes.MapHttpRoute(
name: "CustomApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
使用 HttpGet 和参数装饰您的操作方法,如下所示
[HttpGet]
public HttpResponseMessage ReadMyData(string param1,
string param2, string param3)
{
// your code here
}
对于调用上面的方法 url 将如下所示
http://localhost:[yourport]/api/MyData/ReadMyData?param1=value1¶m2=value2¶m3=value3
第二种选择将路由前缀添加到控制器类并使用 HttpGet 修饰操作方法,如下所示。在这种情况下,无需更改任何 WebApiConfig.cs。它可以有默认路由。
[RoutePrefix("api/{controller}/{action}")]
public class MyDataController : ApiController
{
[HttpGet]
public HttpResponseMessage ReadMyData(string param1,
string param2, string param3)
{
// your code here
}
}
对于调用上面的方法 url 将如下所示
http://localhost:[yourport]/api/MyData/ReadMyData?param1=value1¶m2=value2¶m3=value3
如果您将 ASP.NET 5 与 MVC 6 一起使用 ASP.NET 则这些答案中的大多数根本不起作用,因为您通常会让 MVC 为您创建适当的路由集合(使用默认的 RESTful 约定(,这意味着您将找不到任何Routes.MapRoute()
调用来随意编辑。
Startup.cs
文件调用的 ConfigureServices()
方法将使用 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());
}
这样做的好处是,框架现在可以处理所有艰苦的工作,遍历所有控制器的操作并设置其默认路由,从而为您节省一些多余的工作。
不好的是,关于如何添加自己的路由的文档很少或根本没有。幸运的是,您可以通过使用基于约定和/或基于属性的方法(也称为属性路由(轻松做到这一点。
基于约定
在 Startup.cs 类中,替换以下内容:
app.UseMvc();
有了这个:
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" }
);
});
基于属性
MVC6 的一个优点是,您还可以通过使用适当的RouteAttribute
和/或HttpGet
/HttpPost
模板参数修饰 Controller
类和/或Action
方法,从而基于每个控制器定义路由,如下所示:
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!");
}
}
}
此控制器将处理以下请求:
[GET] api/items
[GET] api/items/5
[GET] api/items/GetLatestItems
[GET] api/items/GetLatestItems/5
[POST] api/items/PostSomething
另请注意,如果使用这两种方法,则基于属性的路由(如果已定义(将覆盖基于约定的路由,并且这两种路由都将覆盖UseMvc()
定义的默认路由。
有关更多信息,您还可以在我的博客上阅读以下帖子。
有关命名操作的较长讨论,请参阅本文。它还表明您可以使用 [HttpGet] 属性,而不是在操作名称前面加上"get"。
http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api
Web APi 2 及更高版本支持一种称为属性路由的新型路由。顾名思义,属性路由使用属性来定义路由。通过属性路由,可以更好地控制 Web API 中的 URI。例如,您可以轻松创建描述资源层次结构的 URI。
例如:
[Route("customers/{customerId}/orders")]
public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }
将完美,你不需要任何额外的代码,例如在WebApiConfig.cs中。只是您必须确保在WebApiConfig中启用或未启用Web api路由.cs如果没有,则可以像下面这样激活:
// Web API routes
config.MapHttpAttributeRoutes();
您不必在 WebApiConfig.cs 中执行更多操作或更改某些内容。有关更多详细信息,您可以查看本文。
只需修改你的WebAPIConfig.cs如波纹管
Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { action = "get", id = RouteParameter.Optional });
然后以下面的方式实现您的 API
// GET: api/Controller_Name/Show/1
[ActionName("Show")]
[HttpGet]
public EventPlanner Id(int id){}