代码之家  ›  专栏  ›  技术社区  ›  Christian Gollhardt

如何使操作一般地显示视图或序列化的视图模型?

  •  0
  • Christian Gollhardt  · 技术社区  · 6 年前

    在我的整个应用程序中,我使用强类型视图模型。现在,我有了显示视图正常状态的任务,或者在存在特定参数时提供序列化的viewmodel。

    所以,我首先想到的是:

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

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

    1 回复  |  直到 6 年前
        1
  •  0
  •   Christian Gollhardt    6 年前

    完全有可能。

    我们可以延长 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)
    }