Làm thế nào để hiển thị một khung nhìn ASP.NET MVC dưới dạng một chuỗi?


485

Tôi muốn xuất ra hai chế độ xem khác nhau (một dạng chuỗi sẽ được gửi dưới dạng email) và trang kia hiển thị cho người dùng.

Điều này có thể có trong ASP.NET MVC beta không?

Tôi đã thử nhiều ví dụ:

1. RenderPartial to String trong ASP.NET MVC Beta

Nếu tôi sử dụng ví dụ này, tôi sẽ nhận được "Không thể chuyển hướng sau khi tiêu đề HTTP đã được gửi."

2. Khung MVC: Chụp đầu ra của khung nhìn

Nếu tôi sử dụng điều này, tôi dường như không thể thực hiện chuyển hướng, vì nó cố gắng hiển thị chế độ xem có thể không tồn tại. Nếu tôi quay lại chế độ xem, nó hoàn toàn bị rối và trông không ổn chút nào.

Có ai có bất kỳ ý tưởng / giải pháp cho những vấn đề này tôi có, hoặc có bất kỳ đề xuất cho những vấn đề tốt hơn?

Cảm ơn nhiều!

Dưới đây là một ví dụ. Những gì tôi đang cố gắng làm là tạo phương thức GetViewForEmail :

public ActionResult OrderResult(string ref)
{
    //Get the order
    Order order = OrderService.GetOrder(ref);

    //The email helper would do the meat and veg by getting the view as a string
    //Pass the control name (OrderResultEmail) and the model (order)
    string emailView = GetViewForEmail("OrderResultEmail", order);

    //Email the order out
    EmailHelper(order, emailView);
    return View("OrderResult", order);
}

Câu trả lời được chấp nhận từ Tim Scott (được tôi thay đổi và định dạng một chút):

public virtual string RenderViewToString(
    ControllerContext controllerContext,
    string viewPath,
    string masterPath,
    ViewDataDictionary viewData,
    TempDataDictionary tempData)
{
    Stream filter = null;
    ViewPage viewPage = new ViewPage();

    //Right, create our view
    viewPage.ViewContext = new ViewContext(controllerContext, new WebFormView(viewPath, masterPath), viewData, tempData);

    //Get the response context, flush it and get the response filter.
    var response = viewPage.ViewContext.HttpContext.Response;
    response.Flush();
    var oldFilter = response.Filter;

    try
    {
        //Put a new filter into the response
        filter = new MemoryStream();
        response.Filter = filter;

        //Now render the view into the memorystream and flush the response
        viewPage.ViewContext.View.Render(viewPage.ViewContext, viewPage.ViewContext.HttpContext.Response.Output);
        response.Flush();

        //Now read the rendered view.
        filter.Position = 0;
        var reader = new StreamReader(filter, response.ContentEncoding);
        return reader.ReadToEnd();
    }
    finally
    {
        //Clean up.
        if (filter != null)
        {
            filter.Dispose();
        }

        //Now replace the response filter
        response.Filter = oldFilter;
    }
}

Ví dụ sử dụng

Giả sử một cuộc gọi từ bộ điều khiển để nhận email xác nhận đơn hàng, đi qua vị trí Site.Master.

string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);

2
Làm thế nào bạn có thể sử dụng điều này với một cái nhìn, được gõ mạnh mẽ? I E. Làm thế nào tôi có thể cung cấp một mô hình cho trang?
Kjensen

Không thể sử dụng điều này và tạo JsonResult sau đó, vì loại nội dung không thể được đặt sau khi tiêu đề đã được gửi (vì Flush gửi chúng).
Arnis Lapsa

Bởi vì không có câu trả lời đúng duy nhất, tôi cho rằng. :) Tôi đã tạo ra một câu hỏi dành riêng cho tôi, nhưng tôi biết rằng đó cũng là một câu hỏi được hỏi rộng rãi.
Dan Atkinson

2
Giải pháp được đề xuất không hoạt động trong MVC 3.
Kasper Holdum

1
@Qua: Giải pháp đề xuất là hơn hai năm tuổi. Tôi cũng không mong đợi nó hoạt động cho MVC 3! Bên cạnh đó, có những cách tốt hơn để làm điều này bây giờ.
Dan Atkinson

