Neu in .NET 8.0 [19]: Razor-HTML-Rendering in beliebigen .NET-Anwendungen
Das HTML-Rendern mit Razor-Komponenten ist in .NET 8.0 auch außerhalb von Blazor-Anwendungen möglich, beispielsweise für HTML-formatierte E-Mails.
- Dr. Holger Schwichtenberg
Die Razor-Template-Syntax hat Microsoft schon im Jahr 2010 vorgestellt und in ASP.NET MVC Classic Version 3 am 13.11.2011eingeführt, siehe Blogeintrag von Scott Guthrie vom 3.7.2010. Sie wurde auch in ASP.NET Webpages verwendet und später in ASP.NET Core MVC und ASP.NET Core Razor Pages übernommen. In Blazor gibt es eine erweiterte Version mit einem vereinfachten Modell für wiederverwendbare Razor-Komponenten.
Das Rendern der in Blazor verwendeten Razor-Komponenten ist in .NET 8.0 auch außerhalb von Blazor-Anwendungen möglich. Somit steht die gleiche Syntax, die in Blazor für Web- und Hybridanwendungen zum Einsatz kommt, nun auch für HTML-Rendering für E-Mails im HTML-Format oder andere HTML-Einsatzgebiete zur Verfügung.
Dazu gibt es in .NET 8.0 die neue Klasse Microsoft.AspNetCore.Components.Web.HtmlRenderer
im NuGet-Paket Microsoft.AspNetCore.Components.Web
.
Für das folgende Beispiel gibt es zunächst drei Razor-Komponenten. EMailTemplate.razor
bindet Headline.razor
und Footer.razor
per Tags ein: <Headline>
und <Footer>
. Bei Headline wird ein Parameter ĂĽbergeben. Bei Footer kann man ein Razor-Fragment ĂĽbergeben.
Alle Styles sind im HTML-Dokument in <style>
-Tags enthalten. Externe Style-Sheet-Dateien wie EMailTemplate.razor.css werden nicht wie Blazor automatisch integriert, sondern mĂĽssen explizit per <link rel="stylesheet" type="text/css" href="EMailTemplate.razor.css">
referenziert werden. Das funktioniert gut beim Rendering ins Dateisystem, ist aber nicht möglich bei E-Mails.
Der Code fĂĽr EMailTemplate.razor sieht folgendermaĂźen aus:
<html>
<body>
<style>
body { font-family: Arial}
</style>
<Headline Text="Terminbestätigung"></Headline>
<p>Guten Tag @Name,</p>
<p>.NET 8.0 ist am <b>@Datum.ToLongDateString()</b> erschienen.</p>
@{
var url = "https://www.IT-Visions.de";
}
@* Einbinden einer weiteren Razor-Komponente mit Child Content *@
<Footer>
<p>
Ihr Team von<br />
<a href="@url">www.IT-Visions.de</a></p>
</Footer>
</body>
</html>
@code {
[Parameter]
public string Name { get; set; }
[Parameter]
public DateTime Datum { get; set; } = new(2023, 11, 14);
}
Dies ist der Code fĂĽr Headline.razor:
@* Razor Component mit einfachem Parameter *@
<style>
.headline {
color: white;
background-color: #12B4FF;
padding: 10px;
}
</style>
<h3 class="headline">@Text</h3>
@code {
[Parameter]
public string Text { get; set; }
}
Und im Folgenden ist der Code fĂĽr Footer.razor zu sehen:
@* Razor Component mit Template *@
<p>Mit freundlichen GrĂĽĂźen</p>
@ChildContent
@code
{
[Parameter]
public RenderFragment ChildContent { get; set; }
}
In der Online-Konferenz betterCode() .NET 9.0 am 19. November 2024 von iX und dpunkt.verlag werden .NET-Experten von www.IT-Visions.de den fertigen Stand von .NET 9.0 anhand von Praxisbeispielen präsentieren. Dazu zählen die Neuerungen bezüglich des .NET 9.0 SDK, C# 13.0, ASP.NET Core 9.0, Blazor 9.0, OR-Mapping mit Entity Framework Core 9.0, Windows Forms 9.0, WPF 9.0, WinUI, Cross-Plattform-Entwicklung mit .NET MAUI 9.0 und ein Ausblick auf .NET 10.0.
Der Ticketverkauf ist bereits gestartet: Vor Bekanntgabe des Programms sind vergünstigte Blind-Bird-Tickets erhältlich.
Der Code im folgenden Listing rendert in einer Konsolenanwendung die E-Mail. Das entstandene HTML-Dokument gibt er auf der Konsole aus, speichert ihn in einer Datei und verwendet ihn zum Versand einer E-Mail:
using System.Diagnostics;
using ITVisions;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
namespace NET8_Console;
class FCL_RazorRendering
{
public async Task Run()
{
CUI.H1(nameof(FCL_RazorRendering));
#region Vorbereiten des Renderns mit Razor Templates
IServiceCollection services = new ServiceCollection();
services.AddLogging((loggingBuilder) => loggingBuilder
.SetMinimumLevel(LogLevel.Trace)
.AddConsole()
);
IServiceProvider serviceProvider = services.BuildServiceProvider();
ILoggerFactory loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
#endregion
#region HTML Rendering using a Razor Component
// Klasse HtmlRenderer neu in .NET 8.0
await using var renderer = new HtmlRenderer(serviceProvider, loggerFactory);
var html = await renderer.Dispatcher.InvokeAsync(async () =>
{
// Parameter zusammenstellen
var name = "Dr. Holger Schwichtenberg";
CUI.Print("Parameter 'Name' = " + name);
var pdic = new Dictionary<string, object>() { { "Name", name } };
var pv = ParameterView.FromDictionary(pdic); // oder: var pv = ParameterView.Empty;
// Nun EMailTemplate.razor rendern
var output = await renderer.RenderComponentAsync<Razor_EMailTemplates.EMailTemplate>(pv);
return output.ToHtmlString();
});
#endregion
#region HTML anzeigen
CUI.H2("Gerendertes HTML");
CUI.PrintYellow(html);
#endregion
#region HTML speichern
var path = Path.GetTempFileName();
path = Path.ChangeExtension(path, ".html");
System.IO.File.AppendAllText(path, html);
// Start new Process to open the File in the default Browser
Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
#endregion
#region HTML-E-Mail senden
new ITVisions.Network.MailUtil().SendMail("absender@IT-Visions.de",
"empfänger@IT-Visions.de",
"Terminbestätigung .NET 8.0",
html, HTML: true);
#endregion
}
}
(rme)