路由属性名称 属性
Route attribute Name property
我有 ProductsController 和 OwnersController:
public class ProductsController : ApiController
{
//constructor is here
// GET /api/products
public IHttpActionResult GetProducts()
{
return Ok(new ApiResponse());
}
// GET /api/products/{productCode}
[HttpGet, Route("api/products/{productCode}")]
public IHttpActionResult GetProductByCode(string productCode)
{
return Ok(new ApiResponse());
}
// POST /api/products
public IHttpActionResult PostProduct(Product product /*my class*/)
{
return CreatedAtRoute("DefaultApi", new { id = product.Id }, product);
}
}
效果很好。
但是现在我创建了第二个控制器并做同样的事情但是 我在尝试 POST 方法时得到了错误。另一种方法效果很好!
先来看看代码:
public class OwnersController : ApiController
{
// constructor
// GET /api/owners/{label}
// GET /api/owners/{label}?skip=1&take=4
[Route("api/owners/{label}")]
public IHttpActionResult GetOwnersExamples(string label, int skip=0, int take=10)
{
return Ok(new ApiResponse());
}
// POST /api/owners/{productCode}
//[HttpPost]
[Route("api/owners/{productCode}"/*, Name = "CreateOwner"*/)]
public IHttpActionResult PostOwner(string productCode, Owner owner)
{
return CreatedAtRoute("DefaultApi", new { id = Owner.Id }, owner);
}
}
错误信息:
UrlHelper.Link must not return null
我的路由配置:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
据我了解 CreateAtRoute
方法必须得到另一个 RouteName
的问题。如您所见,我可以通过添加 Route Name 参数(现在已评论)并将 "DefaultApi"
替换为 "CreateOwner"
来解决问题,但它看起来像是一个 hack。我相信还有另一种方法可以避免 Name Property
.
P.S。看起来我的 Web API 只能看到第一个控制器 (ProductsController) - 如果我删除显式 Route [Route("...")]
...
,任何其他方法都不起作用
As I understand problem that CreateAtRoute method must get another
RouteName. As you see I can solve the problem by adding Route Name
parameter (commented now) and replace "DefaultApi" with "CreateOwner"
but it looks like a hack. I believe there is another method to do it
avoiding Name Property.
你的理解基本正确。但是,您不应为当前路由指定名称,而应为指向已创建资源的路由指定名称。 CreatedAtRoute
填充响应 Location header 应包含新创建资源的 GET-able URI。
这是一个工作示例:
[HttpGet]
[Route("api/owners/{id}", Name = "GetOwnerById")]
public IHttpActionResult GetOwner(int id)
{
// Obtain the owner by id here
return Ok(new ApiResponse());
}
[HttpPost]
[Route("api/owners/{productCode}"/*, Name = "CreateOwner"*/)]
public IHttpActionResult PostOwner(string productCode, Owner owner)
{
return CreatedAtRoute("GetOwnerById", new { id = owner.Id }, owner);
}
(注意:要使此示例正常运行,您应该注释 GetOwnersExamples
操作,否则多个操作将匹配您的 GET 请求。)
你说它看起来像黑客,但事实并非如此。 CreatedAtRoute
将路由名称作为参数,您应该提供它。否则将如何选择正确的操作并构建 Location
header?
我使用后续步骤解决问题:
- 删除控制器的所有
[RoutePrefix]
- 让它们默认工作 - 它非常适合简单的请求。
- 重要提示:检查所有方法是否重复!问题是我有 2 个方法,路由
api/controller/{label}
和 api/controller/{parameter}
- 它无法理解默认使用它们中的哪一个。 (或使用显式 uri:api/controller?label=1
)
- 重要提示: 避免将许多复杂类型放入 api 方法中 - 为它们创建 Wrapper 并只放置一个参数!
所有这些操作让我删除了多余的属性并使方法更具可读性。
结果如下:
public IHttpActionResult PostOwner(OwnerWrapper modelWrapper)
{
string productCode = modelWrapper.Product.Code;
Owner owner = modelWrapper.Owners[0];
return CreatedAtRoute("DefaultApi", new { id = Owner.Id }, owner);
}
这只是测试用例,所以我们可以看到productCode
从来没有用过,但我的真正实现比较困难。
我有 ProductsController 和 OwnersController:
public class ProductsController : ApiController
{
//constructor is here
// GET /api/products
public IHttpActionResult GetProducts()
{
return Ok(new ApiResponse());
}
// GET /api/products/{productCode}
[HttpGet, Route("api/products/{productCode}")]
public IHttpActionResult GetProductByCode(string productCode)
{
return Ok(new ApiResponse());
}
// POST /api/products
public IHttpActionResult PostProduct(Product product /*my class*/)
{
return CreatedAtRoute("DefaultApi", new { id = product.Id }, product);
}
}
效果很好。 但是现在我创建了第二个控制器并做同样的事情但是 我在尝试 POST 方法时得到了错误。另一种方法效果很好!
先来看看代码:
public class OwnersController : ApiController
{
// constructor
// GET /api/owners/{label}
// GET /api/owners/{label}?skip=1&take=4
[Route("api/owners/{label}")]
public IHttpActionResult GetOwnersExamples(string label, int skip=0, int take=10)
{
return Ok(new ApiResponse());
}
// POST /api/owners/{productCode}
//[HttpPost]
[Route("api/owners/{productCode}"/*, Name = "CreateOwner"*/)]
public IHttpActionResult PostOwner(string productCode, Owner owner)
{
return CreatedAtRoute("DefaultApi", new { id = Owner.Id }, owner);
}
}
错误信息:
UrlHelper.Link must not return null
我的路由配置:
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
据我了解 CreateAtRoute
方法必须得到另一个 RouteName
的问题。如您所见,我可以通过添加 Route Name 参数(现在已评论)并将 "DefaultApi"
替换为 "CreateOwner"
来解决问题,但它看起来像是一个 hack。我相信还有另一种方法可以避免 Name Property
.
P.S。看起来我的 Web API 只能看到第一个控制器 (ProductsController) - 如果我删除显式 Route [Route("...")]
...
As I understand problem that CreateAtRoute method must get another RouteName. As you see I can solve the problem by adding Route Name parameter (commented now) and replace "DefaultApi" with "CreateOwner" but it looks like a hack. I believe there is another method to do it avoiding Name Property.
你的理解基本正确。但是,您不应为当前路由指定名称,而应为指向已创建资源的路由指定名称。 CreatedAtRoute
填充响应 Location header 应包含新创建资源的 GET-able URI。
这是一个工作示例:
[HttpGet]
[Route("api/owners/{id}", Name = "GetOwnerById")]
public IHttpActionResult GetOwner(int id)
{
// Obtain the owner by id here
return Ok(new ApiResponse());
}
[HttpPost]
[Route("api/owners/{productCode}"/*, Name = "CreateOwner"*/)]
public IHttpActionResult PostOwner(string productCode, Owner owner)
{
return CreatedAtRoute("GetOwnerById", new { id = owner.Id }, owner);
}
(注意:要使此示例正常运行,您应该注释 GetOwnersExamples
操作,否则多个操作将匹配您的 GET 请求。)
你说它看起来像黑客,但事实并非如此。 CreatedAtRoute
将路由名称作为参数,您应该提供它。否则将如何选择正确的操作并构建 Location
header?
我使用后续步骤解决问题:
- 删除控制器的所有
[RoutePrefix]
- 让它们默认工作 - 它非常适合简单的请求。 - 重要提示:检查所有方法是否重复!问题是我有 2 个方法,路由
api/controller/{label}
和api/controller/{parameter}
- 它无法理解默认使用它们中的哪一个。 (或使用显式 uri:api/controller?label=1
) - 重要提示: 避免将许多复杂类型放入 api 方法中 - 为它们创建 Wrapper 并只放置一个参数!
所有这些操作让我删除了多余的属性并使方法更具可读性。
结果如下:
public IHttpActionResult PostOwner(OwnerWrapper modelWrapper)
{
string productCode = modelWrapper.Product.Code;
Owner owner = modelWrapper.Owners[0];
return CreatedAtRoute("DefaultApi", new { id = Owner.Id }, owner);
}
这只是测试用例,所以我们可以看到productCode
从来没有用过,但我的真正实现比较困难。