路径属性Name属性

时间:2018-02-07 12:19:34

标签: c# asp.net .net routing asp.net-web-api2

我有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参数(现在注释)并将"DefaultApi"替换为"CreateOwner"来解决问题,但它看起来像是一个黑客。我相信还有另一种方法可以避免Name Property

P.S。看起来我的Web API只能看到第一个控制器(ProductsController) - 如果我删除显式路由[Route("...")],任何其他方法都不起作用...

2 个答案:

答案 0 :(得分:1)

  

据我所知,CreateAtRoute方法必须得到另一个问题   RouteName。如您所见,我可以通过添加路由名称来解决问题   参数(现在注释)并替换" DefaultApi"用" CreateOwner"   但它看起来像一个黑客。我相信还有另一种方法可以做到这一点   避免使用名称属性。

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

答案 1 :(得分:1)

我使用后续步骤解决了这个问题:

  1. 删除控制器的所有api/controller/{label} - 默认情况下让它们正常工作 - 它非常适合简单的请求。
  2. 重要提示:检查重复项的所有方法!问题是我有两个路由api/controller/{parameter}api/controller?label=1的方法 - 它无法理解默认情况下使用哪些方法。 (或使用显式的uri:public IHttpActionResult PostOwner(OwnerWrapper modelWrapper) { string productCode = modelWrapper.Product.Code; Owner owner = modelWrapper.Owners[0]; return CreatedAtRoute("DefaultApi", new { id = Owner.Id }, owner); }
  3. 重要提示:避免将api方法放入很多复杂类型 - 为它们创建Wrapper并只放置一个参数!
  4. 所有这些操作都让我删除了多余的属性,使方法更具可读性。

    结果如下:

    productCode

    这只是测试用例,所以我们可以看到import json >>> df = sqlContext.read.table("n1") >>> df.show() +-----+-------+----+---------------+-------+----+ | c1| c2| c3| c4| c5| c6| +-----+-------+----+---------------+-------+----+ |00001|Content| 1|Content-article| |2018| |00002|Content|null|Content-article|Content|2015| +-----+-------+----+---------------+-------+----+ >>> results = df.toJSON().map(lambda j: json.loads(j)).collect() >>> for i in results: print i["c1"], i["c6"] ... 00001 2018 00002 2015 从未使用过,但我真正的实现更难。

相关问题