【问题标题】:How to Render Partial View into a String如何将部分视图渲染成字符串
【发布时间】:2010-03-29 12:20:23
【问题描述】:

我有以下代码:

public ActionResult SomeAction()
{
    return new JsonpResult
    {
        Data = new { Widget = "some partial html for the widget" }
    };
}

我想修改它,以便我可以拥有

public ActionResult SomeAction()
{
    // will render HTML that I can pass to the JSONP result to return.
    var partial = RenderPartial(viewModel); 
    return new JsonpResult
    {
        Data = new { Widget = partial }
    };
}

这可能吗?有人可以解释一下吗?

注意,我在发布解决方案之前编辑了问题。

【问题讨论】:

  • 对于所有的答案——作为一个陷阱,如果你试图从另一个控制器渲染视图,你必须完全指定视图名称"~/Views/<Controller>/<ViewName>.cshtml"

标签: asp.net-mvc partial-views


【解决方案1】:

我为 ASP.NET MVC 4 应用程序选择了如下扩展方法。我认为这比我看到的一些建议更简单:

public static class ViewExtensions
{
    public static string RenderToString(this PartialViewResult partialView)
    {
        var httpContext = HttpContext.Current;

        if (httpContext == null)
        {
            throw new NotSupportedException("An HTTP context is required to render the partial view to a string");
        }

        var controllerName = httpContext.Request.RequestContext.RouteData.Values["controller"].ToString();

        var controller = (ControllerBase)ControllerBuilder.Current.GetControllerFactory().CreateController(httpContext.Request.RequestContext, controllerName);

        var controllerContext = new ControllerContext(httpContext.Request.RequestContext, controller);

        var view = ViewEngines.Engines.FindPartialView(controllerContext, partialView.ViewName).View;

        var sb = new StringBuilder();

        using (var sw = new StringWriter(sb))
        {
            using (var tw = new HtmlTextWriter(sw))
            {
                view.Render(new ViewContext(controllerContext, view, partialView.ViewData, partialView.TempData, tw), tw);
            }
        }

        return sb.ToString();
    }
}

它允许我执行以下操作:

var html = PartialView("SomeView").RenderToString();

此外,此方法保留视图的任何 Model、ViewBag 和其他视图数据。

【讨论】:

  • 我喜欢扩展方法的想法,因为您可以获得 PartialView 方法的语法突出显示和编辑时错误检查,即当找到具有该名称的视图时,视图名称会改变颜色。跨度>
  • @ted-nyberg 迁移到 MVC 5 应用程序,此扩展程序开始失败,并显示以下消息:“值不能为空。参数名称:controllerContext”,关于如何修复它的任何想法?谢谢。
【解决方案2】:

这是一个有效的答案的略微修改版本:

public static string RenderPartialToString(string controlName, object viewData)
{
    ViewPage viewPage = new ViewPage() { ViewContext = new ViewContext() };

    viewPage.ViewData = new ViewDataDictionary(viewData);
    viewPage.Controls.Add(viewPage.LoadControl(controlName));

    StringBuilder sb = new StringBuilder();
    using (StringWriter sw = new StringWriter(sb))
    {
        using (HtmlTextWriter tw = new HtmlTextWriter(sw))
        {
            viewPage.RenderControl(tw);
        }
    }

    return sb.ToString();
}

用法:

string ret = RenderPartialToString("~/Views/MyController/MyPartial.ascx", model);

【讨论】:

  • 这对我来说效果很好。但是,如果我将 RenderPartial 添加到传递给此方法的局部视图,我会开始在 RenderControl 调用上收到异常:“值不能为空。参数名称:视图”
  • 对我不起作用,我使用的是 razor 视图引擎,似乎这适用于 ascx 用户控件而不是部分 cshtml 视图。我在这里发布了我自己的适用于剃须刀的版本:stackoverflow.com/questions/5532345/…
【解决方案3】:

DaveDev 的回答对我来说效果很好,但是当局部视图调用另一个局部视图时,我得到“值不能为空。参数名称:视图”

