我有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("...")]
,任何其他方法都不起作用...
答案 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)
我使用后续步骤解决了这个问题:
api/controller/{label}
- 默认情况下让它们正常工作 - 它非常适合简单的请求。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);
}
)所有这些操作都让我删除了多余的属性,使方法更具可读性。
结果如下:
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
从未使用过,但我真正的实现更难。