繁体   English   中英

路线属性名称属性

[英]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不得返回null


我的RouteConfig

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

据我了解的问题, CreateAtRoute方法必须获取另一个RouteName 如您所见,我可以通过添加Route Name参数(现在进行注释)并用"CreateOwner"替换"DefaultApi"来解决该问题,但是它看起来像是一种黑客。 我相信还有另一种方法可以避免Name Property

PS看起来我的Web API只能看到第一个控制器(ProductsController)-如果删除明确的Route [Route("...")] ...,其他任何方法都将不起作用...

据我了解的问题,CreateAtRoute方法必须获取另一个RouteName。 如您所见,我可以通过添加Route Name参数(现在进行注释)并用“ CreateOwner”替换“ DefaultApi”来解决该问题,但是它看起来像是一种黑客。 我相信还有另一种避免名称属性的方法。

您的理解几乎是正确的。 但是,您不应为当前路由指定名称,而应为指向已创建资源的名称指定名称。 CreatedAtRoute填充响应位置标头,该标头应包含新创建资源的可GET 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标头?

我使用以下步骤解决问题:

  1. 删除控制器的所有[RoutePrefix] -默认情况下让它们工作-完全适合简单的请求。
  2. 重要提示:检查所有方法是否重复! 问题是我有两种使用api/controller/{label}api/controller/{parameter}路由的方法-它无法理解默认使用哪种方法。 (或使用显式uri: api/controller?label=1
  3. 重要提示:避免将许多复杂类型放入api方法中-为它们创建包装器,并仅输入一个参数!

所有这些操作使我可以删除多余的属性,并使方法更具可读性。

结果如下:

public IHttpActionResult PostOwner(OwnerWrapper modelWrapper)
{
    string productCode = modelWrapper.Product.Code;
    Owner owner = modelWrapper.Owners[0];

    return CreatedAtRoute("DefaultApi", new { id = Owner.Id }, owner);
}

这只是测试用例,因此我们可以看到productCode从未使用过,但是我真正的实现更加困难。

暂无
暂无

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

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