blecon https://blecon.de Interactive & Digital Mon, 23 Feb 2026 07:55:00 +0000 de hourly 1 https://wordpress.org/?v=6.9 https://blecon.de/wp-content/uploads/2026/01/cropped-blecon-icon-32x32.webp blecon https://blecon.de 32 32 Roundcube Webmail Exploits werden ausgenutzt https://blecon.de/blog/sicherheitsschwachstellen/cve-2025-49113-cve-2025-68461/ Mon, 23 Feb 2026 07:49:52 +0000 https://blecon.de/?p=1963 Zwei Sicherheitslücken in der Webmail-Anwendung RoundCube werden zur Zeit aktiv ausgenutzt.

Es handelt sich hierbei um eine Remote Code Execution durch einen autorisierten Nutzer (CVE-2025-49113) und eine Cross Site Scripting Attacke über den animate tag in SVG Dateien (CVE-2025-68461).

Das pikante, eine Cross Site Scripting Attacke in einem SVG in einer E-Mail kann sich im autorisierten Bereich (im Kontext des Benutzerpostfaches) abspielen.

Update Versionen 1.5.12 und 1.6.12 schließen zumindest die Cross Site Scripting Angriffsoberfläche und Installationen sollten möglichst sofort auf mindestens diese aktualisiert werden.

Was ist eine Remote Code Execution?

Eine „Remote Code Execution“ (RCE) oder „Remotecodeausführung“ ist eine Schwachstelle, die es einem entfernten (Remote) Angreifer erlaubt auf einer Maschine – in der Regel der, auf der die Schwachstelle präsent ist – auszuführen (oder ausführen zu lassen).

Dies kann zu einem Auslesen und Abführen von Informationen oder zur Installation von Schadsoftware auf dem verwundbaren System führen, welches dann beispielsweise als Einstiegspunkt für Command-And-Control Anker oder als Startpunkt von Verschlüsselungstrojanern genutzt werden kann.

Was bedeutet Cross Site Scripting?

Eine Cross Site Scripting (XSS) Attacke ist eine sehr weite verbreite Angriffsform im Internet. Das Kernziel besteht darin fremden (von einer anderen Seite) Code in die Ausführung oder Benutzersteuerung einer anderen Webseite zu platzieren – daher Cross Site, also seitenübergreifend.

Das Ergebnis sind mögliche Zugriffe auf vertrauenswürdige Informationen, Verfälschung von Eingabefeldern, Abfluss von Daten im allgemeinen.

Quellen & weitere Informationen

]]>
Zufällig das gleiche https://blecon.de/blog/sicherheitstipps/zufaellig-das-gleiche/ Thu, 19 Feb 2026 08:03:32 +0000 https://blecon.de/?p=1940 Die KI Sicherheitsfirma Irregular hat einen Bericht veröffentlicht, der sich mit der Sicherheit von KI generierten Passwörtern befasst

Das Ergebnis in Kurzform ist, dass ein Large Language Model (LLM) das wiedergibt, was es stochastisch als am wahrscheinlichsten ansieht. Beim Erzeugen von einmaligen, zufälligen und sicheren Passwörtern führt dies zu Problemen.

Passwörter, die von LLMs erzeugt wurden – also nicht durch einen Tool-Aufruf (ein externes Werkzeug, wie einen „klassischen“ Passwortgenerator) – sehen zwar erst mal sicher aus, sind es bei einer Stichprobe mit 50 generierten Passwörtern und Anthropics Claude Opus 4.6 aber nicht. Eigentlich sind es nur 30 einmalige Zeichenketten und die Unterschiede zwischen ihnen sind teils sehr gering. So beginnt ein Großteil der Stichprobe mit K7#mP9 (auch als ich das einfach mal selber ausprobiert hab…)

Aber wer nutzt denn KI für seine Passwörter?

Ich bin mir sicher, viele von euch benutzen (bitte bitte bitte) einen Passwortmanager, egal ob als SaaS oder auf dem eigenen PC. Diese bringen alle einen Passwortgenerator mit, vollständig integriert, einfach zu erreichen und zumeist wirklich zufällig.

Aber KIs fragen KIs nach Passwörtern. Viele Passwörter, die in das Muster der KI-Generierten Strings passen, sind beispielsweise auf GitHub in öffentlichen Repositories zu finden. Dort schnell nach "K7#mP9" OR "k9#vL" gesucht liefert 37 Code-Ergebnisse – beides beliebte Teile von Passwörtern aus Anthropics Claude Opus und Sonnet und Googles Gemini.
(Darunter auch ein Twitch-Login, der bis auf den E-Mail 2FA scheinbar auch funktioniert 🤦)

Also was sagt uns das jetzt…

Passwörter sollten niemals von algorithmisch gesteuerten Tools erzeugt werden, das macht sie, im wahrsten Sinne des Wortes, berechenbar – und genau das wollen wir ja nicht…

Wenn ihr selbst Passwörter benötigt, nutzt euren Passwortmanager (den ihr ja sicher alle habt) oder nutzt, wenn es sein muss, die Webseiten von vertrauenswürdigen Passwortgeneratoren. Als Beispiele lasse ich euch mal unverbindlich ein paar da – in keiner Reihenfolge und ohne Sponsoring

Wenn ihr im Coding-Umfeld mit KI arbeitet und dort Passwörter braucht, lasst sie entweder durch Tool-Calls gegen richtige Passwortgeneratoren erzeugen oder gebt sie selbst über Konfigurationsvariablen in das fertige Produkt hinein.

