自定义ASP.NET MVC路由以服务".json"".xml"样式URL

Dus*_*sda 9 c# asp.net-mvc asp.net-mvc-routing

我有一个搜索Api,我正在努力,需要在一个Html块中返回搜索结果(使用客户端已经定义的样式).我还想在Json中返回结果,以便我们最终将使用的未来Api内容.目前,路线看起来像这样:

/api/1/search/json?param1=blah&param2=blah&etc
/api/1/search/html?param1=blah&param2=blah&etc
Run Code Online (Sandbox Code Playgroud)

作为参考,此处的模式为/ {area}/1/{controller}/{action}.

我喜欢一些Api的外观,我看到返回的结果会有不同的格式,具体取决于它们在url中的'扩展',la:

/api/1/search.json?param1=blah&param2=blah&etc
Run Code Online (Sandbox Code Playgroud)

但是,我还没有想出如何配置Asp.Net的Mvc路由来支持这种风格.ApiAreaRegistration.cs中的常规路由是:

context.MapRoute(
    "Api_default",
    "Api/1/{controller}/{action}/{id}",
    new { action = "Index", id = UrlParameter.Optional });
Run Code Online (Sandbox Code Playgroud)

我尝试了以下定义的一般,但不起作用:

//search api
context.MapRoute(
    "searchJson",
    "api/1/{controller}.{action}",
    new { controller = "SearchController" });
Run Code Online (Sandbox Code Playgroud)

如何配置路由以启用.format样式的URL?

son*_*tek 9

context.MapRoute(
    "Api_default",
    "{area}/1/{controller}.{format}",
    new { action = "Index", id = UrlParameter.Optional });
Run Code Online (Sandbox Code Playgroud)

可能就是你想要的.然后你可以根据传入的参数返回不同的结果.

在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);
    }
}
Run Code Online (Sandbox Code Playgroud)


mne*_*syn 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" });
Run Code Online (Sandbox Code Playgroud)

由于除输出序列化外,结果通常没有差异,因此您可能不希望路由到不同的操作.定制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;
    }
}
Run Code Online (Sandbox Code Playgroud)