<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Rafael`s Blog]]></title><description><![CDATA[Privater Blog mit Fokus auf Technologie-Themen.]]></description><link>https://carnucci.de/</link><image><url>https://carnucci.de/favicon.png</url><title>Rafael`s Blog</title><link>https://carnucci.de/</link></image><generator>Ghost 5.81</generator><lastBuildDate>Fri, 12 Jun 2026 15:01:13 GMT</lastBuildDate><atom:link href="https://carnucci.de/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Angular Dev Webserver mit SSL unter Windows 11 betreiben]]></title><description><![CDATA[<p>In bestimmten Projekten ist es notwendig, auch in der lokalen Entwicklungsumgebung HTTPS zu verwenden, zum Beispiel, wenn das Angular-Frontend mit einem ASP.NET Core Backend kommuniziert, das HTTPS voraussetzt, oder wenn Funktionen wie Secure Cookies, OAuth2 oder CORS mit &quot;secure&quot;-Kontext getestet werden sollen.</p><p>Visual Studio erleichtert dies,</p>]]></description><link>https://carnucci.de/angular-ssl/</link><guid isPermaLink="false">66587549ba27a20001bac434</guid><category><![CDATA[Asp.Net Core]]></category><category><![CDATA[Angular]]></category><category><![CDATA[Programmierung]]></category><dc:creator><![CDATA[Rafael Carnucci]]></dc:creator><pubDate>Sun, 20 Apr 2025 20:15:27 GMT</pubDate><media:content url="https://carnucci.de/content/images/2025/04/b7a45822-695e-4a27-80b4-c20aefc13b71.png" medium="image"/><content:encoded><![CDATA[<img src="https://carnucci.de/content/images/2025/04/b7a45822-695e-4a27-80b4-c20aefc13b71.png" alt="Angular Dev Webserver mit SSL unter Windows 11 betreiben"><p>In bestimmten Projekten ist es notwendig, auch in der lokalen Entwicklungsumgebung HTTPS zu verwenden, zum Beispiel, wenn das Angular-Frontend mit einem ASP.NET Core Backend kommuniziert, das HTTPS voraussetzt, oder wenn Funktionen wie Secure Cookies, OAuth2 oder CORS mit &quot;secure&quot;-Kontext getestet werden sollen.</p><p>Visual Studio erleichtert dies, indem es beim ersten Start eines ASP.NET Core Projekts automatisch ein selbstsigniertes Entwicklungszertifikat erzeugt und es dem Zertifikatspeicher des aktuellen Benutzers als vertrauensw&#xFC;rdig hinzuf&#xFC;gt. Dieses Zertifikat l&#xE4;sst sich auch f&#xFC;r den Angular Development Server (<code>ng serve</code>) nutzen, um dort SSL zu aktivieren.</p><h2 id="voraussetzungen">Voraussetzungen</h2><ul><li>Windows 11</li><li>PowerShell 7 oder h&#xF6;her installiert</li><li>Ein ASP.NET Core Projekt wurde bereits mit Visual Studio gestartet (damit das Dev-Zertifikat erzeugt wurde)</li></ul><h2 id="schritt-1-entwicklungszertifikat-exportieren">Schritt 1: Entwicklungszertifikat exportieren</h2><p>Damit das Angular CLI das Zertifikat nutzen kann, muss das Zertifikat als <code>key.pem</code> und <code>cert.pem</code> exportiert werden. Dies geschieht am einfachsten per PowerShell:</p><h3 id="powershell-skript-exportiere-aspnet-core-development-zertifikat">PowerShell-Skript: Exportiere ASP.NET Core Development-Zertifikat</h3><pre><code class="language-Powershell">$ErrorActionPreference = &apos;Stop&apos;;

# Zielpfade
$exportPath = &apos;C:\DEIN-PROJEKLT\certificates&apos;;
$keyPath = Join-Path $exportPath &apos;key.pem&apos;;
$certPath = Join-Path $exportPath &apos;cert.pem&apos;;

Write-Host &apos;Entwicklungszertifikat ermitteln&apos;;

# Thumbprint des Zertifikats abrufen
# Es handelt sich dabei um einen Flie&#xDF;text
$certsCheckOutput = dotnet dev-certs https --check;

# Regex zum extrahieren des Fingerprint
$thumbrint = [regex] &apos;: ([\w]+) -&apos;;
$certificateIdMatch = $thumbrint.Matches($certsCheckOutput);


if($certificateIdMatch.Groups.Length -eq 0) {
    Write-Error &apos;Entwicklungszertifikat-Fingerprint konnte nicht ermittelt werden&apos;;
    return 1;
}

Write-Host &quot;Entwicklungszertifikat laden&quot;

# Id des Zertifikates
$certificateId = $certificateIdMatch.Groups[1];

Write-Host &quot;ID: $certificateId&quot;

# Zertifikat abrufen
$cert = Get-ChildItem -Path Cert:\CurrentUser\My |
    Where-Object { $_.HasPrivateKey -and $_.Thumbprint -eq $certificateId } |
    Sort-Object NotAfter -Descending |
    Select-Object -First 1

if(!$cert) {
    Write-Error &apos;Es wurde kein Entwicklungszertifikat gefunden f&#xFC;r $certificateId&apos;;
    return 1;
}

Write-Host &quot;Zertifikat gefunden: $($cert.Subject)&quot;

Write-Host &apos;Zertifikate erstellen&apos;

# Privaten Key lesen
$RSACng = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert);

# Zertifikate erstellen
$RSACng.ExportPkcs8PrivateKeyPem() | Set-Content -Path $keyPath -Encoding ascii
Write-Host &quot;Zertifikat $keyPath wurde erstellt&quot;

