programing tip

ASP.NET MVC Razor : 컨트롤러 작업 내에서 Razor 부분보기의 HTML을 렌더링하는 방법

itbloger 2020. 8. 22. 08:17
반응형

ASP.NET MVC Razor : 컨트롤러 작업 내에서 Razor 부분보기의 HTML을 렌더링하는 방법


ASP.NET보기 엔진에서 지정된 부분보기의 HTML을 생성하는 방법 은 알려져 있습니다.

그러나이 기능이 면도기 부분보기에서 사용되면 부분보기가 "UserControl"에서 파생되지 않는다는 예외가 있기 때문에 작동하지 않습니다.

Razor 부분보기를 지원하도록 렌더링을 수정하는 방법은 무엇입니까?

이 부분보기에서 이메일을 생성하기 때문에 이것이 필요합니다 ...

최신 정보:

실패한 코드 (@mcl) :

public string RenderPartialToString(string controlName, object viewData)
    {
        ViewPage viewPage = new ViewPage() { ViewContext = new ViewContext() };
        viewPage.Url = this.GetUrlHelper();

        string fullControlName = "~/Views/Email/" + controlName + ".ascx";

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

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

@Html.Partial("nameOfPartial", Model)

최신 정보

protected string RenderPartialViewToString(string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.RouteData.GetRequiredString("action");

    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();
    }
}

적절한 답변이 이미 주어졌지만 MVC 컨트롤러 클래스에서 사용할 수있는 도우미 메서드없이 사용할 수있는 덜 장황한 솔루션을 제안하고 싶습니다. "RazorEngine"이라는 타사 라이브러리를 사용하면 .Net 파일 IO를 사용하여 razor 파일의 내용을 가져오고 호출 할 수 있습니다.

string html = Razor.Parse(razorViewContentString, modelObject);

Get the third party library here.


You could also use the RenderView Controller extension from here (source)

and use it like this:

public ActionResult Do() {
var html = this.RenderView("index", theModel);
...
}

it works for razor and web-forms viewengines


I saw that someone was wondering how to do it for another controller.

In my case I had all of my email templates in the Views/Email folder, but you could modify this to pass in the controller in which you have views associated for.

public static string RenderViewToString(Controller controller, string viewName, object model)
    {
        var oldController = controller.RouteData.Values["controller"].ToString();

        if (controller.GetType() != typeof(EmailController))
            controller.RouteData.Values["controller"] = "Email";

        var oldModel = controller.ViewData.Model;
        controller.ViewData.Model = model;
        try
        {
            using (var sw = new StringWriter())
            {
                var viewResult = ViewEngines.Engines.FindView(controller.ControllerContext, viewName,
                                                                           null);

                var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
                viewResult.View.Render(viewContext, sw);

                //Cleanup
                controller.ViewData.Model = oldModel;
                controller.RouteData.Values["controller"] = oldController;

                return sw.GetStringBuilder().ToString();
            }
        }
        catch (Exception ex)
        {
            Elmah.ErrorSignal.FromCurrentContext().Raise(ex);

            throw ex;
        }
    }

Essentially what this does is take a controller, such as AccountController and modify it to think it's an EmailController so that the code will look in the Views/Email folder. It's necessary to do this because the FindView method doesn't take a straight up path as a parameter, it wants a ControllerContext.

Once done rendering the string, it returns the AccountController back to its initial state to be used by the Response object.


great code; little hint: if you sometimes have to bypass more data and not only the viewmodel ..

 if (model is ViewDataDictionary)
 {
     controller.ViewData = model as ViewDataDictionary;
 } else {
     controller.ViewData.Model = model;
 }

Borrowing @jgauffin answer as an HtmlHelper extension:

public static class HtmlHelperExtensions
{
    public static MvcHtmlString RenderPartialViewToString(
        this HtmlHelper html, 
        ControllerContext controllerContext, 
        ViewDataDictionary viewData,
        TempDataDictionary tempData,
        string viewName, 
        object model)
    {
        viewData.Model = model;
        string result = String.Empty;

        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);

            result = sw.GetStringBuilder().ToString();
        }

        return MvcHtmlString.Create(result);
    }
}

Usage in a razor view:

Html.RenderPartialViewToString(ViewContext, ViewData, TempData, "Search", Model)

참고URL : https://stackoverflow.com/questions/4344533/asp-net-mvc-razor-how-to-render-a-razor-partial-views-html-inside-the-controll

반응형