Am Schluss läuft es immer auf das gleiche hinaus – passt auf und macht keinen Quatsch.

Quellen und weitere Informationen

]]>
30 Fake KI Plugins im Google Chome Extension Store https://blecon.de/blog/sicherheitsschwachstellen/30-fake-ki-plugins-im-google-chome-extension-store/ Mon, 16 Feb 2026 09:21:53 +0000 https://blecon.de/?p=1901 Erweiterungen im Browser sind hilfreich und können die Arbeit leichter machen, keine frage. Insbesondre die Integration von künstlicher Intelligenz lockt aktuell viele Nutzer*innen mit Versprechen von Effizienz Steigerung der Zeitersparnis.

LayerX, ein amerikanisches Sicherheitsunternehmen mit Fokus auf den sicheren Einsatz von KI im Arbeits- und Unternehemnsalltag, hat eine Untersuchung veröffentlicht in der 30 schädliche „KI“ Erweiterungen im Chrome Webstore untersucht wurden. Diese Erweiterungen habe zusammen genommen rund 260.000 Nutzer*innen.

Die Erweiterungen nutzen die Namen bekannter KI Unternehmen und Produkte um vertrauenserweckend zu wirken, bieten aber primär einen Angriffsvektor gegen den Browser des installierenden. Die Erweiterung setzt hierbei auf einen fensterfüllenden iFrame, der es den Angreifern erlaubt ohne ein Update über den Extension Store den Inhalt des Plugins vollständig auszutauschen. Gepaart mit den API Zugriffsmöglichkeiten von Erweiterungen entsteht heir somit ein schwer einschätzbares Risiko.

Wie kann sich jede*r Nutzer*in und jedes Unternehmen schützen?

  • Nur vertrauenswürdige Erweiterungen nutzen.
    Indikatoren hierfür können zum Einen das Alter der Erweiterung oder die Menge an Bewertungen sein (schädliche Erweiterungen überleben in der Regel nicht lange in den einzelnen Stores).
    Alternativ, der sichere Weg, ist sich ausschließlich über Links auf den Herstellerseiten zu Downloads führen zu lassen.
  • Sicherheitssoftware und ihre Updates installieren.
    Viele Anti-Viren beinhaltet heutzutage Verhaltenserkennung von Anwendungen und integriert sich auch in die gängigen Browser. hierüber kann verdächtiges Verhalten erkannt und unterbunden werden.

Quellen und weitere Informationen

]]>
Remote Code Execution in Microsoft Windows Notepad https://blecon.de/blog/sicherheitsschwachstellen/cve-2026-20841/ Sun, 15 Feb 2026 19:57:14 +0000 https://blecon.de/?p=1892 Microsoft Notepad, eine Standardanwendung des Microsoft Windows Betriebssystems, besitzt aktuell eine Remote Code Execution Schwachstelle.

Betroffen ist Windows Notepad in der Version vor 11.2510
Aktualisierungen können im Microsoft Store abgerufen werden: https://apps.microsoft.com/detail/9msmlrh6lzf3

Konkret handelt es sich um eine Schwachstelle in der Bereinigung von Verknüpfungen in Markdown-Dateien. Auslöser ist eine präparierte Datei und den Klick auf einen Link in diesem Dokument. Danach kann Notepad vorbereite, verifizierte Dateien und Protokolle von unbekannten Quellen ausführen.

Was ist eine Remote Code Execution?

Eine „Remote Code Execution“ (RCE) oder „Remotecodeausführung“ ist eine Schwachstelle, die es einem entfernten (Remote) Angreifer erlaubt auf einer Maschine – in der Regel der, auf der die Schwachstelle präsent ist – auszuführen (oder ausführen zu lassen).

Dies kann zu einem Auslesen und Abführen von Informationen oder zur Installation von Schadsoftware auf dem verwundbaren System führen, welches dann beispielsweise als Einstiegspunkt für Command-And-Control Anker oder als Startpunkt von Verschlüsselungstrojanern genutzt werden kann.

Quellen und weitere Informationen

]]>
Use After Free in CSS in Chromium-Basierten Browsern https://blecon.de/blog/sicherheitsschwachstellen/cve-2026-2441/ Sun, 15 Feb 2026 13:36:54 +0000 https://blecon.de/?p=1591 Ein aktueller Use-After-Free Zeroday plagt Chromium-Basierte Browser wie Google Chrome, Microsoft Edge, Brave und viele andere.

Betroffen sind Chromium-Browser vor der Version 145.0.7632.75
Die Version deines Browsers kannst du unter chrome://settings/help prüfen und aktualisieren.
(Den Link musst Du selbst aufrufen, da das ein interner Link Deines Browsers ist, kann ich Dich da nicht einfach hin teleportieren)

Zum aktuellen Zeitpunkt sind die aktuellsten Version verschiedener Browser:

BrowserChromium Version
Google Chrome145.0.7632.110✅ Sicher
Microsoft Edge145.0.3800.65❌ Nicht sicher
Brave145.0.7632.76✅ Sicher
Opera143.0.7499.194❌ Nicht sicher
Zeitpunkt der Informationen: 2026-02-19 11:00 CET

Was bedeutet „Use After Free“

„Use After Free“ (UAF) beschreibt ein fehlerhaftes Verhalten von Software, in dem auf Speicher (RAM) zugegriffen wird, nach dem dieser durch das Programm freigegeben wurde. Dadurch kann es dazu kommen, dass andere Daten als Erwartet in einem Speicherbereich liegen und dann durch die falsche Routine evaluiert werden. Das Ergebnis kann von einem einfachen Programmfehler oder -absturz bis zur Ausführung von unerwünschten Instruktionen führen.

