Razor view Engine в Blazor (преобразование компонента Blazor в HTML-строку во время выполнения)

Я пытаюсь получить PDF-файл в серверной Blazor. Я использую DinkToPdf в качестве внешней библиотеки для преобразования строки HTML в pdf. Но у меня возникли проблемы с преобразованием компонента Blazor в HTML-строку.

Существует способ визуализации шаблонов Razor в строку с помощью Razor ViewEngine. Из этой сети http://fizzylogic.nl/2017/08/03/how-to-generate-pdf-documents-in-asp-net-core/

[HttpGet]
public async Task<IActionResult> CreatePDF()
{
    var globalSettings = new GlobalSettings
    {
        ColorMode = ColorMode.Color,
        Orientation = Orientation.Portrait,
        PaperSize = PaperKind.A4,
        Margins = new MarginSettings { Top = 10 },
        DocumentTitle = "PDF Report",
    };

    var objectSettings = new ObjectSettings
    {
        PagesCount = true,
        HtmlContent = "<h>Hello World</h>",
        WebSettings = { DefaultEncoding = "utf-8"},
        HeaderSettings = { FontName = "Arial", FontSize = 9, Right = "Page [page] of [toPage]", Line = true },
        FooterSettings = { FontName = "Arial", FontSize = 9, Line = true, Center = "Report Footer" }
    };

    var pdf = new HtmlToPdfDocument()
    {
        GlobalSettings = globalSettings,
        Objects = { objectSettings }
    };

    var file = _converter.Convert(pdf);
    return File(file,"application/pdf");
}

Мне нужно изменить ObjectSettings.HtmlContent, чтобы он был моей строкой html компонента Blazor.

3 ответа

Вы пытаетесь преобразовать контент, который может видеть пользователь? Если да, вы можете добавить@ref='ContentToRender' компоненту, который вы хотите визуализировать, Blazor назначит эту ссылку после того, как компонент будет визуализирован:

@inject IJSRuntime JSRuntime

<div @ref=ContentToRender>
  ... Your content here...
</div>

@code {
  ElementReference ContentToRender;

  protected async override Task OnAfterRenderAsync(bool firstRender) 
  {
    if (firstRender) 
    {
      string html = await JSRuntime.InvokeAsync<string>("BlazorUniversity.getInnerHTML", ContentToRender);
    }
  };
}

Где JS будет выглядеть примерно так

var BlazorUniversity = BlazorUniversity || {};
BlazorUniversity.getInnerHTML = function(element) {
  return element.innerHTML;
};

Не забудьте включить JS на главную страницу index.html или _Host.cshtml.

Дополнительные сведения см. В разделе " Передача ссылок на элементы HTML в университете Blazor".

Обратите внимание, что вы не сможете получить доступ к контенту, по крайней мере, после первого события рендеринга (firstRender == true).

Мне пришлось покопаться в исходном коде, и я обнаружил, что это работает для статического контента ( RenderMode.Static) (Я не тестировал это с тегами сценария, иерархиями макетов или вложенными компонентами).

В зависимости от того, где вы пытаетесь это сделать (например, в рамках запроса или фоновой задачи), вам нужно будет либо указать текущий HttpContext или создайте свой.

      public static async Task<string> RenderAsync<TComponent>(IHtmlHelper helper, HttpContext httpContext, object parameters)
{
  if (helper is IViewContextAware viewContextAware)
  {
    viewContextAware.Contextualize(new ViewContext()
    {
      HttpContext = httpContext
    }
  }

  var content = await helper.RenderComponentAsync<TComponent>(RenderMode.Static, parameters);
  var writer = new StringWriter();
  content.WriteTo(writer, HtmlEncoder.Default);
  return writer.ToString();
}

public static HttpContext CreateDefaultContext(IServiceProvider serviceProvider)
{
  return new DefaultHttpContext
  {
    RequestServices = serviceProvider,
    Request =
    {
      Scheme = "http",
      Host = new HostString("localhost"),
      PathBase = "/base",
      Path = "/path",
      QueryString = QueryString.FromUriComponent("?query=value")
    }
  }
}

CreateDefaultContextчастично основан на этом образце, найденном в тестах Microsoft

Sample.razor:

      <h3>@Data.Title</h3>

Hello, @Data.FirstName @Data.LastName!

@code {

  [Parameter]
  public Test Data { get; set; }

  public class Test
  {
    public string Title { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }
  }

}

Демо:

      var helper = ServiceProvider.GetService<IHtmlHelper>();
var context = CreateDefaultContext(ServiceProvider);
var html = await RenderAsync<Sample>(helper, context, new
{
  Data = new Sample.Test()
  {
    Title = "Stack Overflow Test",
    FirstName = "user",
    LastName = "489566"
  }
});

html значение:

      <h3>Stack Overflow Test</h3>

Hello, user 489566!

Это работает для меня:

...... HtmlContent = TemplateGenerator.GetHTMLString(),......

    public static string GetHTMLString()
    {
        IRaumNodeProvider RaumNodeProvider = new 
              RaumNodeProvider(Globals.Connectionstring);

        var reservierungen = RaumNodeProvider.GetReservierungen();

        var sb = new StringBuilder();
        sb.Append(@"
                    <html>
                        <head>
                        </head>
                        <body>
                            <div class='header'><h1>Reservierungsliste</h1></div>
                            <table align='center'>
                                <tr>
                                    <th>Id      </th>
                                    <th>Raum    </th>
                                    <th>Datum   </th>
                                    <th>Zeit    </th>
                                    <th>Beleger </th>
                                    <th>Belegung</th>
                                    <th>EmailMsg</th>
                                </tr>");

        foreach (var res in reservierungen)
        {
            sb.AppendFormat(@"<tr>
                                <td>{0}</td>
                                <td>{1}</td>
                                <td>{2}</td>
                                <td>{3}</td>
                                <td>{4}</td>
                                <td>{5}</td>
                                <td>{6}</td>
                              </tr>", 
                                res.Res_Id              
                              , res.RaumName                                  
                              , res.BelegungsDatumTxt   
                              , res.Zeit                
                              , res.Belegung_durch      
                              , res.Belegung            
                              , res.EmailMsg
                              );
        }

        sb.Append(@"
                            </table>
                        </body>
                    </html>");

        return sb.ToString();
    }
Другие вопросы по тегам