Azure: Attach debugger to App Service funktioniert nicht (Visual Studio 2019 V. 16.09.3)

Beim Versuch eine .NET 5 Webapplikation zu debuggen (Cloud Explorer -> App Service -> Attach Debugger) wurde mir immer folgende Meldung angezeigt:

Die Verbindung mit dem Remoteendpunkt wurde beendet.

Folgendes wurde überprüft:

  • Remotedebuggen ist aktiviert (App Service <Name> -> Konfiguration -> Allgemeine Einstellungen -> Debuggen)
  • Published wurde die “Debug” Konfiguration
  • Korrektes Target Framework eingestellt
  • App Service ist erreichbar

Ursache

Nach einer Weile recherchieren im Netz habe ich folgende Erkenntnis erlangt:

Visual Studio schickt eine Initialisierungsmeldung an den Remote Debugger. Im Inhalt sind unteranderem installierte Komponenten des VS. Es scheint, dass bei manchen VS Installationen diese Meldung die erwartete Grösse überschreitet, was dann zu einem sofortigen Abbruch führt. Gemäss Microsoft wurde dies bereits behoben im “App Service image Version 93” jedoch noch nicht weltweit verteilt. Was nun aber fortlaufen passieren soll. (24.02.2021)

Mit Hilfe von Kudu kann dies bei der Webapplikation überprüft werden. Cloud Explorer -> App Service <Name> -> Open in Kudu

Test halber habe ich einen neuen App Service-Plan mit Standort USA erstellt. Eine Testapplikation published und das Debuggen gestartet. Und es hat funktioniert. Der Azure App Service war in der Version:

Was ist nun die Lösung?

  1. Warten auf auf die “App Service image Version 93”
  2. Auf einen anderen Standort ausweichen, wenn möglich
  3. Als letzte Möglichkeit -> Als Workaround kann auch die Visual Studio Installation angepasst werden und nicht verwendete Komponenten deinstalliert werden (Habe ich selber nicht verifiziert)

Update (06.04.2021)

Das “App Service Image Version 93” ist jetzt auch an meinem verwendeten Standort angekommen und das Debuggen funktioniert wieder.

Nützliche Links

https://developercommunity.visualstudio.com/t/attach-debugger-to-azure-app-service-not-working/933126

.NET 6 Multi-platform App UI (MAUI)

Mit .NET 6 wird MAUI (Multi-platform App UI) xamarin.forms revolutionieren und die Entwicklung von “Cross-platform” Applikationen noch flexibler, produktiver und somit noch wirtschaftlicher ermöglichen.

Egal in welchem Umfeld werden bereits heute verschiedenste Plattformen (iOS, Android, Windows, Mac) eingesetzt, was zunehmend die Entwicklung von Applikationen erschwert. In vielen Betrieben wird auch das Thema BYOD (Bring Your Own Device) gefördert und sorgt dafür, dass die Plattform Vielfalt noch herausfordernder wird.

Das sind die Vorteile von .NET MAUI:

  • Free & open source
  • Cross-platform, native UI
  • Single project system, single codebase
  • Deploy to multiple devices, mobile & desktop
    • Native User Interfaces
    • Native API Access
    • Native Performance

Was heisst native UI?

Native UI heisst, egal welche Plattform ich als Benutzer verwende, ich erhalte immer die erwartete Oberfläche / Elemente (Datumspicker, Buttons, Navigation, Dark-Light Mode usw.) meiner verwendeten Plattform.

Video: The Future of Native Apps Development in .NET 6

Nützliche Links

Discord: DotNetEvolution

Xamarin

github: .NET MAUI

.NET 6.0 Preview Download

.NET 5.0 (Linux, macOS, and Windows)

Ich beschäftige mich schon eine ganze Weile mit dem .NET Framework und .NET Core, privat wie auch beruflich. Für Projekte im privaten Bereich wurde .NET für mich erst so richtig interessant, als es dank Mono möglich wurde, Programme auch auf einem Raspberry Pi auszuführen.

Mit der Einführung von .NET Core der Open Source und Cross-Plattform Version von .NET, hat Microsoft mir und einer grossen Community eine spannende Entwicklungsplattform zur Verfügung gestellt.

Was ich besonders an der .NET Plattform schätze, ist wirklich die Idee dahinter. Eine Entwicklungsplattform zur Verfügung zu haben, in der ich praktisch alle benötigten Szenarien bedienen kann. So ist es unteranderem möglich mit nur einer Entwicklungsumgebung, (Visual Studio) Desktopanwendungen, Clouddienste, Webapplikationen, Web-Services und APPS (Android, iOS) zu erstellen. (Aufzählung nicht vollständig)

