Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 自定义ASP.NET MVC路由到“服务”;。json"&引用;。xml";样式URL_C#_Asp.net Mvc_Asp.net Mvc Routing - Fatal编程技术网

C# 自定义ASP.NET MVC路由到“服务”;。json"&引用;。xml";样式URL

C# 自定义ASP.NET MVC路由到“服务”;。json"&引用;。xml";样式URL,c#,asp.net-mvc,asp.net-mvc-routing,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 public class SearchController : Controller { publ

我有一个正在开发的搜索Api,它需要以Html块的形式返回搜索结果(使用客户端定义的样式)。我还想返回Json格式的结果,以便将来我们最终使用Api。目前,路线如下所示:

/api/1/search/json?param1=blah&param2=blah&etc
/api/1/search/html?param1=blah&param2=blah&etc
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);
    }
}
作为参考,这里的模式是/{area}/1/{controller}/{action}

我喜欢一些Api的外观,我看到返回结果的格式不同,这取决于url中的“扩展名”,即la:

/api/1/search.json?param1=blah&param2=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样式的URL

context.MapRoute(
    "Api_default",
    "{area}/1/{controller}.{format}",
    new { action = "Index", id = UrlParameter.Optional });
这可能是你想要的。然后,您可以根据传入的参数返回不同的结果

在Api区域的上下文中,SearchController如下所示:

/api/1/search/json?param1=blah&param2=blah&etc
/api/1/search/html?param1=blah&param2=blah&etc
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);
    }
}

路由有点棘手,因为您在可选参数之后插入了一个必需的参数-一般来说,我建议使用
接受类型
,这既更加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;
    }
}
public类RestResult:ActionResult
{
公共T数据{get;set;}
公共厕所结果(T数据)
{
数据=数据;
}
私有字符串序列化为JSON()
{
MemoryStream ms=新的MemoryStream();
YourFavoriteJSonSerializer.SerializeToStream(Data,Data.GetType(),ms);
var temp=Encoding.UTF8.GetString(ms.ToArray());
返回温度;
}     
公共覆盖无效ExecuteSult(ControllerContext上下文)
{
string resultString=string.Empty;
string resultContentType=string.Empty;
//或者,使用路由值字典
//或者是建议的接受类型。
var extension=SomeExtensionParserMethod(context.RequestContext.HttpContext.Request.RawUrl);
字符串结果=string.Empty;
if(扩展名==“json”)
{
结果=序列化JSON()
}
否则如果(…)
//等
context.RequestContext.HttpContext.Response.Write(resultString);
context.RequestContext.HttpContext.Response.ContentType=resultContentType;
}
}

我喜欢这种方法,不过我可能会使用ActionFilter,这样就不必返回自定义的ActionResults。当我将此样式应用于Api的其余部分(搜索之外)时,我将对此进行更多研究。这对我来说没有太大意义:如果您使用
ActionFilter
修改结果,您将允许您的控制器返回任何
ActionResult
,例如
FileResult、ContentResult
ViewResult
,其中大多数在RESTAPI上下文中没有意义。此外,您还需要访问一些可以序列化的强类型对象。因此,您必须使用
ViewResult
Model
(并且您必须使用它的实际类型,而不是声明的类型),
JsonResult.Data
,对于ContentResult,除了转发字符串之外,没有其他解决方案?有点黑…那是因为我最终的计划是尝试将Api集成到站点本身,类似于Vanilla的工作方式。看这个:然后这个:。在我看来,这种风格非常自然,基本上只是将幕后使用的模型序列化并将其公开。有明显的安全考虑需要考虑,但作为一个总的想法,我真的很喜欢。不过,你可能是对的,我最终可能需要一个CustomResult(以防止不必要的渲染和其他东西)。我在这种方法上遇到了麻烦:IIS中正确的错误处理是一团乱,而要让最终用户和API用户正确地使用它似乎非常棘手,我没有做到这一点。无论如何,这与您的
操作结果的类型没有任何关系?我也采用了ActionFilter方法。它根据我的接受类型(取自扩展,如果不是querystring,如果不是accept头)确定它可以返回什么内容类型(如果有)。它运行良好,易于扩展:这在我的SearchController中非常有效;它默认为索引,我根据指定的格式返回不同的ActionResult,默认为json。最后,我想知道如何覆盖使用ActionFilter返回的ActionResult,这样我就不必在操作中手动执行,但现在就可以了。