Câu trả lời:


572

Đây là những gì tôi nghĩ ra và nó hiệu quả với tôi. Tôi đã thêm (các) phương thức sau vào lớp cơ sở điều khiển của mình. (Bạn luôn có thể đặt các phương thức tĩnh này ở một nơi khác chấp nhận bộ điều khiển làm tham số tôi cho là)

Kiểu MVC2 .ascx

protected string RenderViewToString<T>(string viewPath, T model) {
  ViewData.Model = model;
  using (var writer = new StringWriter()) {
    var view = new WebFormView(ControllerContext, viewPath);
    var vdd = new ViewDataDictionary<T>(model);
    var viewCxt = new ViewContext(ControllerContext, view, vdd,
                                new TempDataDictionary(), writer);
    viewCxt.View.Render(viewCxt, writer);
    return writer.ToString();
  }
}

Dao cạo .cshtml phong cách

public string RenderRazorViewToString(string viewName, object model)
{
  ViewData.Model = model;
  using (var sw = new StringWriter())
  {
    var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext,
                                                             viewName);
    var viewContext = new ViewContext(ControllerContext, viewResult.View,
                                 ViewData, TempData, sw);
    viewResult.View.Render(viewContext, sw);
    viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
    return sw.GetStringBuilder().ToString();
  }
}

Chỉnh sửa: thêm mã Dao cạo.


31
Hiển thị chế độ xem thành một chuỗi luôn "không phù hợp với toàn bộ khái niệm định tuyến", vì nó không liên quan gì đến định tuyến. Tôi không chắc tại sao một câu trả lời có tác dụng lại bỏ phiếu.
Ben Lesh

4
Tôi nghĩ rằng bạn có thể cần phải xóa "tĩnh" khỏi khai báo phương thức của phiên bản Dao cạo, nếu không, nó không thể tìm thấy ControlContext et al.
Mike

3
Bạn sẽ cần phải thực hiện phương pháp loại bỏ của riêng bạn cho những khoảng trắng thừa. Cách tốt nhất tôi có thể nghĩ ra khỏi đỉnh đầu là tải chuỗi vào XmlDocument, sau đó viết lại thành chuỗi có XmlWriter, theo liên kết tôi để lại trong bình luận cuối cùng của tôi. Tôi thực sự hy vọng điều đó sẽ giúp.
Ben Lesh

3
Hmm, tôi nên làm điều này như thế nào bằng Trình điều khiển WebApi, mọi đề xuất sẽ được đánh giá cao
Alexander

3
Xin chào mọi người sử dụng nó với từ khóa "Tĩnh" cho tất cả các bộ điều khiển để làm cho nó phổ biến, bạn phải tạo lớp tĩnh và bên trong nó, bạn phải đặt phương thức này với tham số "this" làm "Tham số". Bạn có thể thấy ở đây stackoverflow.com/a/18978036/2318354 nó.
Dilip0165

68

Câu trả lời này không phải trên đường của tôi. Đây là bản gốc từ https://stackoverflow.com/a/2759898/2318354 nhưng ở đây tôi đã chỉ ra cách sử dụng nó với Từ khóa "Tĩnh" để làm cho nó phổ biến cho tất cả các Bộ điều khiển.

Cho rằng bạn phải làm cho staticlớp trong tập tin lớp. (Giả sử Tên tệp lớp của bạn là Utils.cs)

Ví dụ này là cho dao cạo.

Công dụng.cs

public static class RazorViewToString
{
    public static string RenderRazorViewToString(this Controller controller, string viewName, object model)
    {
        controller.ViewData.Model = model;
        using (var sw = new StringWriter())
        {
            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);
            viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View);
            return sw.GetStringBuilder().ToString();
        }
    }
}

Bây giờ bạn có thể gọi lớp này từ trình điều khiển của mình bằng cách thêm NameSpace trong Tệp điều khiển của bạn theo cách sau bằng cách chuyển "this" làm tham số cho Trình điều khiển.

string result = RazorViewToString.RenderRazorViewToString(this ,"ViewName", model);

Theo đề xuất của @Sergey, phương thức mở rộng này cũng có thể gọi từ trình điều khiển như được đưa ra dưới đây

string result = this.RenderRazorViewToString("ViewName", model);