Diese Ausführung von unerwarteten Programmanweisungen ist was eine UAF Situation gefährlich macht. Durch gezielt vorbereitete Abfolgen von Speicherbeeinflussung kann ein Programm, das an sich keine Schadsoftware beinhaltet, dazu ausgenutzt werden um auf Informationen zuzugreifen und diese nach außen abzuführen oder andere Software auf das Zielsystem zu übertragen.

Quellen & weitere Informationen

]]>
Wiesbaden-Engagiert 2025 in der Karl-Gärtner-Schule in Delkenheim https://blecon.de/blog/nachhaltigkeit/wiesbaden-engagiert-2025/ Mon, 22 Sep 2025 03:00:00 +0000 https://blecon.de/?p=1639 Wiedermal war es soweit. Die jährliche Aktionswoche Wiesbaden Engagiert 2025 stand an und wir von blecon beteiligten uns voller Begeisterung zum ersten mal mit einem eigenen Projekt. Mit viel Engagement und Teamgeist haben wir gemeinsam mit dem Schulleiter der Karl-Gärtner-Schule Projekte umgesetzt, die den Kindern einen Ort zum wohlfühlen bieten.

Neuer Lesebereich – Ein Ort der Ruhe und Inspiration

Eines der Herzensprojekte war die Einrichtung einer gemütlichen Sitzecke zum Lesen. In einer ruhigen Ecke des Schulhofs haben wir eine kleine, aber feine Lese-Oase geschaffen, die nicht nur zum Schmökern einlädt, sondern auch als Rückzugsort dient. Mit wetterfesten Sitzbänken, dem geplanten Sonnensegel und einem frei nutzbaren Bücherregal ist dieser Bereich zu einem echten Highlight geworden.

Klettergerüst im neuen Glanz

Ein weiteres Projekt war das Streichen und Auffrischen des alten Klettergerüsts, auf dem auch unser Chef als Schulkind schon gespielt hat. Mit bunten Farben und einer gründlichen Auffrischung haben wir dem Spielplatz neues Leben eingehaucht.

Die Buddelkiste – Sand, Spaß und Kreativität

Zu guter Letzt haben wir eine neue Buddelkiste angelegt. Der Sandkasten war schon immer ein Ort, an dem Kinder ihrer Fantasie freien Lauf lassen konnten, doch nie war ganz klar ob das nun ein Bereich zum wilden Buddeln oder gerade zum behutsamen Burgen bauen ist. Gemeinsam haben wir einen neuen Buddelbereich errichtet, der nun mit einer stabilen Umrandung darauf wartet, dass die Kinder dort bauen, graben und spielen können.

Ein nachhaltiger Beitrag zur Zukunft der Kinder

Das Engagement in unserer lokalen Gemeinschaft liegt uns besonders am Herzen. Mit dieser Initiative wollten wir nicht nur die Infrastruktur der Schule verbessern, sondern auch ein Zeichen setzen, wie wichtig es ist, in die Bildung und das Wohl der nächsten Generation zu investieren. Wir sind überzeugt, dass eine gute Lernumgebung den Kindern nicht nur bei ihrer schulischen Entwicklung hilft, sondern sie auch in ihrer sozialen und emotionalen Entwicklung stärkt.

Fazit: Wiesbaden engagiert 2025, ein gelungenes Projekt, das im Herzen bleibt

Die Arbeiten sind abgeschlossen, und wir freuen uns, dass die Kinder der Grundschule die neu gestalteten Bereiche nutzen können. Es war ein Tag voller Lachen, Engagement und unvergesslicher Momente. Für uns ist es nicht nur ein Erfolg, etwas Positives für die Kinder und die Schule getan zu haben, sondern auch ein gelungenes Projekt mit (fast) dem gesamten blecon-Team abseits der Softwareentwicklung.

Wir bedanken uns bei allen Beteiligten, die dieses Projekt möglich gemacht haben, und freuen uns auf zukünftige Initiativen, die wir gemeinsam für eine bessere Zukunft gestalten können.

]]>
Ein Jahr des Wachstums, der Innovation und des Teamgeistes https://blecon.de/blog/leben-bei-blecon/jahresruckblick-2024/ Mon, 23 Dec 2024 01:00:00 +0000 https://blecon.de/?p=1664 Das Jahr 2024 neigt sich dem Ende zu, und wir bei der blecon GmbH aus Wiesbaden blicken auf ein äußerst spannendes und ereignisreiches Jahr zurück. Es war ein Jahr voller neuer Chancen, herausfordernder Projekte und bedeutender Weiterentwicklungen, die uns als Unternehmen und als Team weitergebracht haben. In diesem Blogbeitrag möchten wir einige der wichtigsten Meilensteine und Erfahrungen des vergangenen Jahres teilen und einen Ausblick auf die Zukunft geben.

Neue Partnerschaften und das Wachstum unserer Digitalisierungsstrategie

2024 war für uns ein Jahr des Wachstums – und das nicht nur im physischen Sinne, sondern vor allem im Hinblick auf unsere strategischen Partnerschaften und die Erweiterung unseres Wissens im Bereich der Digitalisierung. Durch die Zusammenarbeit mit zwei neuen Partnerunternehmen, die wir über das Microsoft Partner Portal betreuen, konnten wir nicht nur unseren Direktkundenstamm vergrößern, sondern auch unsere Expertise in der Fernverwaltung von Unternehmen ausbauen. Dieser Schritt hat uns besonders im Markt der Digitalisierung kleinerer Unternehmen ohne eigene IT-Abteilung enorm vorangebracht.