Wird nun alles mit .NET 5 noch besser? Wir werden sehen, wohin diese spannende und sehr flexible Entwicklungsplattform uns führt. Erste Erfahrungen mit einer .NET 5 Webapplikation konnte ich bereits sammeln. Diese haben wir am 08.12.2020 in Betrieb genommen und sind bis jetzt nicht entäuscht worden.

Hier habe ich nun ein paar interessante Informationen rund um .NET 5 zusammen getragen:

Introducing .NET 5 (06. Mai 2019)

Introducing .NET 5

Announcing .NET 5.0 (10. November 2020)

Announcing .NET 5.0

.NET 5 verfügbar für Windows, macOS und Linux. Für x86, x64, Arm32, Arm64

.NET Conf 2020 – Keynote (12. November 2020)

.NET Conf 2020 – Das .NET Ökosystem

.NET ecosystem momentum – aus dem Video

Nützliche Links:

What’s new in .NET 5

.NET 5 Herunterladen

Free .NET Architecture Guides

.NET Channel on YouTube

.NET Foundation on YouTube

Visual Studio

Visual Studio Community

Eine Saunasteuerung von Johnny Hooyberghs – MijnSauna: .NET 5 (Docker, Webservice, Raspberry Pi)

(C / C++): Bitmanipulation mit bitweise Operatoren

Bitweises Komplement / Bitwise NOT

Der NOT-Operator (~) invertiert jedes einzelne Bit einer Zahl.

Beispiel mit 8-Bits:

 0000 0100 = 4
~0000 0100 = 1111 1011 = 251

Bitweises UND / Bitwise AND

Der AND-Operator (&) wird auf jedes einzelne Bit zwischen zwei Operanden angewendet. Das Ergebnisbit ist 1, wenn beide Bits den Wert 1 aufweisen.

Beispiel mit 4-Bits:

 0001
&1001
-----
 0001

Bitweises ODER / Bitwise OR

Der OR-Operator (|) wird auf jedes einzelne Bit zwischen zwei Operanden angewendet. Das Ergebnisbit ist 1, wenn eines der beiden Bits den Wert 1 aufweisen.

Beispiel mit 4-Bits:

 0001
|1001
-----
 1001

Bitweises exklusives ODER / Bitwise XOR

Der XOR-Operator (^) wird auf jedes einzelne Bit zwischen zwei Operanden angewendet. Das Ergebnisbit ist 1, wenn die beiden Bits unerschiedliche Werte haben.

Beispiel mit 4-Bits:

 0001
^1001
-----
 1000

Linksverschiebung / Left shift

Bei der bitweise Linksverschiebung (<<) werden alle Bits um die angegebene Position nach links verschoben.

Beispiel mit 4-Bits:

0001 << 1 = 0010
0001 << 2 = 0100

Rechtsverschiebung / Right shift

Bei der bitweise Rechtsverschiebung (>>) werden alle Bits um die angegebene Position nach rechts verschoben.

Beispiel mit 4-Bits:

0010 >> 1 = 0001
0100 >> 2 = 0001
1010 >> 1 = 0101 

Bit löschen

Will man in einem Byte mehrere Bits auf 0 setzen, wird dazu die UND-Verknüpfung verwendet.

PORTB &= ~(1 << 0)

Löscht Bit 0

Sollen gleichzeitig mehrere Bits gelöscht werden:

PORTB &= ~((1 << 0) | (1 << 2));

Löscht Bit 0 und 2 in PORTB

Bit invertieren


PORTB ^= (1 << 3);

Invertiere das dritte Bit

Bit setzen


PORTB |= (1 << 2);

Setzt das Bit 2 auf 1

Beispiel Methoden:


void set_PORTB_bit(int8_t  position, int8_t  value)
{
	// Sets or clears the bit in position 'position'
	// either high or low (1 or 0) to match 'value'.
	// Leaves all other bits in PORTB unchanged.
	
	if (value == 0)
	{
                // Set bit # 'position' low
		PORTB &= ~(1 << position);
	}
	else
	{
                // Set bit # 'position' high
		PORTB |= (1 << position);
	}
}

void set_Pin_Mode(int8_t  position, int8_t  value){
	if (value == 0)
	{
                // Set bit # 'position' to input
		DDRB  &= ~(_BV(position));
	}
	else
	{
                // Set bit # 'position' to output
		DDRB  |= (1 << position);
	}
}

Nützliche Links

mikrocontroller.net: Bitmanipulation

wikipedia: Bitweiser Operator

stackoverflow.com: How do you set, clear and toggle a single bit?