Tôi hy vọng điều này sẽ hữu ích để bạn làm cho mã sạch sẽ và gọn gàng.


1
Giải pháp tốt đẹp! Một điều, RenderRazorViewToString thực sự là phương thức mở rộng (vì bạn truyền tham số bộ điều khiển với từ khóa này), vì vậy phương thức tiện ích mở rộng này có thể được gọi theo cách này: this.RenderRazorViewToString ("ViewName", model);
Sergey

@Sergey Hmmm ... Hãy để tôi kiểm tra theo cách đó, nếu nó tốt hơn tôi sẽ cập nhật câu trả lời của tôi. Dù sao cũng cảm ơn lời đề nghị của bạn.
Dilip0165

Dilip0165, tôi gặp lỗi tham chiếu null trên var viewResult = ViewEngines.Engines.FindPartialView (control.ContoderContext, viewName);. Bạn còn ý kiến ​​nào không?
CB4

@ CB4 Tôi nghĩ đó có thể là vấn đề của "viewName" mà bạn đang chuyển vào chức năng. Bạn phải vượt qua "viewName" với đường dẫn đầy đủ theo cấu trúc thư mục của bạn. Vì vậy, kiểm tra điều này.
Dilip0165

1
@Sergey Cảm ơn lời đề nghị của bạn, tôi đã cập nhật câu trả lời của mình theo đề nghị của bạn hoàn toàn chính xác
Dilip0165

32

Điều này làm việc cho tôi:

public virtual string RenderView(ViewContext viewContext)
{
    var response = viewContext.HttpContext.Response;
    response.Flush();
    var oldFilter = response.Filter;
    Stream filter = null;
    try
    {
        filter = new MemoryStream();
        response.Filter = filter;
        viewContext.View.Render(viewContext, viewContext.HttpContext.Response.Output);
        response.Flush();
        filter.Position = 0;
        var reader = new StreamReader(filter, response.ContentEncoding);
        return reader.ReadToEnd();
    }
    finally
    {
        if (filter != null)
        {
            filter.Dispose();
        }
        response.Filter = oldFilter;
    }
}

Cảm ơn vì nhận xét của bạn, nhưng không được sử dụng để hiển thị bên trong chế độ xem? Làm thế nào tôi có thể sử dụng nó trong bối cảnh tôi đã cập nhật câu hỏi với?
Dan Atkinson

Xin lỗi, vẫn đang suy nghĩ về Silverlight năm ngoái có chiếc RC đầu tiên là 0. :) Tôi sẽ thử cái này hôm nay. (Ngay sau khi tôi tìm ra định dạng chính xác của đường dẫn xem)
NikolaiDante

Điều này vẫn phá vỡ các chuyển hướng trong RC1
đánh bại

đánh bại: Không, nó không. Nếu vậy, thì bạn đang làm gì đó sai.
Dan Atkinson

Đã hợp nhất điều này với stackoverflow.com/questions/520863/ , đã bổ sung nhận thức về ViewEnginesCollection, đã cố gắng bật một phần và xem stackoverflow.com/questions/520863/ . : E
Arnis Lapsa

31

Tôi đã tìm thấy một giải pháp mới giúp hiển thị chế độ xem thành chuỗi mà không phải gặp rắc rối với luồng Phản hồi của HTTPContext hiện tại (không cho phép bạn thay đổi ContentType hoặc các tiêu đề khác của phản hồi).

Về cơ bản, tất cả những gì bạn làm là tạo một HTTPContext giả để chế độ xem tự hiển thị:

/// <summary>Renders a view to string.</summary>
public static string RenderViewToString(this Controller controller,
                                        string viewName, object viewData) {
    //Create memory writer
    var sb = new StringBuilder();
    var memWriter = new StringWriter(sb);

    //Create fake http context to render the view
    var fakeResponse = new HttpResponse(memWriter);
    var fakeContext = new HttpContext(HttpContext.Current.Request, fakeResponse);
    var fakeControllerContext = new ControllerContext(
        new HttpContextWrapper(fakeContext),
        controller.ControllerContext.RouteData,
        controller.ControllerContext.Controller);

    var oldContext = HttpContext.Current;
    HttpContext.Current = fakeContext;

    //Use HtmlHelper to render partial view to fake context
    var html = new HtmlHelper(new ViewContext(fakeControllerContext,
        new FakeView(), new ViewDataDictionary(), new TempDataDictionary()),
        new ViewPage());
    html.RenderPartial(viewName, viewData);

    //Restore context
    HttpContext.Current = oldContext;    

    //Flush memory and return output
    memWriter.Flush();
    return sb.ToString();
}