Zudem haben wir in diesem Jahr erfolgreich vier go-digital Förderungen erhalten, die es uns ermöglicht haben, kleinen und mittelständischen Unternehmen (KMU) bei der digitalen Transformation zu unterstützen. Auch im Bereich der Finanzierung haben wir zwei Unternehmen bei einer Förderung durch den DIGI Zuschuss der WI Bank unterstützt – ein weiteres Beispiel dafür, wie wir als Unternehmen unseren Beitrag zur Digitalisierung der Region Wiesbaden leisten.

Vertiefung von Fachwissen und neuen Technologien

Auch im technischen Bereich haben wir uns weiterentwickelt. So konnten wir im Rahmen zweier komplexer Projekte im UI-Bereich unsere Kenntnisse in Blazor und FluentUI vertiefen, was nicht nur zu einer besseren Qualität unserer Projekte, sondern auch zu einer breiten Kompetenz im Team geführt hat. Ein weiteres Highlight war die Entwicklung einer Smartphone-Anwendung, die uns die Möglichkeit gab, uns intensiv mit .NET MAUI auseinanderzusetzen – eine Technologie, die uns in Zukunft noch weiter begleiten wird.

Darüber hinaus haben wir uns in spannende neue Themen wie Künstliche Intelligenz (AI) vertieft. Verschiedene Projekte ermöglichten uns den Einstieg in dieses zukunftsträchtige Feld, das wir mit Begeisterung weiter erkunden werden. Auch neue Technologien wie Sprachsteuerung, WhatsApp-Integration und KI-gesteuerte Gesprächsaufbauten fanden ihren Weg in unsere Arbeit, was uns hilft, noch innovativere Lösungen zu entwickeln.

Ein besonders aufregender Schritt war der Beginn der Entwicklung unseres ersten eigenen Produkts als Prototypen. Hierfür haben wir bekannte Eingabegeräte umgebaut, um mit modernen Technologien zu kommunizieren und so neue Möglichkeiten der Interaktion zu schaffen.

Weiterbildung und interne Standards

Neben der Arbeit an Projekten war auch die Weiterbildung ein wichtiger Bestandteil unseres Jahres. Die AWS-Fortbildung eines unserer Mitarbeiter war ein Highlight, da wir dadurch unser Wissen in der AWS-Platform und Software-Architektur vertiefen und zusätzliche Cloud-Plattformen zu Microsoft Azure erkunden konnten. Auch die Entwicklung einer internen Standard-Herangehensweise für ASP.NET Web-Apps war ein wichtiger Schritt. Dieser Standard wird uns künftig dabei helfen, noch effizienter und strukturierter zu arbeiten.

Öffentlichkeits- und Netzwerkarbeit

2024 haben wir unsere Öffentlichkeitsarbeit und Netzwerkaktivitäten weiter intensiviert. Es war spannend zu sehen, wie sich unser Engagement in verschiedenen Wiesbadener Netzwerken ausgezahlt hat. Besonders hervorzuheben sind hier das Wirtschaftsforum Wiesbaden, das CSR Regio.NET und die WITech Alliance. In diesen Netzwerken haben wir nicht nur wertvolle Kontakte geknüpft, sondern auch unsere Position als Unternehmen in Wiesbaden weiter gestärkt.

Das Wirtschaftsforum Wiesbaden fördert den Austausch zwischen Unternehmern, und die Teilnahme an den regelmäßigen Treffen und Impulsvorträgen hat uns neue Perspektiven eröffnet. Auch im CSR Regio.NET haben wir uns intensiv mit dem Thema verantwortungsvolle Unternehmensführung auseinandergesetzt und unser Engagement in diesem Bereich ausgebaut.

Die WITech Alliance hat es uns ermöglicht, uns mit anderen Unternehmen aus der IT- und Tech-Branche auszutauschen und gemeinsam große Ausschreibungen anzugehen – ein spannender Schritt, der uns auch in Zukunft viele Chancen bieten wird.

Werte und Ziele für die Zukunft

Ein weiteres Highlight des Jahres war die Arbeit an unseren eigenen Werten und Zielen als Unternehmen. Wir haben gemeinsam an unserem Leitbild und unseren strategischen Zielen gearbeitet, was nicht nur zu einer klareren Ausrichtung, sondern auch zu einer stärkeren Identifikation jedes Einzelnen mit der blecon GmbH geführt hat. Dieses Jahr der Veränderung und Anpassung hat uns als Team enger zusammengebracht und uns auf den Weg gebracht, noch stärker und fokussierter in die Zukunft zu blicken.

Rückblick auf ein herausforderndes Jahr

Das Jahr 2024 war nicht nur ein Jahr des Wachstums, sondern auch ein Jahr der Herausforderungen. Der Wechsel von vermittelten Projekten zu Direktkundenprojekten war ein bedeutender Schritt, den wir mit viel Einsatz und Flexibilität gemeistert haben. Zwar gab es viele Umstellungen und kleinere, kürzere Projekte, doch wir haben es geschafft, uns erfolgreich neu zu positionieren und sind nun nicht mehr von vermittelten Projekten abhängig. Diese Umstellung hat uns als Team gestärkt und uns auf den zukünftigen Erfolg vorbereitet.

Ein gelungenes Jahresabschlussfest

