传回多个服务uris
我创建了一个asp.net web api 2控制器来管理逻辑资产。 像往常一样,这篇文章创建它并将uri返回给资产,删除将它删除,但是我有2个put来对资产执行单独的操作,所以我的代码如下所示:
public class Controller : ApiController
{
public IHttpActionResult Post(Stuff stuff)
{
var id = CreateNewStuff(stuff);
return CreatedAtRoute("DefaultApi", new { id = this.id }, id);
}
[HttpPut]
public IHttpActionResult ActionA(int id, ActionAStuff stuff)
{
// Perform action A
return Ok();
}
[HttpPut]
public IHttpActionResult ActionB(int id, ActionBStuff stuff)
{
// Perform action B
return Ok();
}
public IHttpActionResult Delete(int id)
{
// Delete the asset
return Ok();
}
}
为了使路由理解这一点,我的路由规则是(包括默认规则):
config.Routes.MapHttpRoute(name: "ActionApi", routeTemplate: "api/{controller}/{action}/{id}");
config.Routes.MapHttpRoute(name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional });
这是有效的,并且感觉系统整齐地按照行动分开投入代码,并且确保系统将拒绝我们不支持的动作的请求。
问题是,通过post创建资产的客户端不知道put(action)uris是什么,它通过从post发回的位置标题对资产uri执行的操作。 如果我们将来改变uri形式,那么客户端就会因为手动创建uris而破裂。
从帖子中返回多个servicepoint uris的正确方法是什么,或者只是做得更好。
使用路线区分操作。 例如:
[RoutePrefix("api/Admin")]
public class Controller : ApiController
{
[Route("ActionA")
[HttpPut]
public IHttpActionResult ActionA(int id, ActionAStuff stuff)
{
// Perform action A
return Ok();
}
[Route("ActionB")
[HttpPut]
public IHttpActionResult ActionB(int id, ActionBStuff stuff)
{
// Perform action B
return Ok();
}
}
然后在您的webapiconfig.cs中启用属性路由
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API routes
config.MapHttpAttributeRoutes();
// Other Web API configuration not shown.
}
}
最后在您的客户端中,您可以区分如下所示的放置URI:http(s):/// api / Admin / ActionA
HTTP(S):/// API /管理员/ ActionB
每个方法都应该使用路由前缀来区分。
[Route("ActionA")
[HttpPut]
public IHttpActionResult ActionA(int id, ActionAStuff stuff)
{
// Perform action A
return Ok();
}
当我们使用config.Routes.MapHttpRoute中的Route config配置路由时,它必须是正确的顺序,因为它添加到堆栈并从堆栈中使用。
一旦它从路由表中找到任何条目,它就会尝试执行它。 所以更好的方法是使用路由前缀。
您可以将链接标题添加到POST
方法的结果中:
为了给IHttpActionResult
类添加一个自定义头文件,你可以定义一个扩展方法,例如:
public static class HttpActionResultHeaderExtensions
{
public static IHttpActionResult AddHeader(this IHttpActionResult action,
string headerName,
params string[] headerValues)
{
return new HeaderActionResult(action, headerName, headerValues);
}
private class HeaderActionResult : IHttpActionResult
{
private readonly IHttpActionResult action;
private readonly Tuple<string, IEnumerable<string>> header;
public HeaderActionResult(IHttpActionResult action,
string headerName,
IEnumerable<string> headerValues)
{
this.action = action;
header = Tuple.Create(headerName, headerValues);
}
public async Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = await action.ExecuteAsync(cancellationToken);
response.Headers.Add(header.Item1, header.Item2);
return response;
}
}
}
添加路线属性:
[System.Web.Http.RoutePrefixAttribute("api/stuff")]
public class Controller : ApiController
{
[System.Web.Http.HttpPut]
[System.Web.Http.RouteAttribute("ActionA", Name = "ActionA")]
public IHttpActionResult ActionA(int id, ActionAStuff stuff)
{
// your code
}
[System.Web.Http.HttpPut]
[System.Web.Http.RouteAttribute("ActionB", Name = "ActionB")]
public IHttpActionResult ActionB(int id, ActionBStuff stuff)
{
// your code
}
}
扩展POST
方法,将标题链接添加到结果中:
public IHttpActionResult Post(Stuff stuff)
{
var id = CreateNewStuff(stuff);
var actionALink = this.Url.Link("ActionA", new { id = id });
var actionBLink = this.Url.Link("ActionB", new { id = id });
return CreatedAtRoute("DefaultApi", new { id = id }, id)
.AddHeader("Link", $"<{actionALink}>; rel="ActionA"",
$"<{actionBLink}>; rel="ActionB"");
}
扩展配置:
config.MapHttpAttributeRoutes();
config.EnsureInitialized();