/// <summary>Fake IView implementation used to instantiate an HtmlHelper.</summary>
public class FakeView : IView {
    #region IView Members

    public void Render(ViewContext viewContext, System.IO.TextWriter writer) {
        throw new NotImplementedException();
    }

    #endregion
}

Công trình này trên ASP.NET MVC 1.0, cùng với ContentResult, JsonResult, vv (thay đổi Headers trên bản gốc HttpResponse không ném " Máy chủ không thể thiết lập kiểu nội dung sau HTTP headers đã được gửi đi " ngoại lệ).

Cập nhật: trong ASP.NET MVC 2.0 RC, mã thay đổi một chút vì chúng ta phải chuyển qua StringWritersử dụng để ghi khung nhìn vào ViewContext:

//...

//Use HtmlHelper to render partial view to fake context
var html = new HtmlHelper(
    new ViewContext(fakeControllerContext, new FakeView(),
        new ViewDataDictionary(), new TempDataDictionary(), memWriter),
    new ViewPage());
html.RenderPartial(viewName, viewData);

//...

Không có phương thức RenderPartial trên đối tượng HtmlHelper. Điều này là không thể - html.RenderPartial (viewName, viewData);
MartinF

1
Trong ASP.NET MVC phát hành 1.0, có một vài phương thức mở rộng RenderPartial. Ứng dụng tôi đang sử dụng cụ thể là System.Web.Mvc.Html.RenderPartialExtensions.RenderPartial (HtmlHelper, chuỗi, đối tượng) này. Tôi không biết liệu phương thức này đã được thêm vào trong các phiên bản mới nhất của MVC và không có trong các phiên bản trước đó.
LorenzCK

Cảm ơn. Chỉ cần thêm không gian tên System.Web.Mvc.Html vào khai báo bằng cách sử dụng (khác html.RenderPartial (..) tất nhiên sẽ không thể truy cập được :))
MartinF

Có ai có cái này làm việc với RC của MVC2 không? Họ đã thêm một tham số Textwriter bổ sung vào ViewContext. Tôi đã thử chỉ thêm một StringWriter () mới, nhưng nó không hoạt động.
vẫy gọi

1
@beckelmw: Tôi đã cập nhật phản hồi. Bạn phải chuyển trong bản gốc StringWritermà bạn đang sử dụng để ghi vào StringBuilder, không phải là một thể hiện mới hoặc đầu ra của khung nhìn sẽ bị mất.
LorenzCK

11

Bài viết này mô tả cách hiển thị Chế độ xem thành chuỗi trong các trường hợp khác nhau:

  1. Bộ điều khiển MVC gọi một ActionMethods khác của riêng nó
  2. Bộ điều khiển MVC gọi ActionMethod của Bộ điều khiển MVC khác
  3. Trình điều khiển WebAPI gọi ActionMethod của Trình điều khiển MVC

Giải pháp / mã được cung cấp dưới dạng một lớp gọi là ViewRenderer . Nó là một phần của WestwindToolkit của Rick Stahl tại GitHub .

Cách sử dụng (3. - Ví dụ về WebAPI):

string html = ViewRenderer.RenderView("~/Areas/ReportDetail/Views/ReportDetail/Index.cshtml", ReportVM.Create(id));

3
Cũng như gói NuGet West Wind Web MVC Utility ( nuget.org/packages/Westwind.Web.Mvc ). Là một phần thưởng, trình kết xuất chế độ xem không chỉ có thể hiển thị một phần chế độ xem mà còn toàn bộ chế độ xem bao gồm Bố cục. Bài viết trên blog có mã: weblog.west-wind.com/posts/2012/May/30/iêu
Jeroen K

Sẽ thật tuyệt nếu điều này được chia thành các gói nhỏ hơn. Gói Nuget thực hiện một loạt các thay đổi cho web.config và thêm các tệp js vào dự án của bạn, sau đó không được dọn sạch khi bạn gỡ cài đặt nó: /
Josh Noe