LearnCpp.Com: Bitwise operators

Logic Gate Simulator

AVR: Unterschied zwischen sleep_cpu() und sleep_mode()

Die zwei Methoden unterscheiden sich nur beim Handling des SE-Bit. Bei der Methode sleep_cpu() muss durch den Code sichergestellt werden, dass zuvor das SE-Bit gesetzt wird und nach dem Aufwachen der CPU das SE-Bit wieder gelöscht wird.

Beispiel mit sleep_cpu():


    sleep_enable();
    sleep_cpu();
    sleep_disable();

Beispiel mit sleep_mode():


    sleep_mode();

Nützliche Links

avr-libc: sleep

C#: Prüfen ob die Datenbankverbindung auf den SQL – Server verschlüsselt wird

Muss die Datenbankverbindung von einer C#-Applikation zum SQL-Server verschlüsselt werden, muss der SQL-Server mit einem Zertifikat korrekt konfiguriert sein. Im weiteren müssen im ConnenctionString Parameter konfiguriert werden, damit eine verschlüsselte Verbindung hergestellt wird. Dazu wird der ConnenctionString mit folgenden Parametern versehen:

  • encrypt=true SSL Encryption aktivieren.
  • trustServerCertificate=false Zertifikat wird validiert. (Bei self-signed Zertifikaten auf “true” setzen)

Wird nun mit der C#-Applikation eine Verbindung auf den SQL-Server hergestellt, sollte die Verbindung verschlüsselt sein. Wie kann man sich jedoch sicher sein? Eine Möglichkeit ist die Verwendung eines “Sniffers”, wie WireShark, oder aber man prüft dies auf dem SQL-Server selber.

Auf dem SQL-Server kann man folgende SQL-Abfrage absetzen, um alle Verbindungen mit ihren Verschlüsselungsoptionen anzuzeigen:


SELECT session_id,encrypt_option
FROM sys.dm_exec_connections

session_id  encrypt_option
----------- ----------------------------------------
73          TRUE
73          TRUE
73          TRUE
75          FALSE
76          FALSE

Bei den Verbindungen mit der SessionId 73 sehen wir, dass die Verschlüsselung aktiviert und verwendet wird. (encryption_option = true)

Nützliche Links

SQL Server SSL Troubleshooting Steps
Connection Properties
TrustServerCertificate Property

VBScript: Standard Pingabfrage mit WMI

Um zu überprüfen ob ein Host im Netzwerk erreichbar ist, kann man eine standard Pingabfrage verwenden.

Mit der “Win32_PingStatus WMI CLASS” bietet Microsoft die Möglichkeit eine solche standard Pingabfrage in einem VBScript zu verwenden.


Dim hostToPingFrom: hostToPingFrom= "localhost"
Dim targetIP: targetIP = 8.8.8.8

Dim cPingResults: Set cPingResults = GetObject("winmgmts:{impersonationLevel=impersonate}//" & _
hostToPingFrom & "/root/cimv2"). ExecQuery("SELECT * FROM Win32_PingStatus " & _
"WHERE Address = '" + targetIP + "'")

For Each oPingResult In cPingResults
    If oPingResult.StatusCode = 0 Then
       wscript.echo "Host is reachable"
    End if
Next

  • Zeilen 4,5,6: Verschickt die Pingabfrage
  • Zeile 8: Iterieren über die Ping-Resultate
  • Zeile 9: Ist der Statuscode 0 war das Pingkommando erfoglreich. Weitere Statuscodes werden in der Dokumentation zur “Win32_PingStatus class” beschrieben.

ping-checker.vbs

Ein kleines VBScript, das ein Ping sendet und bei einem Fehler eine Benachrichtigung als Email, über einen SMTP-Server, verschickt oder in der Windows Konsole anzeigt. Je nach Konfiguration. Dieses einfache Skript kann als Grundlage dienen, um sich ein eigenes, den Bedürfnissen angepasstes Skript zu erstellen.

ping-checker.vbs als 7zip herunterladen

ping-checker.vbs output
Der Konsolen-Output des Skriptes, da der Host 192.168.88.55 nicht erreichbar war.

Nützliche Links

Microsoft: Win32_PingStatus class
Wikipedia: Ping

Windows Installer XML (WiX)

Wurde eine neue Software entwickelt, muss diese Software noch paketiert werden. Mit Hilfe dieses Installationspaketes kann diese Software dann an die verschiedenen Windows-Clients verteilt werden. Um ein solches Installationspaket, auch Setup bezeichnet, zu erstellen gibt es verschiedene gratis und Open Source – Applikationen.