Zum Jahresabschluss haben wir gemeinsam ein unvergessliches Erlebnis gehabt: Unser Team besuchte einen Escape-Room in Frankfurt, erkundete den Weihnachtsmarkt und genoss ein hervorragendes Abendessen in einem spanischen Restaurant. Die entspannte Hotelübernachtung rundete unseren Jahresabschluss perfekt ab und gab uns die Gelegenheit, das Jahr in entspannter Atmosphäre ausklingen zu lassen.

Ausblick auf 2025

Mit Blick auf das Jahr 2025 sind wir voller Vorfreude auf die neuen Herausforderungen und Chancen, die auf uns warten. Die Erfahrungen und Erfolge aus 2024 bilden die Grundlage für unser weiteres Wachstum und unsere Weiterentwicklung. Wir werden weiterhin mit unseren Partnern und Kunden zusammenarbeiten, innovative Lösungen entwickeln und unseren Weg als führendes Unternehmen in der Digitalisierung kleiner und mittelständischer Unternehmen fortsetzen.

Wir möchten uns an dieser Stelle bei unseren Kunden, Partnern und dem gesamten Team für die Zusammenarbeit und den Einsatz im vergangenen Jahr bedanken. Auf ein erfolgreiches und spannendes Jahr 2025!

Das blecon Team

]]>
Code Coverage via CLI https://blecon.de/blog/arbeiten-bei-blecon/code-coverage-via-cli/ Tue, 19 Nov 2024 01:00:00 +0000 https://blecon.de/?p=1685 Eine gute Code Coverage-Übersicht hilft sehr dabei, Stellen im Code zu identifizieren, für die noch Unit Tests ergänzt werden sollten. In Visual Studio gibt es dafür im Menü Test unter Analyze Code Coverage for All Tests ein nützliches Fenster.

Dieses Fenster steht einem allerdings nur in der Enterprise Version von Visual Studio zur Verfügung.

Will man eine ähnliche Erfahrung haben, das aber möglichst ohne zusätzliche Kosten, muss man schon etwas wühlen, bis man eine Lösung findet.
Ich selbst fand mich in der Lage wieder, mit einer Professional-Version von Visual Studio zu arbeiten, bei der aus mir unbekannten Gründen Extensions wie Fine Code Coverage nicht zuverlässig funktionieren wollten.

Zu meiner Rettung stieß ich dann auf zwei CLI-Tools, die mir enorm weiterhelfen sollten: dotnet-coverage und dotnet-reportgenerator-globaltool.

Ein Beispiel inklusive des nötigen PowerShell-Scripts zur Verwendung der nachfolgend beschriebenen Lösung steht im GitHub-Repository der blecon GmbH zur Verfügung.

Einrichtung der Code Coverage

Um die beiden genannten Tools verwenden zu können, muss man sie zunächst einmalig installieren. Das ist über das .NET CLI sehr einfach gemacht:

dotnet tool install -global dotnet-coverage
dotnet tool install -global dotnet-reportgenerator-globaltool

Sammeln von Daten

Sind beide Tools installiert, kann man mit dem Sammeln der nötigen Daten für eine Code Coverage-Ansicht beginnen.
Führt man dotnet-coverage wie folgt aus, wird ein neuer Test-Run gestartet und das Tool legt die Coverage-Daten in der Datei coverage.xml ab.

dotnet-coverage collect --output-format xml --output coverage.xml dotnet test <solution/project>

Erstellen des Coverage-Reports

Man kann mit dem folgenden Befehl einen HTML-Bericht aus den Coverage-Daten erzeugen.

reportgenerator -reports:coverage.xml -targetdir:.\report

Das Tool erzeugt den Bericht, mit allen nötigen Dateien im Verzeichnis report. Man kann nun in diesem Verzeichnis index.html im Browser öffnen, wodurch man eine Seite wie die folgende sieht.

Wie im Visual Studio-Fenster kann man hier sehen, dass die Testabdeckung für CalculatorLibrary.Calculator bei mageren 25% liegt.

Drilldown im Coverage-Report

Der Report erlaubt es nun auch, sich in der Hierarchie nach unten zu bohren. Klicke ich zum Beispiel auf die Zeile CalculatorLibrary.Calculator, bekomme ich eine hübsche Übersicht über die (nicht) abgedeckten Code-Zeilen.

Das hilft mir definitiv weiter, wenn ich wissen will, welche Tests ich noch schreiben muss.

One step further

Böse Zungen behaupten ja immer wieder, dass Entwickler nur deswegen Entwickler geworden sind, weil sie faul sind. Und ja, was soll ich sagen, da ist doch auch was dran, oder?
Ich jedenfalls war zu faul, jedes Mal die beiden nötigen Befehle einzutippen, um einen aktuellen Coverage-Bericht zu bekommen. Darum habe ich für das hier verwendete Demo-Projekt eine PS1-Datei mit folgendem Inhalt zusammengebaut.

Remove-Item -Path ".\CodeCoverage" -Recurse -Force
dotnet-coverage collect --output-format xml --output .\CodeCoverage\coverage.xml dotnet test CodeCoverageDemo.sln
reportgenerator -reports:.\CodeCoverage\coverage.xml -targetdir:.\CodeCoverage\report

Im ersten Schritt lösche ich hier bisherige Code Coverage-Daten. Danach erzeuge ich die aktuellen Daten und erstelle schließlich den Bericht.
Jetzt brauche ich nur noch im Browser meine Seite neu zu laden und habe die aktuellen Code Coverage-Ergebnisse zur Hand.

Fazit

Zwar bietet mir diese Methode „nur“ eine Line Coverage, eine Method Coverage müsste gegen den Einwurf kleiner Münzen freigeschaltet werden. Aber ich bin der Meinung, das ist allemal deutlich besser als nichts.
Mir jedenfalls haben die so erzeugten Berichte in meinem aktuellen Kundenprojekt ziemlich weitergeholfen.