$cert.ExportCertificatePem() |  Set-Content -Path $certPath -Encoding ascii
Write-Host &quot;Zertifikat $certPath wurde erstellt&quot;</code></pre><h2 id="schritt-2-angular-dev-server-mit-ssl-starten">Schritt 2: Angular Dev Server mit SSL starten</h2><p>Der Angular Dev Server kann mit den Parametern <code>--ssl</code>, <code>--ssl-key</code> und <code>--ssl-cert</code> gestartet werden. </p><pre><code>ng serve  --ssl --ssl-key certificates/key.pem --ssl-cert certificates/cert.pem</code></pre><h2 id="faq">FAQ</h2><p><strong>Was passiert, wenn ich kein Zertifikat sehe?</strong><br>Starte ein beliebiges ASP.NET Core Projekt in Visual Studio, das HTTPS nutzt. Visual Studio erzeugt dann automatisch ein Entwicklungszertifikat.</p><p>Alternative kann der Befehl <code>dotnet dev-certs https --trust</code> ausgef&#xFC;hrt werden.</p>]]></content:encoded></item><item><title><![CDATA[.NET Core: Result-Pattern]]></title><description><![CDATA[<h1 id="einleitung">Einleitung</h1><p>In dem Artikel &quot;<a href="https://carnucci.de/asp-net-8-iexceptionhandler/" rel="noreferrer">ASP.NET Core 8: IExceptionHandler f&#xFC;r APIs</a>&quot; wurde die Fehlerbehandlung durch Exception Handling pr&#xE4;zisiert. Unter Entwicklern ist die Methode der Fehlerbehandlung ein intensiv diskutiertes Thema.</p><p>Es gibt drei Varianten der Fehlerbehandlung. Eine davon ist die R&#xFC;ckgabe von Null</p>]]></description><link>https://carnucci.de/net-core-result-pattern/</link><guid isPermaLink="false">662e2ac22dd8940001f86f38</guid><category><![CDATA[C#]]></category><category><![CDATA[Dotnet]]></category><category><![CDATA[Programmierung]]></category><dc:creator><![CDATA[Rafael Carnucci]]></dc:creator><pubDate>Sun, 28 Apr 2024 12:20:15 GMT</pubDate><media:content url="https://carnucci.de/content/images/2024/04/pexels-cottonbro-5244340-1.jpg" medium="image"/><content:encoded><![CDATA[<h1 id="einleitung">Einleitung</h1><img src="https://carnucci.de/content/images/2024/04/pexels-cottonbro-5244340-1.jpg" alt=".NET Core: Result-Pattern"><p>In dem Artikel &quot;<a href="https://carnucci.de/asp-net-8-iexceptionhandler/" rel="noreferrer">ASP.NET Core 8: IExceptionHandler f&#xFC;r APIs</a>&quot; wurde die Fehlerbehandlung durch Exception Handling pr&#xE4;zisiert. Unter Entwicklern ist die Methode der Fehlerbehandlung ein intensiv diskutiertes Thema.</p><p>Es gibt drei Varianten der Fehlerbehandlung. Eine davon ist die R&#xFC;ckgabe von Null bei einem Funktionsaufruf, was nur angewendet werden sollte, wenn der Fehler klar definiert ist, wie zum Beispiel beim Laden eines Datensatzes aus der Datenbank (vorhanden/nicht vorhanden).</p><pre><code>public Task&lt;object?&gt; GetCompanyAsync(Guid id) {
  return Repository.GetOrDefaultAsync(id);
}</code></pre><p>Die zweite Methode ist das Ausl&#xF6;sen von Ausnahmen (Exceptions). Auf vielen Plattformen wird davon abgeraten, Exceptions zu verwenden, insbesondere wenn sie dazu dienen, den Programmfluss zu steuern. </p><p>Zum Beispiel wird anstelle der Verwendung von <code>File.Exists</code> versucht, die Datei zu &#xF6;ffnen, und im Falle einer Ausnahme wird der Pfad zur Erstellung der Datei verfolgt. </p><p>Ein Punkt, den ich noch nicht gepr&#xFC;ft habe, ist die Leistung. Es wird behauptet, dass das Ausl&#xF6;sen von Ausnahmen zeitaufwendig ist.</p><pre><code>public void CancleTicket(Ticket ticket) {
  if(ticket.state != 0) {
    throw new Exception(&quot;Ticket muss zum stornieren ge&#xF6;ffnet sein.&quot;);
  }
}</code></pre><p>Eine dritte Methode zur Fehlerbehandlung ist das Result-Pattern.</p><h1 id="result-pattern">Result-Pattern</h1><p>Das Result-Pattern gibt den Fehler als R&#xFC;ckgabewert weiter. Dazu sind zun&#xE4;chst grundlegende Klassen erforderlich.</p><pre><code class="language-c#">public sealed record Error(string? Code, string Description)
{
  public static Error NotFound(object id) =&gt; new Error(&quot;404&quot;, $&quot;Entity with Id {id} not found&quot;);
}

public class Result
{
    protected Result(bool isSuccess, Error? error)
    {
        if (isSuccess ^ error == null)
        {
            throw new ArgumentException(&quot;Invalid error&quot;, nameof(error));
        }

        IsSuccess = isSuccess;
        Error = error;
    }

    public bool IsSuccess { get; }

    public bool IsFailure =&gt; !IsSuccess;

    public Error? Error { get; }

    public static Result Success() =&gt; new(true, null);

    public static Result Failure(Error error) =&gt; new(false, error);
}

public class Result&lt;TValue&gt; : Result
{
    protected Result(TValue value, bool isSuccess, Error? error) : base(isSuccess, error)
    {
        Value = value;
    }

    public TValue Value { get; }

    public static Result Success(TValue result) =&gt; new Result&lt;TValue&gt;(result, true, null);