Zwei weitverbreitete Programme zum Erstellen von Windows Installationsprogramme sind NSIS und Inno Setup. Beide erstellen eine ausführbare EXE-Datei, um die Software zu installieren. Nachteil beider Installationsprogramme ist, dass sie kein standardisiertes Installationsformat verwenden. Somit ist vor der Installation nicht ersichtlich was genau installiert, beziehungsweise welche Einstellungen vorgenommen werden. Daher verwenden viele Grossfirmen lieber ein standardisiertes Format wie das „Windows Installer XML“ das durch den „Windows Installer“ bereitgestellt wird.

Der Windows Installer (vormals Microsoft Installer) stellt eine Laufzeitumgebung für Installationsroutinen unter Microsoft-Windows-Betriebssystemen bereit. Er besteht aus einem Windows-Systemdienst, welcher Paketdateien im msi-Format (Microsoft Software Installation), sowie Dateien mit den Dateiendungen mst für Transform-Dateien und msp für Patches interpretieren, entpacken und ausführen kann. [1]

Eine Programmsammlung zum Erstellen von MSI-Paketen wurde intern bei Microsoft entwickelt und später als erstes Open-Source Produkt der Firma veröffentlicht. Der Name dieser Programmsammlung ist „WiX-Toolset“. Das gesamte Installationspaket wird mit Hilfe von XML definiert. Die Einarbeitung in das „Windows Installer XML“ braucht zwar seine Zeit, wird aber durch ein praktisches GUI-Tool „WixEdit“ oder dem Visual Studio Template „Votive“ vereinfacht. Auch sehr nützlich ist das Buch von Nick Ramirez mit dem Titel „A Developer’s Guide to Windows Installer XML“.

Nützliche Links

Webseite des WiX Toolset
Webseite des WiX Edit GUI
Wikipedia: WiX
Webseite von Inno Setup
Webseite des NSIS Installer

Referenzen
[1] Wikipedia: Windows Installer

C# .NET: Erstellen einer COM-Komponente

COM-Komponenten können sowohl in Form von Laufzeitmodulen (DLL’s) als auch als ausführbare Programme implementiert werden. Damit die Funktionen der Komponente für den COM-Client sichtbar sind, müssen folgende Punkte befolgt werden:

  • Die Klasse muss „public“ sein
  • Properties, Methoden und Events müssen „public“ sein
  • Properties und Methoden müssen im Klassen-Interface definiert sein
  • Events müssen im Event-Interface definiert sein

Erstellen:

Projekteinstellungen
Projekteinstellungen

  1. Zuerst muss das COM-Interface definiert werden (Definition der Schnittstelle)
  2. Als zweiter Schritt muss die Klasse implementiert werden. Die Klasse muss den Namespace “InteropServices” importieren (using System.Runtime.InteropServices;)
  3. In den Projekteinstellungen unter „Erstellen“ muss die Option „Für COM-Interop registrieren“ sowie unter „Anwendung->Assemblyinformationen“ die Option „Assembly COM-sichtbar machen“ aktiviert werden
  4. Am Schluss muss das Assembly noch signiert werden. Dies kann in den Einstellungen unter “Signierung” gemacht werden. Dazu wird eine neue Schlüsseldatei erstellt

3. „Für COM-Interop registrieren“ Komponente lokal installieren
3. „Für COM-Interop registrieren“ Komponente lokal installieren
3. „Assembly COM-sichtbar machen“
3. „Assembly COM-sichtbar machen“
4. Assembly signieren
4. Assembly signieren


COM-Komponente registrieren:

Um die COM-Komponente auf einem anderen Gerät zu verwenden muss diese zuerst registriert werden. Dazu wird das Programm “RegAsm.exe” verwendet.


RegAsm.exe sCOMDemo.dll /codebase /tlb:sCOMDemo.tlb

COM-Komponente deregistrieren:

Bevor eine neue Version installiert wird, sollte die alte Version unregistriert werden.


RegAsm.exe sCOMDemo.dll /unregister

Beispiel Code:

Klassendiagramm
Klassendiagramm

Das Interface:



namespace sCOMDemo
{
    public interface IsCom
    {
        string helloWorld();
    }
}

Die Klasse:


using System.Runtime.InteropServices;

namespace sCOMDemo
{
    public class sCom:IsCom
    {
        public string helloWorld()
        {
            return "hello world!";
        }
    }
}

Verwendung der COM-Komponente unter VBScript:


Dim objDemo: set objDemo = createObject("sCOMDemo.sCom")
wscript.echo objDemo.HelloWorld()

wscript - Ausgabe
Nützliche Links:

