如何使一个动作一般显示一个View或一个序列化的ViewModel?

时间:2018-11-06 21:34:38

标签: c# json asp.net-mvc asp.net-mvc-5

在我的整个应用程序中,我使用强类型的视图模型。现在,我的任务是正常显示视图,或者如果存在特定参数,则提供序列化的ViewModel。

所以,我首先想到的是:

public ActionResult SomeAction(int id, string apiMode)
{
    var model = new ViewModel(); //Obtain model
    if (apiMode == "json")
    {
        return Json(model);
    }
    return View(model)
}

现在我想知道是否有更通用的解决方案?

1 个答案:

答案 0 :(得分:0)

完全有可能。

我们可以通过以下方式扩展RazorViewEngine

public class AppViewEngine : RazorViewEngine
{
    private const string ApiModeParam = "API__MODE";

    public AppViewEngine()
    {
        //Performance optimization, if we do not need to lookup for vbhtml
        FileExtensions = new[] {"cshtml"};
    }

    public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
    {
        var apiMode = controllerContext.HttpContext.Request.Params[ApiModeParam];
        if (apiMode == null)
        {
            return base.FindPartialView(controllerContext, partialViewName, useCache);
        }

        return GetApiResult(apiMode);
    }

    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        var apiMode = controllerContext.HttpContext.Request.Params[ApiModeParam];
        if (apiMode == null)
        {
            return base.FindView(controllerContext, viewName, masterName, useCache);
        }
        return GetApiResult(apiMode);
    }

    private ViewEngineResult GetApiResult(string apiMode)
    {
        switch (apiMode)
        {
            case "json":
                return new ViewEngineResult(new ApiJsonView(), this);
            case "xml":
                return new ViewEngineResult(new ApiXmlView(), this);
            default:
                return new ViewEngineResult(new[] { "API__MODE is not supported" });
        }

    }

}

现在我们只需要一些视图:

public class ApiJsonView : IView
{
    public void Render(ViewContext viewContext, TextWriter writer)
    {
        viewContext.HttpContext.Response.AddHeader("Content-Type", "application/json");

        //Json.NET, normaly included in MVC
        var serializer = JsonSerializer.Create();
        serializer.Serialize(writer, viewContext.ViewData.Model);
    }
}

public class ApiXmlView : IView
{
    public void Render(ViewContext viewContext, TextWriter writer)
    {
        viewContext.HttpContext.Response.AddHeader("Content-Type", "application/xml");
        var model = viewContext.ViewData.Model;
        var serializer = new DataContractSerializer(model.GetType());
        using (var xmlWriter = new XmlTextWriter(writer))
        {
            serializer.WriteObject(xmlWriter, model);
        }
    }
}

最后一件事:我们需要使用global.asax方法在Application_Start中注册它:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new AppViewEngine());

现在,每个附加了?API__MODE=json的请求都显示序列化的ViewModel而不是HTML页面。最好的是,它很简单:

public ActionResult SomeAction(int id)
{
    var model = new ViewModel(); //Obtain model
    return View(model)
}