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