    public static Result Failure(TValue result, Error error) =&gt; new Result&lt;TValue&gt;(result, false, error);
}</code></pre><p>Anschlie&#xDF;end k&#xF6;nnen die zuvor erw&#xE4;hnten Klassen eingesetzt werden.</p><pre><code>public Result CancleTicket(Ticket ticket) {
  if(ticket.state != 0) {
    return Result.Failure(new Error(null, &quot;Ticket muss zum stornieren ge&#xF6;ffnet sein.&quot;));
  }
}</code></pre><p>F&#xFC;r Asp.Net Core muss die genannte Implementierung angepasst werden. Bei Minimal APIs k&#xF6;nnen Werte durch statische Methoden in <code>Results</code> (<code>IResult</code>) zur&#xFC;ckgegeben werden, wodurch ein entsprechender HTTP-Statuscode generiert wird. Bei einer eigenen Implementierung m&#xFC;ssen die Statuscodes manuell zugeordnet werden.</p><h1 id="bestehende-bibliotheken">Bestehende Bibliotheken</h1><p>Bei einfachen Implementierungsaufgaben, die nur wenige Stunden in Anspruch nehmen, bevorzuge ich es, diese selbst durchzuf&#xFC;hren. Die Verwendung externer Bibliotheken kann das Risiko von Angriffen und Abh&#xE4;ngigkeiten erh&#xF6;hen. Dennoch m&#xF6;chte ich hier zwei Bibliotheken erw&#xE4;hnen.</p><ul><li><a href="https://github.com/AKlaus/DomainResult?ref=carnucci.de"><strong>DomainResult</strong></a></li><li><a href="https://github.com/altmann/FluentResults?ref=carnucci.de"><strong>FluentResults</strong></a></li></ul>]]></content:encoded></item><item><title><![CDATA[ASP.NET Core 8: IExceptionHandler für APIs]]></title><description><![CDATA[Optimierung der Fehlerbehandlung in ASP.NET Core 8 durch die Verwendung des neuen IExceptionHandler.]]></description><link>https://carnucci.de/asp-net-8-iexceptionhandler/</link><guid isPermaLink="false">662cc1552dd8940001f86d7b</guid><category><![CDATA[Programmierung]]></category><category><![CDATA[C#]]></category><category><![CDATA[Dotnet]]></category><category><![CDATA[Asp.Net Core]]></category><dc:creator><![CDATA[Rafael Carnucci]]></dc:creator><pubDate>Sun, 28 Apr 2024 10:42:24 GMT</pubDate><media:content url="https://carnucci.de/content/images/2024/04/pexels-cottonbro-5244340.jpg" medium="image"/><content:encoded><![CDATA[<h1 id="einleitung">Einleitung</h1><img src="https://carnucci.de/content/images/2024/04/pexels-cottonbro-5244340.jpg" alt="ASP.NET Core 8: IExceptionHandler f&#xFC;r APIs"><p>Seit der ersten Version von .NET Core bin ich dabei und habe die Verbesserungen w&#xE4;hrend der Entwicklung erlebt.</p><p>Derzeit plane ich eine neue Basis f&#xFC;r mein System und &#xFC;berpr&#xFC;fe daher regelm&#xE4;&#xDF;ig verschiedene Teilbereiche und deren L&#xF6;sungen in den neueren .NET Core-Versionen. Eine dieser Verbesserungen ist das Exception Handling.</p><p>In diesem Beitrag unterscheide ich zwei Arten von Fehlern: Systemfehler und Logikfehler. Systemfehler umfassen unerreichbare Systeme wie Datenbanken, Caches oder externe Dienste sowie Programmierfehler. Logikfehler hingegen stehen im Zusammenhang mit der Gesch&#xE4;ftslogik. Zum Beispiel, wenn ein Benutzer versucht, ein bereits storniertes Ticket zu stornieren, ohne die n&#xF6;tigen Berechtigungen zu haben.</p><p>Bei Systemfehlern sollten keine Details preisgegeben werden. Ist beispielsweise der SQL Server nicht erreichbar, sollte der Nutzer h&#xF6;chstens erfahren, dass es ein Datenbankproblem gibt, ohne weitere Einzelheiten. Die Weitergabe von Fehlermeldungen k&#xF6;nnte sonst die Adresse des SQL-Servers, den Datenbanknamen und m&#xF6;glicherweise den Benutzernamen offenlegen, was ein Sicherheitsrisiko darstellt. Diese Daten m&#xFC;ssen daher bereinigt werden.</p><p>Bei Logikfehlern sollte der Benutzer hingegen mehr Informationen erhalten. Wenn ein Benutzer versucht, ein storniertes Ticket zu stornieren, sollte ihm mitgeteilt werden, dass dies nicht m&#xF6;glich ist. Im Idealfall sollte auch die fehlende Berechtigung angezeigt werden.</p><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">Die Frage, ob Logikfehler durch Exceptions oder <a href="https://carnucci.de/net-core-result-pattern/" rel="noreferrer">Result Pattern</a> behandelt werden sollten, ist eine separate Diskussion und wird daher hier nicht weitergef&#xFC;hrt <a href="https://github.com/dotnet/aspnetcore/issues/46280?ref=carnucci.de#issuecomment-1527898867" rel="noreferrer"><sup style="white-space: pre-wrap;">1</sup></a>.</div></div><h1 id="umsetzung">Umsetzung</h1><div class="kg-card kg-callout-card kg-callout-card-yellow"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text">Ich werde nur Code-Fragmente vorstellen, keine kompletten Klassen oder Funktionen. Sie sollen ausschlie&#xDF;lich als Inspiration dienen und sind f&#xFC;r erfahrene Entwickler konzipiert. Zudem bezieht sich alles auf .Net Core 8.</div></div><p>Das zuvor erw&#xE4;hnte anzeigen von Server-Details, einschlie&#xDF;lich der SQL-Verbindungsdaten, m&#xFC;ssen etwas pr&#xE4;zisiert werden. Asp.Net Core unterscheidet zwischen drei Umgebungen: <code>Development</code>, <code>Stage</code> und <code>Production</code>. Das Verhalten der Anwendung variiert je nach Umgebung. Ist die Umgebung auf <code>Production</code> eingestellt, werden keinerlei Informationen angezeigt, nicht einmal der Text der Ausnahme.</p><h2 id="vor-net-core-8">Vor .Net Core 8</h2><p>In ASP.NET Core vor Version 8 konnten Fehler mittels Middleware abgefangen werden. Dabei wurde eine Middleware mit einem <code>Try-Catch</code>-Block implementiert, wobei die Fehlerbehandlung im <code>Catch</code>-Teil erfolgte.</p><pre><code class="language-C#">public class ExceptionHandlingMiddleware(RequestDelegate next)
{
    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await next(context);
        }
        catch (Exception ex)
        {
            ILogger&lt;ExceptionHandlingMiddleware&gt; logger = context.RequestServices.GetRequiredService&lt;ILogger&lt;ExceptionHandlingMiddleware&gt;&gt;();

            logger.LogError(ex, &quot;An unexpected error occurred&quot;);

            ProblemDetails problemDetails = new()
            {
                Status = StatusCodes.Status500InternalServerError,
                Type = ex.GetType().Name,
                Title = &quot;An unexpected error occurred&quot;,
                Detail = ex.Message,
                Instance = $&quot;{context.Request.Method} {context.Request.Path}&quot;
            };

            context.Response.StatusCode =
                StatusCodes.Status500InternalServerError;

            await context.Response.WriteAsJsonAsync(problemDetails);
        }
    }
}</code></pre><pre><code class="language-c#">app.UseMiddleware&lt;ExceptionHandlingMiddleware&gt;();</code></pre><h2 id="iexceptionhandler">IExceptionHandler</h2><p>In Asp.Net Core 8 wurde mit dem <a href="https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-8.0&amp;ref=carnucci.de#iexceptionhandler" rel="noreferrer"><code>IExceptionHandler</code></a> eine neue Methode zur Fehlerbehandlung eingef&#xFC;hrt.</p><figure class="kg-card kg-code-card"><pre><code class="language-c#">public interface IExceptionHandler
{
    ValueTask&lt;bool&gt; TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken);
}</code></pre><figcaption><p><span style="white-space: pre-wrap;">IExceptionHandler Interface</span></p></figcaption></figure><pre><code class="language-C#">public class DefaultExceptionHandler(ILogger&lt;DefaultExceptionHandler&gt; logger) : IExceptionHandler
{
    public async ValueTask&lt;bool&gt; TryHandleAsync(HttpContext context, Exception exception, CancellationToken cancellationToken)
    {
        logger.LogError(exception, &quot;An unexpected error occurred&quot;);

        await context.Response.WriteAsJsonAsync(new ProblemDetails
        {
            Status = StatusCodes.Status500InternalServerError,
            Type = exception.GetType().Name,
            Title = &quot;An unexpected error occurred&quot;,
            Detail = exception.Message,
            Instance = $&quot;{context.Request.Method} {context.Request.Path}&quot;
        });

        return true;
    }
}</code></pre><pre><code>  builder.Services.AddExceptionHandler&lt;DefaultExceptionHandler&gt;();
  builder.Services.AddProblemDetails();</code></pre><pre><code>   app.UseExceptionHandler();</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://carnucci.de/content/images/2024/04/image-3.png" class="kg-image" alt="ASP.NET Core 8: IExceptionHandler f&#xFC;r APIs" loading="lazy" width="464" height="231"><figcaption><span style="white-space: pre-wrap;">Ergebnis</span></figcaption></figure><h3 id="verkettung-chaining">Verkettung (Chaining)</h3><p><code>ExceptionHandler</code> k&#xF6;nnen miteinander verkettet werden, indem der R&#xFC;ckgabewert der Funktion genutzt wird: <code>true</code> bedeutet, dass der Fehler behandelt wurde, und <code>false</code>, dass der Fehler nicht behandelt wurde und ein anderer <code>ExceptionHandler</code> eingreifen muss.</p><p>Dies bietet den Vorteil, dass Bibliotheken eigene <code>ExceptionHandler</code> f&#xFC;r ihre spezifischen Exceptions bereitstellen k&#xF6;nnen.</p>]]></content:encoded></item><item><title><![CDATA[DNS: HTTPS Umleitung]]></title><description><![CDATA[Neuer DNS-Record HTTPS ermöglicht direkte HTTPS Verbindung zur Website ohne serverseitige Umleitung von HTTP auf HTTPS. ]]></description><link>https://carnucci.de/dns-https-umleitung/</link><guid isPermaLink="false">6629774e2dd8940001f86d6f</guid><category><![CDATA[DNS]]></category><category><![CDATA[Administration]]></category><category><![CDATA[News]]></category><dc:creator><![CDATA[Rafael Carnucci]]></dc:creator><pubDate>Sat, 27 Apr 2024 16:49:54 GMT</pubDate><media:content url="https://carnucci.de/content/images/2024/04/pexels-brett-sayles-2881232.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://carnucci.de/content/images/2024/04/pexels-brett-sayles-2881232.jpg" alt="DNS: HTTPS Umleitung"><p>Es kann vorkommen, dass neue n&#xFC;tzliche Funktionen auftauchen und einem unbemerkt bleiben. In diesem Fall bin ich k&#xFC;rzlich auf den DNS-Record HTTPS gesto&#xDF;en, der in <a href="https://datatracker.ietf.org/doc/rfc9460/?ref=carnucci.de" rel="noreferrer">RFC9460</a> beschrieben wird.</p><p>Jeder Webentwickler kennt das leidige Thema der Umleitung von HTTP auf HTTPS. Wenn ein Besucher die Domain eingibt, wie zum Beispiel carnucci.de, wird zuerst die Webseite &#xFC;ber HTTP aufgerufen. Um auf HTTPS umzuleiten, muss der Webserver oder Proxy entsprechend konfiguriert sein. Das f&#xFC;hrt zu unn&#xF6;tigem Traffic und Wartezeit sowie einer Verschwendung von Ressourcen. Fr&#xFC;her wurde dieses Problem mit Add-ons in den Browsern gel&#xF6;st. Doch dazu musste jedes Add-on erst installiert werden, was die Angriffsfl&#xE4;che erh&#xF6;ht.</p><p>Nun kommt der neue DNS-Record HTTPS ins Spiel. Mit diesem Record kann angegeben werden, dass die Webseite &#xFC;ber HTTPS erreichbar ist. Der Browser fragt den Record ab und verbindet sich direkt &#xFC;ber HTTPS mit der Webseite. Die Umleitung von HTTP auf HTTPS auf dem Webserver wird dadurch &#xFC;berfl&#xFC;ssig. Allerdings sollte man nach dem Eintrag des HTTPS-Records die Konfiguration nicht einfach l&#xF6;schen. Es kann noch einige Zeit dauern, bis alle Besucher einen Browser verwenden, der den HTTPS-Record unterst&#xFC;tzt.</p><p>Die Frage ist nun, welche DNS-Server den neuen Record unterst&#xFC;tzen. Es d&#xFC;rfte nur eine Frage der Zeit sein, bis alle Server den Eintrag unterst&#xFC;tzen. <a href="https://blog.cloudflare.com/speeding-up-https-and-http-3-negotiation-with-dns?ref=carnucci.de" rel="noreferrer">Cloudflare</a> setzt den Eintrag automatisch, sobald HTTP/2 und HTTP/3 f&#xFC;r eine Zone aktiviert sind. Zu Windows Server habe ich leider keine Informationen gefunden, aber ich vermute, dass er erst in einer neueren Version unterst&#xFC;tzt wird.</p>]]></content:encoded></item><item><title><![CDATA[ML.NET: Named-entity recognition (NER) mit C# ausprobiert]]></title><description><![CDATA[<div class="kg-card kg-callout-card kg-callout-card-red"><div class="kg-callout-text">Wenn Sie diese Seite aufgrund von Problemen mit ML.NET und NER besuchen, muss ich Sie leider entt&#xE4;uschen - dieser Artikel bietet keine L&#xF6;sungen. Auch ich bin auf Probleme gesto&#xDF;en und konnte diese bisher nicht l&#xF6;sen.</div></div><h2 id="einleitung">Einleitung</h2><p>Im Rahmen meiner Seminararbeit &quot;</p>]]></description><link>https://carnucci.de/ml-net-ner/</link><guid isPermaLink="false">662cf92a2dd8940001f86d7f</guid><category><![CDATA[ML.NET]]></category><category><![CDATA[C#]]></category><category><![CDATA[KI]]></category><category><![CDATA[Programmierung]]></category><dc:creator><![CDATA[Rafael Carnucci]]></dc:creator><pubDate>Sat, 27 Apr 2024 15:33:06 GMT</pubDate><media:content url="https://carnucci.de/content/images/2024/04/pexels-pixabay-247819.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card kg-callout-card kg-callout-card-red"><div class="kg-callout-text">Wenn Sie diese Seite aufgrund von Problemen mit ML.NET und NER besuchen, muss ich Sie leider entt&#xE4;uschen - dieser Artikel bietet keine L&#xF6;sungen. Auch ich bin auf Probleme gesto&#xDF;en und konnte diese bisher nicht l&#xF6;sen.</div></div><h2 id="einleitung">Einleitung</h2><img src="https://carnucci.de/content/images/2024/04/pexels-pixabay-247819.jpg" alt="ML.NET: Named-entity recognition (NER) mit C# ausprobiert"><p>Im Rahmen meiner Seminararbeit &quot;KI in der Pflege&quot; f&#xFC;r meinen Masterstudiengang in Wirtschaftsinformatik habe ich erneut mit ML.NET gearbeitet. Named Entity Recognition (NER) ist eine Komponente der nat&#xFC;rlichen Sprachverarbeitung (NLP), die vordefinierte Objekte oder Schl&#xFC;sselw&#xF6;rter in einem Text identifizieren kann. Diese Tokens umfassen Personennamen, Organisationen, Orte, medizinische Codes, Zeitangaben, Mengenangaben, Geldwerte und vieles mehr. Kurz gesagt erm&#xF6;glicht NER die Extraktion von Informationen aus einem Text, was insbesondere dann n&#xFC;tzlich ist, wenn Personen Freitexte eingeben und bestimmte Informationen f&#xFC;r spezifische Zwecke ben&#xF6;tigt werden.</p><p>Leider sind viele Anleitungen zur Entwicklung von KI-Anwendungen auf Python ausgerichtet. Obwohl PyTorch und TensorFlow leistungsstarke Tools und Frameworks f&#xFC;r Python bieten, m&#xF6;chte Microsoft mit ML.NET .NET-Entwicklern die M&#xF6;glichkeit geben, KI-Anwendungen zu entwickeln und dabei im gleichen &#xD6;kosystem zu bleiben. Auf diese Weise kann die KI in C# trainiert und unter anderem in ASP.NET Core verwendet werden.</p><p>Durch AutoML und das Model Builder UI wird die Entwicklung von KI-Modellen vereinfacht. Es stehen verschiedene Algorithmen und Einstellungen zur Verf&#xFC;gung. AutoML sucht automatisch den besten Algorithmus f&#xFC;r eine spezifische Aufgabe. Der Model Builder stellt eine grafische Benutzeroberfl&#xE4;che (GUI) in Visual Studio bereit, um eine KI zu trainieren. Dort kann die Art der KI (Klassifizierung, Regression, Objekterkennung, NER usw.) ausgew&#xE4;hlt werden, und anschlie&#xDF;end k&#xF6;nnen die Datenquelle und die Trainingseinstellungen festgelegt werden.</p><h2 id="anwendungsszenario">Anwendungsszenario</h2><p><br>In unserem IT-Systemhaus in Dortmund ist ein Hauptbestandteil meiner Arbeit die Programmierung eines Ticketsystems. Unser Ziel ist es, die Probleme unserer Kunden so schnell wie m&#xF6;glich zu l&#xF6;sen. Um eine effiziente Organisation zu gew&#xE4;hrleisten, erfassen wir alle Vorf&#xE4;lle in einem Ticketsystem. Kunden haben die M&#xF6;glichkeit, eigene Tickets zu erstellen oder uns per E-Mail zu kontaktieren.</p><p>Die Nutzung von Named Entity Recognition (NER) k&#xF6;nnte besonders bei der Verarbeitung von E-Mails von Vorteil sein. Durch NER k&#xF6;nnten relevante Informationen wie Ger&#xE4;t, Ansprechpartner und Standort aus den E-Mails extrahiert werden, um daraus automatisch ein entsprechendes Ticket anzulegen.</p><h2 id="ner">NER</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://carnucci.de/content/images/2024/04/1_8LOMipM-fmszClg-AwATkQ.webp" class="kg-image" alt="ML.NET: Named-entity recognition (NER) mit C# ausprobiert" loading="lazy" width="1200" height="595" srcset="https://carnucci.de/content/images/size/w600/2024/04/1_8LOMipM-fmszClg-AwATkQ.webp 600w, https://carnucci.de/content/images/size/w1000/2024/04/1_8LOMipM-fmszClg-AwATkQ.webp 1000w, https://carnucci.de/content/images/2024/04/1_8LOMipM-fmszClg-AwATkQ.webp 1200w" sizes="(min-width: 720px) 720px"><figcaption><span style="white-space: pre-wrap;">Quelle: </span><a href="https://towardsdatascience.com/named-entity-recognition-ner-meeting-industrys-requirement-by-applying-state-of-the-art-deep-698d2b3b4ede?ref=carnucci.de"><span style="white-space: pre-wrap;">https://towardsdatascience.com/named-entity-recognition-ner-meeting-industrys-requirement-by-applying-state-of-the-art-deep-698d2b3b4ede</span></a></figcaption></figure><p>Es gibt leider kaum Anleitungen f&#xFC;r NER in ML.NET. Auf der Microsoft-Dokumentationsseite wird lediglich knapp der Aufbau der ben&#xF6;tigten Daten beschrieben, ansonsten finde ich dazu nichts.</p><p>Bei mir war der mitgelieferte ML.NET Model Builder nicht auf dem neuesten Stand, daher musste ich die aktuellste Version von der <a href="https://dotnet.microsoft.com/en-us/apps/machinelearning-ai/ml-dotnet/model-builder?ref=carnucci.de" rel="noreferrer">Website</a> herunterladen. </p><p>Anschlie&#xDF;end konnte ich NER (Szenario) zum Trainieren ausw&#xE4;hlen. Die Bedienung des Fensters wird ebenfalls <a href="https://dotnet.microsoft.com/en-us/apps/machinelearning-ai/ml-dotnet/model-builder?ref=carnucci.de" rel="noreferrer">dort</a> beschrieben.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://carnucci.de/content/images/2024/04/image-2.png" class="kg-image" alt="ML.NET: Named-entity recognition (NER) mit C# ausprobiert" loading="lazy" width="348" height="414"><figcaption><span style="white-space: pre-wrap;">NER im Model Builder ausw&#xE4;hlen</span></figcaption></figure><p>Nachdem NER ausgew&#xE4;hlt wurde, m&#xFC;ssen zwei Dateien angegeben werden: die Entity Key Map und die Trainingsdaten. </p><p>Die Entity Key Map ist eine Liste mit den Objekten/Labels.</p><pre><code class="language-txt">Device