Component Object Model (COM)
COM Interop Part 1: C# Client Tutorial
System.Runtime.InteropServices Namespace
How to: Create COM Wrappers
How to: Raise Events Handled by a COM Sink
Creating a COM Visible C# Component
Assembly Registration-Tool (Regasm.exe)
Wikipedia: COM

C#: XML-Serialisierung mit dem XmlSerializer Teil 3

In den vorhergehenden Beiträgen Teil 1 & Teil 2 haben wir eine Adressklasse erstellt um B2B- und B2C-Adressen zu speichern. Nun werden wir diese Adressklasse erweitern, damit auch Kommunikationsdetails (Telefon, Email, usw.) gespeichert werden können.

Als Erstes erstellen wir die Klasse “CommunicationDetail” um damit die Kommunikationsdetails zu speichern:


namespace XML_Serialisierung
{
    public class CommunicationDetail
    {
        public enum CommunicationDetailType
        {
            PRIVATE_MOBILE,
            BUSINESS_MOBILE,
            PRIVATE_PHONE,
            BUSINESS_PHONE,
            PRIVATE_FAX,
            BUSINESS_FAX,
            PRIVATE_EMAIL,
            BUSINESS_EMAIL,
            SKYPE_MESSANGER
        }

        [XmlAttribute("Typ")]
        public CommunicationDetailType DetailType { get; set; }

        [XmlElement("Wert")]
        public string Value { get; set; }

        public CommunicationDetail()
        {
        }
        public CommunicationDetail(CommunicationDetailType detailType, string value)
        {
            this.Value = value;
            this.DetailType = detailType;
        }
    }
}

Nun werden wir die Address-Klasse mit einer Liste vom Typ “CommunicationDetail” erweitern. Damit beim Serialisieren der Liste, die einzelnen Details auch richtig im XML-Abgebildet werden, verwenden wir das Attribut [XmlArray(“”)] um den Namen des Hauptelementes festzulegen und [XmlArrayItem(“”)] um damit den Namen der Unterknoten zu bestimmen.


namespace XML_Serialisierung
{
    public class Address
    {
        [XmlAttribute("Adressenummer")]
        public int AddressNumber { get; set; }
        
        [XmlElement("Strasse")]
        public string Street { get; set; }

        [XmlElement("Hausnumer")]
        public string HouseNumber { get; set; }

        [XmlElement("Land")]
        public string Country { get; set; }

        [XmlElement("Postleitzahl")]
        public string ZIP { get; set; }

        [XmlElement("Stadt")]
        public string City { get; set; }

        [XmlArray("Kommunikation")]
        [XmlArrayItem("Kommunikationsdetail")]
        public List CommunicationNumbers;


        public Address()
        {
            this.CommunicationNumbers = new List();
        }
    }
}

Klasse mit dem XmlSerializer serialisieren

Nun haben wir die Möglichkeit die Adresse mit Kommunikationsdetails zu erweitern:


/*b2c addresse*/
AddressB2C addressB2C_2 = new AddressB2C();
addressB2C_2.AddressNumber = 123456789;
addressB2C_2.Firstname = "Max";
addressB2C_2.Lastname = "Mustermann";
addressB2C_2.Street = "Musterstrasse";
addressB2C_2.HouseNumber = "77a";
addressB2C_2.City = "Musterhausen";
addressB2C_2.ZIP = "1234";
addressB2C_2.Country = "In einem fernen Land";

CommunicationDetail mobile = new CommunicationDetail(CommunicationDetail.CommunicationDetailType.PRIVATE_MOBILE, "079 123 45 67");
addressB2C_2.CommunicationNumbers.Add(mobile);

CommunicationDetail email = new CommunicationDetail(CommunicationDetail.CommunicationDetailType.PRIVATE_EMAIL, "meine@email.ch");
addressB2C_2.CommunicationNumbers.Add(email);

XmlSerializer xmls3 = new XmlSerializer(typeof(AddressB2C));
StreamWriter mwriter3 = new StreamWriter("b2cAddressWithNumbers.xml");
xmls3.Serialize(mwriter3, addressB2C_2);
mwriter3.Close();

Und als Ergebniss erhalten wir folgendes XML:




  
    
      079 123 45 67
    
    
      meine@email.ch
    
  
  Musterstrasse
  77a
  In einem fernen Land
  1234
  Musterhausen
  Max
  Mustermann

Nützliche Links:

C#: XML-Serialisierung mit dem XmlSerializer Teil 1
C#: XML-Serialisierung mit dem XmlSerializer Teil 2
msdn: xml.serialization
msdn: List