四处搜索,我制作了following 的变体,似乎效果很好。

 public static string RenderPartialToString(string viewName, object model, ControllerContext ControllerContext)
    {
        if (string.IsNullOrEmpty(viewName))
            viewName = ControllerContext.RouteData.GetRequiredString("action");
        ViewDataDictionary ViewData = new ViewDataDictionary();
        TempDataDictionary TempData = new TempDataDictionary();
        ViewData.Model = model;

        using (StringWriter sw = new StringWriter())
        {
            ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
            ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
            viewResult.View.Render(viewContext, sw);

            return sw.GetStringBuilder().ToString();
        }

    }

用法:

String result = MVCHelpers.RenderPartialToString("PartialViewHere", Model, ControllerContext)

【讨论】:

    【解决方案4】:

    您可以创建将视图呈现为字符串的扩展。

    public static class RenderPartialToStringExtensions
    {
        /// <summary>
        /// render PartialView and return string
        /// </summary>
        /// <param name="context"></param>
        /// <param name="partialViewName"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        public static string RenderPartialToString(this ControllerContext context, string partialViewName, object model)
        {
            return RenderPartialToStringMethod(context, partialViewName, model);
        }
    
        /// <summary>
        /// render PartialView and return string
        /// </summary>
        /// <param name="context"></param>
        /// <param name="partialViewName"></param>
        /// <param name="viewData"></param>
        /// <param name="tempData"></param>
        /// <returns></returns>
        public static string RenderPartialToString(ControllerContext context, string partialViewName, ViewDataDictionary viewData, TempDataDictionary tempData)
        {
            return RenderPartialToStringMethod(context, partialViewName, viewData, tempData);
        }
    
        public static string RenderPartialToStringMethod(ControllerContext context, string partialViewName, ViewDataDictionary viewData, TempDataDictionary tempData)
        {
            ViewEngineResult result = ViewEngines.Engines.FindPartialView(context, partialViewName);
    
            if (result.View != null)
            {
                StringBuilder sb = new StringBuilder();
                using (StringWriter sw = new StringWriter(sb))
                {
                    using (HtmlTextWriter output = new HtmlTextWriter(sw))
                    {
                        ViewContext viewContext = new ViewContext(context, result.View, viewData, tempData, output);
                        result.View.Render(viewContext, output);
                    }
                }
    
                return sb.ToString();
            }
            return String.Empty;
        }
    
        public static string RenderPartialToStringMethod(ControllerContext context, string partialViewName, object model)
        {
            ViewDataDictionary viewData = new ViewDataDictionary(model);
            TempDataDictionary tempData = new TempDataDictionary();
            return RenderPartialToStringMethod(context, partialViewName, viewData, tempData);
        }
    }
    

    然后在行动中使用它

    [HttpPost]
    public ActionResult GetTreeUnit(string id)
    {
        int _id = id.ExtractID();
        string render = ControllerContext.RenderPartialToString("SomeView");
        return Json(new { data = render });
    }
    

    【讨论】:

      【解决方案5】:

      完美运行(仅需要视图名称)
      * 对于可以使用模型的参数
      * 也可以从视图中调用它

      查看端或调用端

      BuyOnlineCartMaster ToInvoice1 = new BuyOnlineCartMaster(); // for passing parameters
      ToInvoice1.CartID = 1;
      
      string HtmlString = RenderPartialViewToString("PartialInvoiceCustomer", ToInvoice1);
      

      生成 HTML 的函数

      public class BuyOnlineCartMaster
      {
              public int CartID { get; set; }
      }
      
       public static string RenderPartialViewToString(string viewName, object model)
       {    
           using (var sw = new StringWriter())
                  {
                      BuyOnlineController controller = new BuyOnlineController(); // instance of the required controller (you can pass this as a argument if needed)
      
                      // Create an MVC Controller Context
                      var wrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
      
                      RouteData routeData = new RouteData();
      
                      routeData.Values.Add("controller", controller.GetType().Name
                                                                  .ToLower()
                                                                  .Replace("controller", ""));
      
                      controller.ControllerContext = new ControllerContext(wrapper, routeData, controller);
      
                      controller.ViewData.Model = model;
      
                      var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
      
                      var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
                      viewResult.View.Render(viewContext, sw);
      
                      return sw.ToString();
                  }
         }
      

      部分视图页面

      @{ 
          var ModelContents = (Common.BuyOnlineCartMaster)ViewData.Model;
      
      
      }
      
      Your cart id : @(ModelContents.CartID)
      

      【讨论】:

        【解决方案6】:

        戴夫,

        同一主题的变体(mvc v1.0):

                protected static string RenderPartialToString(Controller controller, string partialName, object model)
            {
                var vd = new ViewDataDictionary(controller.ViewData);
                var vp = new ViewPage
                {
                    ViewData = vd,
                    ViewContext = new ViewContext(),
                    Url = new UrlHelper(controller.ControllerContext.RequestContext)
                };
        
                ViewEngineResult result = ViewEngines
                                          .Engines
                                          .FindPartialView(controller.ControllerContext, partialName);
        
                if (result.View == null)
                {
                    throw new InvalidOperationException(
                    string.Format("The partial view '{0}' could not be found", partialName));
                }
                var partialPath = ((WebFormView)result.View).ViewPath;
        
                vp.ViewData.Model = model;
        
                Control control = vp.LoadControl(partialPath);
                vp.Controls.Add(control);
        
                var sb = new StringBuilder();
        
                using (var sw = new StringWriter(sb))
                {
                    using (var tw = new HtmlTextWriter(sw))
                    {
                        vp.RenderControl(tw);
                    }
                }
                return sb.ToString();
            }
        

        在控制器中的使用:

                public string GetLocationHighlites()
            {
                IBlockData model = WebPagesMapper.GetLocationHighlites();
                // **this** being the controoler instance
                // LocationPartial.ascx can be defined in shared or in view folder
                return RenderPartialToString(**this**,"LocationPartial", model);
            }
        

        【讨论】:

          【解决方案7】:

          您可以立即使用:

          var partial = new HtmlString(Html.Partial("_myPartial", Model).ToString());
          

          【讨论】:

          • 我无法获取 Html.Partial。
          • @Dan-p 据我所知 Html.Partial 不能直接在控制器中使用。你是如何让这行代码工作的?
          • 抱歉,您是对的,我们在视图的 Razor 中的 @{ } 块中使用该行,而不是直接在控制器中。也许您的控制器可以返回使用该代码的部分视图。
          【解决方案8】:
          public virtual string RenderPartialViewToString(string viewName, object viewmodel)
                  {
                      if (string.IsNullOrEmpty(viewName))
                      {
                          viewName = this.ControllerContext.RouteData.GetRequiredString("action");
                      }
          
                      ViewData.Model = viewmodel;
          
                      using (var sw = new StringWriter())
                      {
                          ViewEngineResult viewResult = System.Web.Mvc.ViewEngines.Engines.FindPartialView(this.ControllerContext, viewName);
                          var viewContext = new ViewContext(this.ControllerContext, viewResult.View, this.ViewData, this.TempData, sw);
                          viewResult.View.Render(viewContext, sw);
                          viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
          
                          return sw.GetStringBuilder().ToString();
                      }
                  }
          

          【讨论】:

            【解决方案9】:

            旧帖子,但我认为你让这太难了。

            为什么return PartialView("&lt;my partial&gt;", model); 不会返回你想要的字符串。

            只需将 Get/Post 方法设为 IActionResult 和 JsonResult、PartialResult 和其他从 ActionResult 继承的方法,您就可以发回任何内容,包括 JsonResult

              [HttpPost]
              public IActionResult CheckForContent(string id, string type){
                try{
                   
                   if(type = "something"){
                      return Json(new {
                         success = true,
                         myProp = "this prop"       
                      });
                   } else {
                      MyViewModel model = new MyViewModel();
                      model.Content = _service.GetContent(new GetContentRequest(){ id = id }
                      return PartialView("<my partial>", model);
                } catch(Exception ex){
                   _logger.LogError(ex.Message);
                   return Json(new { success = false }
                }
              }
            

            阿贾克斯:

               $.ajax({
                  url: '/CheckForContent',
                  type: 'POST',
                  cache: false,
                  contentType: false,
                  processData: false,
                  success: function (result) {
                     if(!result && !result.success){
                        console.log("Failed to load");
                     } else if(result && result.success){
                        $('#MyProp').val(result.myProp);
                     } else {
                        $('#MyContainer').html(result);
                     }
                  },
               });
            

            【讨论】:

              猜你喜欢
              • 2015-11-01
              • 1970-01-01
              • 2013-10-09
              • 2014-01-10
              • 1970-01-01
              • 2015-07-16
              • 1970-01-01
              • 1970-01-01
              • 2022-01-14
              相关资源
              最近更新 更多