Person
Priority</code></pre><p>Bei den Trainingsdaten handelt es sich um eine Liste von S&#xE4;tzen und den oben genannten Objekten. Die erste Spalte repr&#xE4;sentiert den Satz, w&#xE4;hrend die anderen Spalten die jeweiligen Objekte enthalten. Die Spalten sind durch Tabs getrennt. Ein vollst&#xE4;ndiges Beispiel kann aus dem offiziellen Repository von ML.NET auf <a href="https://github.com/michaelgsharp/machinelearning/blob/main/test/data/ner-conll2012_english_v4_train.txt?ref=carnucci.de" rel="noreferrer">GitHub</a> entnommen werden.</p><pre><code class="language-txt">Joseph hat Probleme mit dem Ger&#xE4;t dc-de-un-66. Die Anmeldung ist nicht mehr m&#xF6;glich. Es ist wichtig.	Person	0	0	0	0	0	0	Device	0	0	0	0	0	0	0	0	Priority
Chantal hat Probleme mit dem Ger&#xE4;t adfs-us-un-34. Die Anmeldung ist nicht mehr m&#xF6;glich. Es ist unwichtig.	Person	0	0	0	0	0	0	Device	0	0	0	0	0	0	0	0	Priority</code></pre><p>Zuerst habe ich die Daten in Excel erstellt und als TXT-Datei mit Tab-Abst&#xE4;nden gespeichert. Jedoch konnte der Model Builder die Datei nicht einlesen. Nachdem ich die Daten anschlie&#xDF;end in Notepad erstellt habe, konnte sie erfolgreich eingelesen werden. Wenn Umlaute verwendet werden, muss die Datei als UTF-8 gespeichert sein.</p><p>In der Vorschauversion von ML.NET habe ich gesehen, dass auch das Zuweisen eines Labels zu einer Wortgruppe gel&#xF6;st wurde. Eine Wortgruppe k&#xF6;nnte beispielsweise &quot;Max Mustermann&quot; sein. Dabei handelt es sich um eine Person und der Name besteht aus zwei W&#xF6;rtern. In der Entity Key Map werden &quot;B_Person&quot; und &quot;Person&quot; hinzugef&#xFC;gt. Im Entity Key Map erh&#xE4;lt das erste Wort das Label &quot;B_Person&quot; und alle darauf folgenden W&#xF6;rter, die zum selben Label geh&#xF6;ren, das Label &quot;Person&quot;.</p><h2 id="fazit">Fazit</h2><p>Bisher hatte ich immer gute Erfahrungen mit ML.NET und dem Model Builder gemacht, abgesehen von einigen kleineren Fehlern. Diesmal war es jedoch anders. Trotz mehrerer Versuche konnte ich kein positives Ergebnis erzielen. Ich habe es sowohl mit 20.000 generierten Zufallss&#xE4;tzen als auch mit den Test-Trainingsdaten von GitHub versucht. Leider ohne Erfolg.</p><figure class="kg-card kg-image-card"><img src="https://carnucci.de/content/images/2024/04/image-1.png" class="kg-image" alt="ML.NET: Named-entity recognition (NER) mit C# ausprobiert" loading="lazy" width="1239" height="298" srcset="https://carnucci.de/content/images/size/w600/2024/04/image-1.png 600w, https://carnucci.de/content/images/size/w1000/2024/04/image-1.png 1000w, https://carnucci.de/content/images/2024/04/image-1.png 1239w" sizes="(min-width: 720px) 720px"></figure><p><br>Auf dem Bild ist deutlich zu erkennen, dass das Label falsch zugewiesen wird und das Label &quot;Priorit&#xE4;t&quot; &#xFC;berhaupt nicht erkannt wird. Interessant ist, dass &quot;Chantal&quot; erkannt wird, aber &quot;hat&quot; das Label &quot;Person&quot; erh&#xE4;lt. Zun&#xE4;chst dachte ich, dass es sich um einen Anzeigefehler im Model Builder handelt, aber das gleiche Ergebnis erhielt ich auch im Programmcode.</p><p>Meine Vermutung ist, dass das Tool sich noch in der Beta-Phase befindet und daher noch nicht einwandfrei funktioniert. Zudem wird nach meinen Informationen ein vortrainiertes Modell (BERT) verwendet. Es ist wahrscheinlich darauf ausgelegt, eher f&#xFC;r die englische Sprache als f&#xFC;r Deutsch zu funktionieren.</p><p>Ein alternativer Ansatz k&#xF6;nnte darin bestehen, den NerTrainer direkt zu verwenden, ohne den Model Builder einzubeziehen. M&#xF6;glicherweise liegt der Fehler dort und nicht am Algorithmus.</p>]]></content:encoded></item><item><title><![CDATA[C# Assembly ohne expliziten Aufruf initialisieren]]></title><description><![CDATA[In bestimmten Situationen ist es notwendig, eine Assembly zu initialisieren. Beispielsweise, um statische Werte zuzuweisen.]]></description><link>https://carnucci.de/csharp-moduleinitializer/</link><guid isPermaLink="false">66277f6a2dd8940001f86d02</guid><category><![CDATA[C#]]></category><category><![CDATA[Programmierung]]></category><dc:creator><![CDATA[Rafael Carnucci]]></dc:creator><pubDate>Wed, 24 Apr 2024 21:02:32 GMT</pubDate><media:content url="https://carnucci.de/content/images/2024/04/pexels-brettjordan-10394994.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://carnucci.de/content/images/2024/04/pexels-brettjordan-10394994.jpg" alt="C# Assembly ohne expliziten Aufruf initialisieren"><p>In bestimmten Situationen ist es notwendig, eine Assembly zu initialisieren. Beispielsweise, um statische Werte zuzuweisen, &#xDC;berpr&#xFC;fungen durchzuf&#xFC;hren oder Schriftarten zu laden. Ein Beispiel w&#xE4;re der Aufruf von&#xA0;<code>BsonClassMap.RegisterClassMap</code>&#xA0;aus dem MongoDB SDK oder das Setzen des Werts f&#xFC;r&#xA0;<code>QuestPDF.Settings.License</code>&#xA0;in QuestPDF.&#xA0;Um diese Initialisierung automatisch durchzuf&#xFC;hren, kann das Attribut&#xA0;<code>ModuleInitializer</code>&#xA0;verwendet werden. Dieses Attribut kennzeichnet Methoden, die vor jedem anderen Code (z. B. Typinitialisierer oder statische Konstruktoren) in der gesamten Assembly ausgef&#xFC;hrt werden. Es wurde mit C#9 eingef&#xFC;hrt. Die Anforderungen an eine solche Initialisierungsmethode sind<a href="https://learn.microsoft.com/de-de/dotnet/csharp/language-reference/proposals/csharp-9.0/module-initializers?ref=carnucci.de" rel="noreferrer"><sup>1</sup></a>:</p><ul><li>Sie muss&#xA0;<strong>statisch</strong>&#xA0;sein.</li><li>Sie darf&#xA0;<strong>keine Parameter</strong>&#xA0;haben.</li><li>Sie muss&#xA0;<strong>void</strong>&#xA0;zur&#xFC;ckgeben.</li><li>Sie darf&#xA0;<strong>nicht generisch</strong>&#xA0;sein.</li><li>Sie darf&#xA0;<strong>nicht in einer generischen Klasse</strong>&#xA0;enthalten sein.</li><li>Sie muss aus der enthaltenden Assembly&#xA0;<strong>zug&#xE4;nglich</strong>&#xA0;sein (d. h. die Methode und ihre enthaltende Klasse m&#xFC;ssen&#xA0;<strong>internal</strong>&#xA0;oder&#xA0;<strong>public</strong>&#xA0;sein).</li></ul><p>Das Attribut&#xA0;<code>ModuleInitializer</code>&#xA0;erm&#xF6;glicht es somit, Initialisierungsmethoden automatisch aufzurufen, ohne dass ein expliziter Aufruf erforderlich ist.</p><pre><code class="language-C#">using System.Runtime.CompilerServices;
class Init
{
    [ModuleInitializer]
    internal static void Initialisierung()
    {
        // ...
    }
}</code></pre><h2 id="nachteile">Nachteile</h2><p>Die Verwendung von <code>ModuleInitializer</code> in C# bietet zwar Vorteile, aber es gibt auch einige Nachteile.</p><ol><li><strong>Nachvollziehbarkeit geht verloren</strong>:<ul><li>Bei <code>ModuleInitializer</code> wird die Assembly initialisiert ohne direkten Aufruf,  andere Entwickler k&#xF6;nnen dies nicht direkt einsehen und somit &#xFC;bersehen.</li><li>Dies kann die Wartbarkeit und das Debugging erschweren, da es keine klare Stelle im Code gibt, an der die Initialisierung stattfindet.</li><li>Andere Entwickler k&#xF6;nnten Schwierigkeiten haben, den Zusammenhang zwischen der automatischen Initialisierung und bestimmten Funktionalit&#xE4;ten zu erkennen.</li></ul></li><li><strong>Keine Parameter</strong>:<ul><li><code>ModuleInitializer</code> m&#xFC;ssen parameterlos sein. Das bedeutet, dass keine Abh&#xE4;ngigkeiten oder Konfigurationsoptionen &#xFC;ber Parameter &#xFC;bergeben werden k&#xF6;nnen.</li><li>Dependency Injection (DI) ist daher nicht m&#xF6;glich, da keine Parameter zur Verf&#xFC;gung stehen.</li><li>Wenn spezifische Konfigurationsoptionen f&#xFC;r die Initialisierung ben&#xF6;tigst werden, m&#xFC;ssen alternative Ans&#xE4;tze in Betracht gezogen werden.</li></ul></li></ol><p>Es ist wichtig, diese Nachteile abzuw&#xE4;gen und zu entscheiden, ob die Verwendung von <code>ModuleInitializer</code> in deinem speziellen Fall sinnvoll ist. In einigen Situationen k&#xF6;nnen sie dennoch eine praktische L&#xF6;sung sein, um bestimmte Aufgaben automatisch auszuf&#xFC;hren.</p>]]></content:encoded></item><item><title><![CDATA[DOTNET: AOT Kompilierung in Docker/Container]]></title><description><![CDATA[Dieser Artikel befasst sich mit der AOT Kompilierung einer .NET Core 8-Anwendung in Docker und deren Bereitstellung als fertiges Image.]]></description><link>https://carnucci.de/dotnet-aot-kompilierung-in-docker/</link><guid isPermaLink="false">6614de3a2dd8940001f86c1e</guid><category><![CDATA[Programmierung]]></category><category><![CDATA[Docker]]></category><category><![CDATA[C#]]></category><category><![CDATA[Dotnet]]></category><dc:creator><![CDATA[Rafael Carnucci]]></dc:creator><pubDate>Wed, 10 Apr 2024 21:59:49 GMT</pubDate><media:content url="https://carnucci.de/content/images/2024/04/pexels-pixabay-163726.jpg" medium="image"/><content:encoded><![CDATA[<div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text">Dieser Artikel enth&#xE4;lt Affiliate-Links. Wenn Sie &#xFC;ber diese Links Produkte kaufen, erhalte ich eine kleine Provision. Dies beeinflusst nicht meine Unabh&#xE4;ngigkeit. Die Verwendung der Links unterst&#xFC;tzt meine Arbeit. Vielen Dank f&#xFC;r Ihre Unterst&#xFC;tzung!</div></div><h2 id="einleitung">Einleitung</h2><img src="https://carnucci.de/content/images/2024/04/pexels-pixabay-163726.jpg" alt="DOTNET: AOT Kompilierung in Docker/Container"><p>Dieser Artikel befasst sich mit der AOT (Ahead-Of-Time) Kompilierung einer .NET Core 8-Anwendung in Docker und deren Bereitstellung als fertiges Image.</p><p>Bevor wir uns der konkreten Implementierung der AOT-Kompilierung in Docker widmen, folgt eine kurze Einf&#xFC;hrung in AOT und Docker-Kompilierung.</p><h3 id="aot">AOT</h3><p>Die AOT Kompilierung in C# ist eine Technik, die den Code vor der Laufzeit kompiliert. Dies kann zu einer verbesserten Leistung f&#xFC;hren, da der Code nicht zur Laufzeit interpretiert oder just-in-time kompiliert werden muss.</p><p>In ASP.NET Core 8.0 wurde Unterst&#xFC;tzung f&#xFC;r native .NET-AOT-Kompilierung eingef&#xFC;hrt1. Die Ver&#xF6;ffentlichung und Bereitstellung einer nativen AOT-App bietet folgende Vorteile:</p><ul><li>Minimierter ben&#xF6;tigter Speicherplatz auf dem Datentr&#xE4;ger: Bei der Ver&#xF6;ffentlichung mit nativer AOT-Kompilierung wird eine einzelne ausf&#xFC;hrbare Datei erstellt, die nur den Code aus externen Abh&#xE4;ngigkeiten enth&#xE4;lt, der zur Unterst&#xFC;tzung des Programms erforderlich ist.</li><li>Verk&#xFC;rzte Startzeit: Native AOT-Anwendungen k&#xF6;nnen k&#xFC;rzere Startzeiten aufweisen.</li><li>Reduzierter Speicherbedarf: Native AOT-Apps k&#xF6;nnen je nach den von der App ausgef&#xFC;hrten Aktionen einen geringeren Speicherbedarf aufweisen.</li></ul><p>Es ist jedoch wichtig zu beachten, dass nicht alle ASP.NET Core-Features mit nativer AOT-Kompilierung kompatibel sind. Beispielsweise sind MVC, Blazor Server und SignalR nicht unterst&#xFC;tzt</p><h3 id="kompilierung-in-dockercontainer">Kompilierung in Docker/Container</h3><p>Bei der Kompilierung einer Anwendung in Docker wird ein neues Build-Image erstellt, zu dem der Quellcode hinzugef&#xFC;gt wird. Zudem werden alle Anwendungen und Dateien, die f&#xFC;r die Kompilierung notwendig sind, ebenfalls hinzugef&#xFC;gt. Anschlie&#xDF;end wird die Anwendung kompiliert.</p><p>Die Verwendung von Docker zum Kompilieren bietet den Vorteil der Reproduzierbarkeit und Skalierbarkeit. Das Image muss nur einmal in einem Dockerfile konfiguriert werden und kann dann immer wieder verwendet werden. Das Build-Image kann zun&#xE4;chst lokal auf dem eigenen Client getestet werden, bevor es f&#xFC;r die Build-Pipeline freigegeben wird. Spezifische Einstellungen auf dem Build-Server entfallen. Bei einer neuen .Net Core-Version muss lediglich das Image angepasst werden. Es sind keine Installationen auf dem Build-Server erforderlich. Dadurch k&#xF6;nnen neue Build-Server einfach integriert werden. Dar&#xFC;ber hinaus steht nach dem Erstellen direkt ein Docker-Image zur Verf&#xFC;gung.</p><div class="kg-card kg-callout-card kg-callout-card-grey"><div class="kg-callout-text">Das Build-Image sollte nicht in der Produktionsumgebung eingesetzt werden. Es ist daf&#xFC;r zu gro&#xDF; und enth&#xE4;lt Anwendungen und Dateien, die nicht ben&#xF6;tigt werden. Der einzige Zweck des Images besteht darin, die Kompilierung durchzuf&#xFC;hren und die Anwendung (samt zugeh&#xF6;riger Dateien) bereitzustellen. Dies geschieht im Rahmen von Multi-Stage-Builds.</div></div><h2 id="net-core-aot-kompilierung-in-docker">.Net Core AOT Kompilierung in Docker</h2><p>Dieses Kapitel veranschaulicht beispielhaft, wie eine .dockerignore- und Dockerfile-Datei aussehen k&#xF6;nnten. Es ist notwendig, diese Dateien entsprechend den Anforderungen Ihres eigenen Projekts anzupassen. Vorausgesetzt werden Kenntnisse in Docker und eine bestehende Installation. Theoretisch sollte auch Podman funktionieren.</p><p>F&#xFC;r eine umfassendere Auseinandersetzung mit Docker empfehle ich das Buch &#x201C;<a href="https://amzn.to/3PVhMnV?ref=carnucci.de" rel="noreferrer">Skalierbare Container-Infrastrukturen: Das Handbuch f&#xFC;r Planung und Administration</a>&#x201D;, welches auch die Container-Orchestrierung mit Kubernetes und OpenShift behandelt.</p><h3 id="dockerignore">.dockerignore</h3><p>Die .dockerignore-Datei dient dazu, festzulegen, welche Dateien beim Kopieren mit dem Befehl <code>Copy</code> ignoriert werden sollen. Im untenstehenden Beispiel werden alle Dateien in den Ordnern &#x2018;obj&#x2019; und &#x2018;bin&#x2019; ignoriert. Durch die Reduzierung der Datenmenge kann die Erstellung des Build-Images beschleunigt werden.</p><pre><code class="language-.dockerignore">**/obj/
**/bin/</code></pre><h3 id="dockerfile">Dockerfile</h3><p>Zun&#xE4;chst wird das Runtime-Image definiert und ein Benutzer hinzugef&#xFC;gt. Die Anwendung befindet sich im Verzeichnis <code>/app</code>. Anschlie&#xDF;end wird der Build mit der .NET SDK 8.0 erstellt. Dabei werden sowohl die Projektmappe als auch der Quellcode zum Image hinzugef&#xFC;gt. Danach wird die Anwendung kompiliert, in diesem Fall f&#xFC;r Linux-x64. F&#xFC;r win-x64 (Windows) w&#xE4;re ein Windows-Container erforderlich. Bei der Verwendung von Docker-Hub mit Windows WSL 2 wird stets ein Linux-Container erstellt.</p><p>Schlie&#xDF;lich wird das eigentliche Image erstellt. Die kompilierte Anwendung wird in das Verzeichnis <code>/app</code> kopiert und das auszuf&#xFC;hrende Programm wird als <code>Entrypoint</code> festgelegt. Bei Linux hat die auszuf&#xFC;hrende Datei keine <code>.exe</code>-Endung. Die Labels sind optional.</p><p>Das Image kann mit dem Befehl <code>docker build -t {ImageName} .</code> ausgef&#xFC;hrt werden. </p><pre><code class="language-Dockerfile"># Runtime Image
FROM alpine:3.19.1 AS prepare
# libc6-compat wird zum ausf&#xFC;hren ben&#xF6;tigt
RUN apk add --no-cache libc6-compat
WORKDIR /app
RUN adduser -u 1000 --disabled-password --gecos &quot;&quot; appuser &amp;&amp; chown -R appuser /app
USER appuser