Ich hoffe, dass sie auch dem ein oder anderen da draußen zu Diensten sein werden.

]]>
C#: Mit itext7 ein PDF in einen MemoryStream schreiben https://blecon.de/blog/arbeiten-bei-blecon/c-mit-itext7-ein-pdf-in-einen-memorystream-schreiben/ Fri, 18 Oct 2024 01:00:00 +0000 https://blecon.de/?p=1697 Da wir demnächst verpflichtet sind E-Rechnungen (Factur-X/ZUGFeRD) anzubieten, mussten wir unsere Rechnungserstellung entsprechend erweitern. Wir nutzen LaTeX um aus einem Template ein PDF für den visuellen Teil einer Rechnung zu generieren.Um die Rechnungen nun um E-Rechnungen zu erweitern nutze ich ZUGFeRD-csharp um das dazu gehörende XML zu erstellen. Außerdem nutze ich itext7 um diese beiden Teile zusammen zu führen. Ich muss das PDF dann in einen Blob Storage hoch laden. Deshalb muss ich es in C# mit itext7 in einen MemoryStream schreiben. Allerdings bin ich dabei auf ein Problem gestoßen, zu dem es etwas schwierig war eine dokumentierte Lösung zu finden. Eben weil das so schwierig war, habe ich diesen Blogbeitrag geschrieben.

Das Problem

Die Dokumentation von itext7 erwähnt zwar, dass man PDFs auch in Streams schreiben kann, anstatt direkt in Dateien, übergeht dabei allerdings ein wichtiges Detail. Man muss die PdfWriter-Instanz explizit so konfigurieren, dass sie den ihr übergebenen Stream nicht Disposed. Wenn man dies nicht tut, bevor man PdfDocument#Close() aufruft, wird das PDF zwar in den Stream geschrieben, dann wird allerdings der Stream auch sofort Disposed. Das heißt die Daten sind Weg und nicht mehr lesbar. Die eine Variante, in der das auch ohne die extra Konfiguration funktioniert, ist wenn man einen FileStream benutzt. Das funktioniert deshalb, weil ein FileStream seine Daten in die dazu gehörende Datei auf dem Speichermedium schreibt, sobald sie in ihn geschrieben werden.

Jede Dokumentation, die ich gefunden habe gibt einem Beispiel-Code wie das folgende. Zu dest wird oft gesagt, dass es ein string mit einem Dateipfad sein kann. Es kann allerdings auch ein Stream sein, wie zum Beispiel HttpResponse.OutputStream oder ein MemoryStream. Gerade bei einem HTTP-Response Stream könnte es allerdings auch fatal sein, wenn dieser vorzeitig Disposed wird.

// Beispiel A: Neues PDF-Dokument erstellen
var newWriter = new PdfWriter(dest);
var newPdfDocument = new PdfDocument(newWriter);
var newDocument = new Document(newPdfDocument):
// Mach irgendetwas mit dem PDF.
newDocument.Close();

// Beispiel B: Ein bestehendes PDF-Dokument manipulieren
var existingPdfDocument = new PdfDocument(new PdfReader(src), new PdfWriter(dest));
// Mach irgendetwas mit dem PDF.
existingPdfDocument.Close();

Die Lösung

Die Lösung kam mir dann nach langem Suchen. Ich fand sie in einem Kommentar(!) zu einer Antwort auf StackOverflow: PdfWriter#SetCloseStream(false)
Diese Methode ist in der itext7-Dokumentation nicht einmal auffindbar. Selbst andere StackOverflow Fragen und Antworten oder auch andere Blogbeiträge zu diesem Thema erwähnen diese Methode nur als Randerscheinung.

Mein fertiger Code sieht jetzt in etwa so aus:

using (var pdfOutputStream = new MemoryStream())
{
    var writer = new PdfWriter(pdfOutputStream);

    // DAS HIER IST DER WICHTIGE METHODENAUFRUF!
    writer.SetCloseStream(false);

    var pdfDocument = new PdfADocument(new PdfReader(src), writer);

    // Mach irgendetwas mit dem PDF.

    // Mit diesem Methodenaufruf schreibt itext7 den PDF-Inhalt in den
    // `pdfOutputStream`. Ohne `SetCloseStream(false)` wird der Stream hier auch
    // gleich `Dispose`d.
    pdfDocument.Close();

    // Wir müssen den `Stream` auch wieder "zurück spulen", um von ihm lesen zu
    // können.
    pdfOutputStream.Seek(0, SeekOrigin.Begin);

    // Lese den `pdfOutputStream` mit irgendetwas anderem, wie zum Beispiel
    // einem Blob-Store-Client.
}

Damit habe ich erfolgreich in C# mit itext7 ein PDF in einen MemoryStream geschrieben.

]]>
.NET MAUI (Android): Location-Tracking im Hintergrund https://blecon.de/blog/arbeiten-bei-blecon/net-maui-android-location-tracking-im-hintergrund/ Thu, 17 Oct 2024 01:00:00 +0000 https://blecon.de/?p=1699 In .NET MAUI ist es sehr einach, während der Laufzeit der Anwendung auf die Positionsdaten des Benutzers zuzugreifen. Hierfür reicht ein Aufruf von

await Geolocation.GetLocationAsync(geolocationRequest, cancellationToken);

