我正在进行搜索Api,需要在一个Html块中返回搜索结果(使用客户端在其末尾定义的样式)。我还想在Json中返回结果,以便我们最终将使用的未来Api内容。目前,路线看起来像这样:
/api/1/search/json?param1=blah¶m2=blah&etc
/api/1/search/html?param1=blah¶m2=blah&etc
作为参考,此处的模式为/ {area} / 1 / {controller} / {action}。
我喜欢一些Api的外观,我看到返回的结果会有不同的格式,具体取决于它们在网址中的“扩展名”,la:
/api/1/search.json?param1=blah¶m2=blah&etc
但是,我还没有想出如何配置Asp.Net的Mvc路由来支持这种风格。 ApiAreaRegistration.cs中的常规路由是:
context.MapRoute(
"Api_default",
"Api/1/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional });
我已尝试过以下定义的一般内容,但不起作用:
//search api
context.MapRoute(
"searchJson",
"api/1/{controller}.{action}",
new { controller = "SearchController" });
如何配置路由以启用.format样式的网址?
答案 0 :(得分:9)
context.MapRoute(
"Api_default",
"{area}/1/{controller}.{format}",
new { action = "Index", id = UrlParameter.Optional });
可能就是你想要的。然后你可以根据传入的参数返回不同的结果。
在Api区域的上下文中,SearchController将如下所示:
public class SearchController : Controller
{
public ActionResult Index(string format, SearchModel search)
{
var results = searchFacade.SearchStuff(search);
if(format.Equals("xml"))
return Xml(results); //using an XmlResult or whatever
if(format.Equals("html"))
return View(results);
return Json(results, JsonRequestBehavior.AllowGet);
}
}
答案 1 :(得分:6)
路由有点棘手,因为你在可选的参数后面插入了一个必需的参数 - 一般来说,我建议使用Accept-Type
标题,这样更加RESTful且更少路线很棘手。但是,对某些客户而言,这可能会有问题。
路由必须将带有id且没有id的表单考虑在内:
context.MapRoute(
"Api_default",
"Api/1/{controller}/{action}/{id}.{format}",
new { action = "Index" });
context.MapRoute(
"Api_default_2",
"Api/1/{controller}/{action}.{format}",
new { action = "Index" });
由于除输出序列化外,结果通常没有差异,因此您可能不希望路由到不同的操作。自定义ActionResult
可能会有所帮助。这样,不同的序列化逻辑可以集中化,并且易于扩展。
public class RestResult<T> : ActionResult
{
public T Data { get; set; }
public RestResult(T data)
{
Data = data;
}
private string SerializeToJson()
{
MemoryStream ms = new MemoryStream();
YourFavouriteJsonSerializer.SerializeToStream(Data, Data.GetType(), ms);
var temp = Encoding.UTF8.GetString(ms.ToArray());
return temp;
}
public override void ExecuteResult(ControllerContext context)
{
string resultString = string.Empty;
string resultContentType = string.Empty;
// alternatively, use the route value dictionary
// or the accept-type, as suggested.
var extension = SomeExtensionParserMethod(context.RequestContext.HttpContext.Request.RawUrl);
string result = string.Empty;
if (extension == "json")
{
result = SerializeJson()
}
else if(...)
// etc
context.RequestContext.HttpContext.Response.Write(resultString);
context.RequestContext.HttpContext.Response.ContentType = resultContentType;
}
}