# Build Image
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
# clang zlib1g-dev werden f&#xFC;r AOT ben&#xF6;tigt
RUN apt update &amp;&amp; apt upgrade -y &amp;&amp; apt install -y clang zlib1g-dev
WORKDIR /build
COPY ./Projektmappe.sln ./
COPY ./src ./src
RUN dotnet publish ./src/Projekt/Projekt.csproj -c Release -r linux-x64 -o /app

FROM prepare AS finalalpine

# Labels.
LABEL maintainer=&quot;&quot;
LABEL org.label-schema.schema-version=&quot;1.0&quot;
LABEL org.label-schema.name=&quot;&quot;
LABEL org.label-schema.description=&quot;&quot;
LABEL org.label-schema.version=&quot;1.0&quot;

COPY --chown=appuser --from=build /app ./
ENTRYPOINT [&quot;./Programm&quot;]</code></pre><p>Bei der Verwendung eines privaten Nuget-Repositorys m&#xFC;ssen Sie Anmeldedaten angeben. Die genaue Vorgehensweise wird auf der entsprechenden GitHub-Seite erl&#xE4;utert.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/dotnet/dotnet-docker/blob/main/documentation/scenarios/nuget-credentials.md?ref=carnucci.de"><div class="kg-bookmark-content"><div class="kg-bookmark-title">dotnet-docker/documentation/scenarios/nuget-credentials.md at main &#xB7; dotnet/dotnet-docker</div><div class="kg-bookmark-description">Docker images for .NET and the .NET Tools. Contribute to dotnet/dotnet-docker development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" alt="DOTNET: AOT Kompilierung in Docker/Container"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">dotnet</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/6f11f289504e53c8f643a90a94b3284e0bac7a9681b094ad162f211793fb78d7/dotnet/dotnet-docker" alt="DOTNET: AOT Kompilierung in Docker/Container"></div></a></figure><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[Angular: Dialog Komponente zur Laufzeit laden]]></title><description><![CDATA[Angular ermöglicht das nachträgliche Laden von Komponenten, einschließlich MatDialog, was die Ladezeit verkürzt und das Benutzererlebnis verbessert.]]></description><link>https://carnucci.de/angular-dialog-komponente-zur-laufzeit-laden/</link><guid isPermaLink="false">661430c62dd8940001f86bd1</guid><category><![CDATA[Angular]]></category><category><![CDATA[Programmierung]]></category><dc:creator><![CDATA[Rafael Carnucci]]></dc:creator><pubDate>Mon, 08 Apr 2024 18:39:32 GMT</pubDate><media:content url="https://carnucci.de/content/images/2024/04/lockup_angular_gradient.png" medium="image"/><content:encoded><![CDATA[<h2 id="einleitung">Einleitung</h2><img src="https://carnucci.de/content/images/2024/04/lockup_angular_gradient.png" alt="Angular: Dialog Komponente zur Laufzeit laden"><p>Eine der Herausforderungen bei der Entwicklung von Angular-Webseiten ist die Reduzierung der Bundle-Gr&#xF6;&#xDF;e. Dies ist entscheidend, um eine schnelle Ladezeit der Webseite f&#xFC;r die Besucher zu gew&#xE4;hrleisten. Eine Methode, dies zu erreichen, besteht darin, dass der Kompiler die Webseite in einzelne Javascript-Dateien kompiliert.</p><p>Mit der Einf&#xFC;hrung von Angular 17 wurde die&#xA0;<code>@defer</code>&#xA0;Anweisung hinzugef&#xFC;gt. Diese sieht wie folgt aus:</p><pre><code class="language-Angular">@defer {
  &lt;large-component /&gt;
}</code></pre><p>Diese Anweisung erm&#xF6;glicht es, eine Standalone Komponente nachtr&#xE4;glich zu laden. Dies ist besonders n&#xFC;tzlich, wenn eine Komponente nicht sofort ben&#xF6;tigt wird.</p><h2 id="dialog">Dialog</h2><p>Beim &#xD6;ffnen eines Dialogs (einer Komponente) &#xFC;ber&#xA0;<code>MatDialog</code>&#xA0;wird die zu &#xF6;ffnende Komponente direkt in der Javascript-Datei eingebettet. Dies ist nicht immer w&#xFC;nschenswert, insbesondere wenn der Dialog sehr selten ge&#xF6;ffnet wird und daher kaum ben&#xF6;tigt wird.</p><p>Es ist m&#xF6;glich, die Komponente erst beim Aufruf &#xFC;ber&#xA0;<code>import</code>&#xA0;zu laden. Dadurch wird die eigentliche Javascript-Datei kleiner. Ein Beispiel daf&#xFC;r k&#xF6;nnte wie folgt aussehen:</p><pre><code class="language-Typescript">public openDialog() {
  import(&apos;./dialog.component&apos;).then(
        (x) =&gt; {
           this.matDialog.open(x.DialogComponent)
        },
  );
}
</code></pre><p>Falls die Komponente noch nicht geladen wurde, wird sie &#xFC;ber die&#xA0;<code>import</code>-Anweisung vom Webserver nachgeladen. Anschlie&#xDF;end &#xF6;ffnet&#xA0;<code>MatDialog</code>&#xA0;die Komponente. Es ist empfehlenswert, dass es sich bei der Komponente um eine Standalone-Komponente handelt</p><p>Durch die Verwendung dieser Techniken k&#xF6;nnen Entwickler die Leistung ihrer Angular-Webseiten erheblich verbessern und so f&#xFC;r ein besseres Benutzererlebnis sorgen. Es ist wichtig, stets auf dem neuesten Stand der Technologie zu bleiben und neue Funktionen und Techniken zu nutzen, sobald sie verf&#xFC;gbar sind.</p>]]></content:encoded></item></channel></rss>