Die Abfrage der Positionsdaten, wenn die App nicht im Vordergrund ist, ist deutlich weniger trivial, da dafür via MAUI keine direkte Methodik zur Verfügung steht. Dieser Artikel zeigt, wie man trotzdem an die Positionsdaten kommt, wenn die App minimiert oder sogar geschlossen oder das Smartphone-Display ausgeschaltet ist.

Im GitHub-Repository der blecon GmbH steht ein Beispielprojekt zur Verfügung, dass das hier gezeigte Vorgehen implementiert.

LocationService

Zunächst wird ein Service erstellt, der für die tatsächliche Ermittlung der Positionsdaten zuständig ist.

public sealed class LocationService : ILocationService
{
    private readonly GeolocationRequest _geolocationRequest = new(GeolocationAccuracy.Best);

    public async Task Run(CancellationToken cancellationToken)
        => await Task.Run(async () =>
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                await Task.Delay(5000);

                var location = await Geolocation.GetLocationAsync(_geolocationRequest, cancellationToken);
                if (location is null)
                {
                    return;
                }

                WeakReferenceMessenger.Default.Send(new LocationMessage(location.Latitude, location.Longitude));
            }
        }, cancellationToken);
}

Er bietet nur eine Methode, in der in einer while-Schleife zyklisch die aktuellen Positionsdaten abgerufen werden. Diese werden über den WeakReferenceMessenger, der mit dem MVVM Toolkit kommt, an interessierte Stellen weitergeleitet.

LocationForegroundService

Um den erstellten LocationService zum Einsatz zu bringen, muss ein Android ForegroundService implementiert werden. Diese Klasse ist android-spezifisch und muss daher unter /Platforms/Android erstellt werden. Sie muss von Android.App.Service ableiten und das folgende Attribut aufweisen.

[Service(Name = "de.blecon.bglocationtracking.LocationForegroundService")]

Es müssen drei Methoden überschrieben werden:

  • OnBind
  • OnStartCommand
  • OnStopCommand

OnBind

public override IBinder? OnBind(Intent? intent) => null;

Für unsere Zwecke ist OnBind irrelevant, weshalb einfach null zurückgegeben wird.

OnStartCommand

[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(
    Intent? intent,
    [GeneratedEnum] StartCommandFlags flags,
    int startId)
{
    _cancellationTokenSource = new CancellationTokenSource();

    var notification = new NotificationHelper().GetServiceStartedNotification();

    if (Build.VERSION.SdkInt < BuildVersionCodes.Tiramisu)
    {
        StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
    }
    else
    {
        StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification, ForegroundService.TypeLocation);
    }

    Task.Run(() =>
    {
        try
        {
            var locationService = IPlatformApplication.Current?.Services.GetService<ILocationService>();
            if (locationService is null)
            {
                throw new InvalidOperationException($"Could not resolve required service of type {nameof(ILocationService)}");
            }

            locationService.Run(_cancellationTokenSource.Token).Wait();
        }
        catch (System.OperationCanceledException)
        {
            // ignore expected exception when the task is cancelled
        }
        finally
        {
            if (_cancellationTokenSource.IsCancellationRequested)
            {
                WeakReferenceMessenger.Default.Send(new StopForegroundServiceRequestedMessage());
            }
        }
    }, _cancellationTokenSource.Token);

    return StartCommandResult.Sticky;
}

In OnStartCommand wird eine Notification erzeugt (hierzu wird der ebenfalls selbst erstellte NotificationHelper verwendet), die dem Benutzer dauerhaft angezeigt wird, so lange der ForegroundService läuft. Anschließend wird der ForegroundService gestartet, was zur Anzeige der erwähnten Benachrichtigung führt. Nun wird die registrierte Instanz des zuvor erstellten und im DI-Container registrierten LocationService ermittelt und die Positionsermittlung gestartet.

OnDestroy

public override void OnDestroy()
{
    if (_cancellationTokenSource is not null)
    {
        _cancellationTokenSource.Token.ThrowIfCancellationRequested();
        _cancellationTokenSource.Cancel();
    }

    base.OnDestroy();
}

OnDestroy schließlich wird benötigt, um den LocationService zu stoppen, indem auf der klasseninternen CancellationTokenSource deren Token der Run-Methode des LocationService übergeben wurde, Cancel aufgerufen wird.

MainActivity

In der Klasse MainActivity, ebenfalls zu finden in /Platforms/Android muss die Methode OnCreate überschrieben werden. Zusätzlich werden die beiden Methoden SetServiceMethods und IsServiceRunning hinzugefügt.

OnCreate

protected override void OnCreate(Bundle? savedInstanceState)
{
    base.OnCreate(savedInstanceState);
    Platform.Init(this, savedInstanceState);

    _serviceIntent = new Intent(this, typeof(LocationForegroundService));
    SetServiceMethods();

    if (Build.VERSION.SdkInt >= BuildVersionCodes.M && !Android.Provider.Settings.CanDrawOverlays(this))
    {
        var intent = new Intent(Android.Provider.Settings.ActionManageOverlayPermission);
        intent.SetFlags(ActivityFlags.NewTask);
        StartActivity(intent);
    }
}

Hier werden das Starten und Stoppen des ForegroundService vorbereitet. Der klasseninterne Intent wird instanziiert und anschließend die Methode SetServiceMethods aufgerufen.

Der Inhalt der if-Abfrage ist für ältere Android-Versionen bzw. Systeme, auf denen keine Overlays gezeichnet werden können. Dies ist außerhalb des Scopes dieser Kurzanleitung.

SetServiceMethods