8

Nếu bạn muốn từ bỏ MVC hoàn toàn, do đó tránh tất cả các mớ hỗn độn httpContext ...

using RazorEngine;
using RazorEngine.Templating; // For extension methods.

string razorText = System.IO.File.ReadAllText(razorTemplateFileLocation);
string emailBody = Engine.Razor.RunCompile(razorText, "templateKey", typeof(Model), model);

Điều này sử dụng Công cụ dao động mã nguồn mở tuyệt vời tại đây: https://github.com/Antaris/RazorEngine


Đẹp! Bạn có biết nếu có một công cụ phân tích cú pháp tương tự cho cú pháp WebForms không? Tôi vẫn còn một số chế độ xem WebForms cũ chưa thể chuyển sang Dao cạo.
Dan Atkinson

Xin chào, tôi đã có rất nhiều vấn đề với razorengine và báo cáo lỗi không được tốt lắm. Tôi không nghĩ người trợ giúp Url được hỗ trợ
Layinka

@Layinka Không chắc chắn nếu điều này có ích, nhưng hầu hết các thông tin lỗi nằm trong thuộc CompilerErrorstính của ngoại lệ.
Josh Noe

5

bạn có được khung nhìn trong chuỗi bằng cách này

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

    if (model != null)
        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();
    }
}

Chúng tôi gọi phương pháp này theo hai cách

string strView = RenderPartialViewToString("~/Views/Shared/_Header.cshtml", null)

HOẶC LÀ

var model = new Person()
string strView = RenderPartialViewToString("~/Views/Shared/_Header.cshtml", model)

4

Mẹo bổ sung cho COR NET CORE:

Giao diện:

public interface IViewRenderer
{
  Task<string> RenderAsync<TModel>(Controller controller, string name, TModel model);
}

Thực hiện:

public class ViewRenderer : IViewRenderer
{
  private readonly IRazorViewEngine viewEngine;

  public ViewRenderer(IRazorViewEngine viewEngine) => this.viewEngine = viewEngine;

  public async Task<string> RenderAsync<TModel>(Controller controller, string name, TModel model)
  {
    ViewEngineResult viewEngineResult = this.viewEngine.FindView(controller.ControllerContext, name, false);

    if (!viewEngineResult.Success)
    {
      throw new InvalidOperationException(string.Format("Could not find view: {0}", name));
    }

    IView view = viewEngineResult.View;
    controller.ViewData.Model = model;

    await using var writer = new StringWriter();
    var viewContext = new ViewContext(
       controller.ControllerContext,
       view,
       controller.ViewData,
       controller.TempData,
       writer,
       new HtmlHelperOptions());

       await view.RenderAsync(viewContext);

       return writer.ToString();
  }
}

Đăng ký tại Startup.cs

...
 services.AddSingleton<IViewRenderer, ViewRenderer>();
...

Và sử dụng trong bộ điều khiển:

public MyController: Controller
{
  private readonly IViewRenderer renderer;
  public MyController(IViewRendere renderer) => this.renderer = renderer;
  public async Task<IActionResult> MyViewTest
  {
    var view = await this.renderer.RenderAsync(this, "MyView", model);
    return new OkObjectResult(view);
  }
}

3

Tôi đang sử dụng MVC 1.0 RTM và không có giải pháp nào ở trên làm việc cho tôi. Nhưng điều này đã làm:

Public Function RenderView(ByVal viewContext As ViewContext) As String

    Dim html As String = ""

    Dim response As HttpResponse = HttpContext.Current.Response

    Using tempWriter As New System.IO.StringWriter()

        Dim privateMethod As MethodInfo = response.GetType().GetMethod("SwitchWriter", BindingFlags.NonPublic Or BindingFlags.Instance)

        Dim currentWriter As Object = privateMethod.Invoke(response, BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.InvokeMethod, Nothing, New Object() {tempWriter}, Nothing)

        Try
            viewContext.View.Render(viewContext, Nothing)
            html = tempWriter.ToString()
        Finally
            privateMethod.Invoke(response, BindingFlags.NonPublic Or BindingFlags.Instance Or BindingFlags.InvokeMethod, Nothing, New Object() {currentWriter}, Nothing)
        End Try

    End Using

    Return html

