我已经有一段时间没有写过api了(上次是在asp.core 2.0中),所以今天决定在.core 2.1版本中创建一个新的api,不幸的是发现我的Action不能像以前那样在previos版本。
几个小时后,我找出了导致[Route("api/[controller]")]
的问题,并且由于[ApiController]
无法解决问题,我对它们都进行了评论,并且一切正常。
**所以有人可以向我解释一下如何使此代码与[[ApiController]] unconnebt和相同的操作URL调用一起使用吗?
//[Route("api/[controller]")]
//[ApiController]
public class TestController : ControllerBase
{
[HttpGet("api/[controller]")]
public string A1()
{
return "A1()";
}
[HttpGet]
public string A2(int id)
{
return $"A2(int {id})";
}
[HttpGet]
public string A3(string p1,string p2)
{
return $"A3(string {p1},string {p2})";
}
[Route("api/[controller]/A4/{id}")]
[HttpGet]
public string A4(int id)
{
return $"A4(int {id})";
}
[HttpGet("api/[controller]/A5/{id}")]
public string A5(int id)
{
return $"A5(int {id})";
}
}
` StartUp.css
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{……///code
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "api/{controller=Home}/{action=Index}/{id?}");
});
}
测试1 : 我根据@ chris-pratt答案进行了更改
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet("")]
public string A1()
{
return "A1()";
}
[HttpGet("A2")]
[HttpGet("A2/{id}")]
public string A2([FromQuery]int id)
{
return $"A2(int {id})";
}
[HttpGet("A3")]
public string A3([FromQuery]string p1, [FromQuery]string p2)
{
return $"A3(string {p1},string {p2})";
}
[HttpGet("A4")]
public string A4([FromQuery]int id)
{
return $"A4(int {id})";
}
[HttpGet("A5")]
public string A5([FromQuery]int id)
{
return $"A5(int {id})";
}
}
网址调用:
5&6现在相同
答案 0 :(得分:1)
对于5&6,您不需要使用[FromQuery]
。对于2&3,如果您仍然希望同时使用查询字符串和属性路由,则需要将SuppressInferBindingSourcesForParameters
属性设置为true以禁用默认推理规则。请参阅Binding source parameter inference。
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressInferBindingSourcesForParameters = true;
});
网络api控制器:
[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
[HttpGet("")]
public string A1()
{
return "A1()";
}
[HttpGet("A2")]
[HttpGet("A2/{id}")]
public string A2(int id)
{
return $"A2(int {id})";
}
[HttpGet("A3")]
public string A3([FromQuery]string p1, [FromQuery]string p2)
{
return $"A3(string {p1},string {p2})";
}
[HttpGet("A4/{id}")]
public string A4(int id)
{
return $"A4(int {id})";
}
[HttpGet("A5/{id}")]
public string A5(int id)
{
return $"A5(int {id})";
}
}
答案 1 :(得分:0)
[Route("api/[controller]")]
和[ApiController]
都不是您的实际问题。控制器类级别的[Route]
属性为该控制器中的所有操作指定路由前缀。起飞时,您将回到MVC中的默认路由/{controller}/{action}/{id?}
。
认识到使用属性路由在其应用的级别覆盖默认路由 也很重要。换句话说,如果您未将Route
应用于控制器,则那里的操作将使用默认路由。如果将Route
属性或诸如HttpGet
之类的HTTP方法属性之一应用于操作,则仅单个操作将使用自定义属性路由。但是,如果确实将Route
属性应用于控制器,则即使您未显式应用属性,控制器中的所有操作都将使用属性路由。因此,为每个操作赋予其自己的独特路线非常重要。
您的第一个问题是,您对某些操作所应用的路径与对控制器所应用的相同。最终结果是该操作的路由最终实际上是/api/test/api/test
。您只需要指定路由中前缀之后的部分,即[HttpGet("a1")]
。如果您希望它只是前缀,而没有自己的附加路由段,则只需使用空路由,即[HttpGet("")]
或仅使用[HttpGet]
。只需确保每个HTTP方法只执行一次即可。
现在与应用[ApiController]
的区别在于,除其他外,它将默认绑定从FromForm
切换到FromBody
。但是,这仅适用于引用类型的参数,例如类。像字符串这样的值类型将是未绑定的。显然,由于您想从查询字符串中获取这些内容,因此应在其中添加[FromQuery]
:
[HttpGet]
public string A3([FromQuery]string p1, [FromQuery]string p2)
最后,您还会有一堆重复的路线。正如我在上面概述的那样,未指定路由与在操作中指定空路由相同,这意味着您所拥有的只是控制器上设置的路由前缀。您需要确保每个操作都有其响应的唯一路由。例如,上面的方法实际上应该具有类似[HttpGet("a3")]
之类的东西,它会为您提供/api/test/a3?p1=test&p2=test
的预期路线。
答案 2 :(得分:0)
我对您的代码进行了一些更改,请参阅我建议的解决方案。现在已经设置了路由,控制器上的每个方法都将作为路由名称形成,并且参数上的[FromRoute]
标签表明它们将来自HTTP Verb下指定的路由。
[Route("api/[controller]/[action]")]
public class TestController : Controller
{
public string A1()
{
return "A1()";
}
[HttpGet]
[Route("{id}")]
public string A2([FromRoute]int id)
{
return $"A2(int {id})";
}
[HttpGet]
[Route("{p1}/{p2}")]
public string A3([FromRoute]string p1,[FromRoute]string p2)
{
return $"A3(string {p1},string {p2})";
}
[HttpGet]
[Route("{id}")]
public string A4([FromRoute]int id)
{
return $"A4(int {id})";
}
[HttpGet("{id}")]
public string A5([FromRoute]int id)
{
return $"A5(int {id})";
}
}
您的路线现在应类似于http://localhost:5200/api/test/A2/5