private void SetServiceMethods()
{
    WeakReferenceMessenger.Default.Register<StartForegroundServiceRequestedMessage>(this, (_, _) =>
    {
        if (!IsServiceRunning(typeof(LocationForegroundService)))
        {
            if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
            {
                StartForegroundService(_serviceIntent);
            }
            else
            {
                StartService(_serviceIntent);
            }
        }
    });

    WeakReferenceMessenger.Default.Register<StopForegroundServiceRequestedMessage>(this, (_, _) =>
    {
        if (IsServiceRunning(typeof(LocationForegroundService)))
        {
            StopService(_serviceIntent);
        }
    });
}

Hier wird erneut der WeakReferenceMessenger eingesetzt, diesmal, um Benachrichtigungen zum Starten und Stoppen des ForegroundService zu erhalten. Geht eine entsprechende Meldung ein, wird er gestartet bzw. gestoppt, allerdings jeweils nur dann, wenn die IsServiceRunning-Prüfung zuvor nicht ergibt, dass er bereits im gewünschten Zustand ist.

IsServiceRunning

private bool IsServiceRunning(Type serviceType)
{
    if (GetSystemService(ActivityService) is not ActivityManager activityManager)
    {
        return false;
    }

    // GetRunningServices is marked as deprecated but still works. May break in the future. Be aware!
    foreach (var service in activityManager.GetRunningServices(int.MaxValue)!)
    {
        if (service.Service!.ClassName == Java.Lang.Class.FromType(serviceType).CanonicalName)
        {
            return true;
        }
    }

    return false;
}

Hier wird geprüft, ob der ForegroundService aktuell läuft. Dazu wird die Methode GetRunningServices verwendet. Diese ist zwar als obsolete markiert, funktioniert allerdings noch. Zudem gibt es zur Zeit noch keinen alternativen Weg, um die erforderliche Prüfung zu machen.

AndroidManifest.xml

Unter /Platforms/Android findet sich die AndroidManifest.xml. Hier sind einige Einstellungen vorzunehmen.

<application android:allowBackup="true" android:icon="@mipmap/appicon" android:supportsRtl="true">
    <service android:name="de.blecon.bglocationtracking.LocationForegroundService"
             android:foregroundServiceType="location"
             android:exported="false" />
</application>

Damit der ForegroundService korrekt angesprochen wird, muss er im Manifest definiert werden. Hierzu wird im application-Knoten ein service-Knoten hinzugefügt. Sein Name muss dem entsprechen, der auch im Service-Attribut des LocationForegroundService angegeben wurde. Also foregroundServiceType ist in unserem Fall location zu wählen.

permissions

<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />

Um auf die Positionsdaten zugreifen zu können, sind einige Permissions nötig, die ebenfalls im Manifest hinterlegt werden müssen. Die FOREGROUND_SERVICE und FOREGROUND_SERVICE_LOCATION-Permissions werden benötigt, um den ForegroundService starten zu können. Die SYSTEM_ALERT_WINDOW-Permission schließlich wird benötigt, damit unsere App im Display over other apps-Dialog von Android erscheint und ihr das entsprechende Recht gegeben werden kann. Ohne dieses wird der ForegroundService nicht laufen.

PermissionService

Damit Positionsdaten ermittelt werden dürfen, muss der Benutzer dies explizit erlauben. Um die benötigten Berechtigungen anzufordern, wird der PermissionService verwendet.

public async Task<PermissionStatus> CheckAndRequestLocationAlwaysPermission(bool showRationale = false)
{
    var status = await Permissions.CheckStatusAsync<Permissions.LocationAlways>();
    if (status == PermissionStatus.Granted)
    {
        return status;
    }

    await Application.Current.MainPage.DisplayAlert(
        "Standortberechtigung",
        "Diese App benötigt während der Laufzeit dauerhaften Zugriff auf Ihren Standort.",
        "OK");

    return await Permissions.RequestAsync<Permissions.LocationAlways>();
}

Da für die Hintergrund-Abfrage der Positionsdaten die höchstmögliche Berechtigung aus dem Bereich Location nötig ist, ist es ausreichend, diese anzufragen. Das passiert in der Methode CheckAndRequestLocationAlwaysPermission.

Konsumieren der Positionsdaten

Da die ermittelten Positionsdaten vom LocationService über den WeakReferenceMessenger als LocationMessage versendet werden, können die Positionsdaten an jeder beliebigen Stelle in der Anwendung abgefangen werden, indem ein entsprechender Handler eingerichtet wird. Im Demo-Projekt findet sich z.B. im MainViewModel die folgende Implementierung.

private void HandleLocationMessage(object recipient, LocationMessage locationMessage)
{
    var locationDetails = $"[{DateTime.Now:HH:mm:ss}] Latitude: {locationMessage.Latitude} - Longitude: {locationMessage.Longitude}";

    LocationChanges.Add(locationDetails);
    Debug.WriteLine(locationDetails);
}

Diese sorgt dafür, dass bei jedem Eingang einer LocationMessage eine ObservableCollection<string>, die eine CollectionView speist, um die neuen Daten ergänzt wird. Zusätzlich erfolgt eine Ausgabe via Debug.WriteLine, um auch während die App minimiert oder geschlossen ist, im Debug-Output von Visual Studio sehen zu können, dass der ForegroundService noch läuft.

Vorsicht!

Durch den ForegroundService werden die Positionsdaten auch dann abgefragt, wenn die App geschlossen wurde. Ist das explizit nicht erwünscht, sollte vor Beenden der Anwendung eine StopForegroundServiceRequestedMessage gesendet werden, die von der MainActivity aufgegriffen wird und den Service beendet.

]]>