End Function

2

Tôi đã thấy một triển khai cho MVC 3 và Razor từ một trang web khác, nó hoạt động với tôi:

    public static string RazorRender(Controller context, string DefaultAction)
    {
        string Cache = string.Empty;
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        System.IO.TextWriter tw = new System.IO.StringWriter(sb); 

        RazorView view_ = new RazorView(context.ControllerContext, DefaultAction, null, false, null);
        view_.Render(new ViewContext(context.ControllerContext, view_, new ViewDataDictionary(), new TempDataDictionary(), tw), tw);

        Cache = sb.ToString(); 

        return Cache;

    } 

    public static string RenderRazorViewToString(string viewName, object model)
    {

        ViewData.Model = model;
        using (var sw = new StringWriter())
        {
            var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
            var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
            viewResult.View.Render(viewContext, sw);
            return sw.GetStringBuilder().ToString();
        }
    } 

    public static class HtmlHelperExtensions
    {
        public static string RenderPartialToString(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;

        }

    }

Thông tin thêm về Dao động kết xuất- MVC3 Xem Kết xuất thành Chuỗi


Vâng, đây thực sự là một bản sao của câu trả lời được chấp nhận. :)
Dan Atkinson

2

Để hiển thị chế độ xem cho một chuỗi trong Lớp dịch vụ mà không cần phải vượt qua Trình điều khiển xung quanh, có một bài viết hay về Rick Strahl ở đây http://www.codemag.com/Article/1312081 tạo ra một bộ điều khiển chung. Tóm tắt mã dưới đây:

// Some Static Class
public static string RenderViewToString(ControllerContext context, string viewPath, object model = null, bool partial = false)
{
    // first find the ViewEngine for this view
    ViewEngineResult viewEngineResult = null;
    if (partial)
        viewEngineResult = ViewEngines.Engines.FindPartialView(context, viewPath);
    else
        viewEngineResult = ViewEngines.Engines.FindView(context, viewPath, null);

    if (viewEngineResult == null)
        throw new FileNotFoundException("View cannot be found.");

    // get the view and attach the model to view data
    var view = viewEngineResult.View;
    context.Controller.ViewData.Model = model;

    string result = null;

    using (var sw = new StringWriter())
    {
        var ctx = new ViewContext(context, view, context.Controller.ViewData, context.Controller.TempData, sw);
        view.Render(ctx, sw);
        result = sw.ToString();
    }

    return result;
}

// In the Service Class
public class GenericController : Controller
{ }

public static T CreateController<T>(RouteData routeData = null) where T : Controller, new()
{
    // create a disconnected controller instance
    T controller = new T();

    // get context wrapper from HttpContext if available
    HttpContextBase wrapper;
    if (System.Web.HttpContext.Current != null)
        wrapper = new HttpContextWrapper(System.Web.HttpContext.Current);
    else
        throw new InvalidOperationException("Cannot create Controller Context if no active HttpContext instance is available.");

    if (routeData == null)
        routeData = new RouteData();

    // add the controller routing if not existing
    if (!routeData.Values.ContainsKey("controller") &&
        !routeData.Values.ContainsKey("Controller"))
        routeData.Values.Add("controller", controller.GetType().Name.ToLower().Replace("controller", ""));

    controller.ControllerContext = new ControllerContext(wrapper, routeData, controller);
    return controller;
}

Sau đó, để hiển thị Chế độ xem trong lớp Dịch vụ:

var stringView = RenderViewToString(CreateController<GenericController>().ControllerContext, "~/Path/To/View/Location/_viewName.cshtml", theViewModel, true);

1

Mẹo nhanh

Đối với Mô hình được gõ mạnh, chỉ cần thêm nó vào thuộc tính ViewData.Model trước khi chuyển đến RenderViewToString. ví dụ

this.ViewData.Model = new OrderResultEmailViewModel(order);
string myString = RenderViewToString(this.ControllerContext, "~/Views/Order/OrderResultEmail.aspx", "~/Views/Shared/Site.Master", this.ViewData, this.TempData);

0

Để lặp lại từ một câu hỏi chưa biết, hãy xem MvcIntegrationTestFramework .

Nó giúp bạn tiết kiệm bằng cách viết người trợ giúp của riêng bạn để truyền phát kết quả và được chứng minh là hoạt động đủ tốt. Tôi cho rằng điều này sẽ nằm trong một dự án thử nghiệm và như một phần thưởng bạn sẽ có các khả năng thử nghiệm khác sau khi bạn có thiết lập này. Sự bận tâm chính có lẽ sẽ được sắp xếp ra khỏi chuỗi phụ thuộc.

 private static readonly string mvcAppPath = 
     Path.GetFullPath(AppDomain.CurrentDomain.BaseDirectory 
     + "\\..\\..\\..\\MyMvcApplication");
 private readonly AppHost appHost = new AppHost(mvcAppPath);

    [Test]
    public void Root_Url_Renders_Index_View()
    {
        appHost.SimulateBrowsingSession(browsingSession => {
            RequestResult result = browsingSession.ProcessRequest("");
            Assert.IsTrue(result.ResponseText.Contains("<!DOCTYPE html"));
        });
}

0

Đây là một lớp tôi đã viết để làm điều này cho ASP.NETCore RC2. Tôi sử dụng nó để tôi có thể tạo email html bằng cách sử dụng dao cạo.

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Routing;
using System.IO;
using System.Threading.Tasks;

namespace cloudscribe.Web.Common.Razor
{
    /// <summary>
    /// the goal of this class is to provide an easy way to produce an html string using 
    /// Razor templates and models, for use in generating html email.
    /// </summary>
    public class ViewRenderer
    {
        public ViewRenderer(
            ICompositeViewEngine viewEngine,
            ITempDataProvider tempDataProvider,
            IHttpContextAccessor contextAccesor)
        {
            this.viewEngine = viewEngine;
            this.tempDataProvider = tempDataProvider;
            this.contextAccesor = contextAccesor;
        }

        private ICompositeViewEngine viewEngine;
        private ITempDataProvider tempDataProvider;
        private IHttpContextAccessor contextAccesor;

        public async Task<string> RenderViewAsString<TModel>(string viewName, TModel model)
        {

            var viewData = new ViewDataDictionary<TModel>(
                        metadataProvider: new EmptyModelMetadataProvider(),
                        modelState: new ModelStateDictionary())
            {
                Model = model
            };

            var actionContext = new ActionContext(contextAccesor.HttpContext, new RouteData(), new ActionDescriptor());
            var tempData = new TempDataDictionary(contextAccesor.HttpContext, tempDataProvider);

            using (StringWriter output = new StringWriter())
            {

                ViewEngineResult viewResult = viewEngine.FindView(actionContext, viewName, true);

                ViewContext viewContext = new ViewContext(
                    actionContext,
                    viewResult.View,
                    viewData,
                    tempData,
                    output,
                    new HtmlHelperOptions()
                );

                await viewResult.View.RenderAsync(viewContext);

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

0

Tôi đã tìm thấy một cách tốt hơn để hiển thị trang xem dao cạo khi tôi gặp lỗi với các phương pháp ở trên, giải pháp này cho cả môi trường biểu mẫu web và môi trường mvc. Không có bộ điều khiển là cần thiết.

Dưới đây là ví dụ mã, trong ví dụ này tôi đã mô phỏng một hành động mvc với trình xử lý http async:

    /// <summary>
    /// Enables processing of HTTP Web requests asynchronously by a custom HttpHandler that implements the IHttpHandler interface.
    /// </summary>
    /// <param name="context">An HttpContext object that provides references to the intrinsic server objects.</param>
    /// <returns>The task to complete the http request.</returns>
    protected override async Task ProcessRequestAsync(HttpContext context)
    {
        if (this._view == null)
        {
            this.OnError(context, new FileNotFoundException("Can not find the mvc view file.".Localize()));
            return;
        }
        object model = await this.LoadModelAsync(context);
        WebPageBase page = WebPageBase.CreateInstanceFromVirtualPath(this._view.VirtualPath);
        using (StringWriter sw = new StringWriter())
        {
            page.ExecutePageHierarchy(new WebPageContext(new HttpContextWrapper(context), page, model), sw);
            await context.Response.Output.WriteAsync(sw.GetStringBuilder().ToString());
        }
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.