Fortuna Entwickler Blog

Hier wird Ihnen geholfen

Design Projekt .NET Core Web API

Um in der Zukunft einen einheitlichen Aufbau aller Projekte zu haben, wird hier ein Beispielaufbau einer Anwendung erklärt. Alle Angaben beziehen sich auf .NET Core Web APIs.

Aufbau Struktur

In jedem Projekt sollte es folgende Struktur geben:
  • Controllers => Beinhaltet jegliche Logik zu den Endpoints
  • Services => Beinhaltet jegliche Logik zur Verarbeitung der Daten (Anfragen an Datenbank, Manipulation von Daten, Anfrage an andere APIs usw.)
  • Mappings (wenn gebraucht) => Automapper Konfiguration Dateien
  • Resources (wenn gebraucht) => alle Projektspezifischen Ressourcen wie AppSettings Konfigurations Model 
  • Interfaces (wenn gebraucht) => Selbsterklärend
  • Extensions (wenn gebraucht) => Selbsterklärend
  • Models (wenn gebraucht)  => Selbsterklärend

Folgende Nuget-Pakete sollten in allen Anwendungen installiert sein:

Damit alle Pakete korrekt funktionieren müssen folgende Dinge in das Programm eingebaut werden.

Microsoft.AspNetCore.Mvc.NewtonsoftJson
Folgendes muss unter in der Startup.cs Datei in der Methode ConfigureServices reingeschrieben werden. Dies setzt die neue JSON Libary fest.


Swashbuckle.AspNetCore

Um Swagger nutzen zu können muss an zwei verschiedenen Stellen in der Startup.cs Datei Code eingefügt werden.

Zuerst in der ConfigureServices Methode nach der AddControllers Funktion muss Swagger hinzugefügt werden.

Danach muss Swagger noch aktiviert werden, dazu muss in der Configure Methode folgendes geschrieben werden.

Hier sind vor allem die Zeilen 35-39 wichtig. Der Aufbau der restlichen Zeilen kann aber übernommen werden. Hier gilt zu beachten, dass, dass der Name der API jeweils angepasst wird.

NLog NLog.Web.AspNetCore

http://webentw4/Blog/post/2020/05/12/nlog-in-in-asp-net-core-einbinden


ContentTypes

Die ContentTypes werden zentral in der Startup.cs eingestellt. Die meiste Zeit wird nur application/json benötigt. Sollten weitere benötigt werden, muss geschaut werden, ob diese zentral eingestellt werden oder nur für eine bestimmte Funktion. Zu beachten ist, wenn die ContentTypes überschrieben werden müssen an der Funktion dann alle angegeben werden.

Aufbau des Controllers

Ein Controller dient als Sammelstelle aller Endpoints. Hier ist nochmal zu erwähnen, jegliche Logik sollte in die Services geschrieben werden und nur der Zugriff auf die Services bzw. auf die Endpoints sollte im Controller beschrieben werden.

Im ersten Schritt sollte ein BaseController implementiert werden. Dieser beinhaltet alle allgemein gültigen Funktionen zur Verarbeitung von HTTP Requests bzw. Responses.


Der BaseController sollte zwingend die HandleError Methode besitzen, damit alle Fehler geloggt werden. Außerdem ist wichtig, dass der Controller mit dem Attribute ApiController ausgestattet wird, damit beim Kompilieren erkannt wird, dass alle zu erbenden Klassen bzw. Controller Teil der API sind.

Wird dann ein Blick auf die "richtigen" Controller geworfen, müssen ein paar Dinge erledigt werden. Zuerst muss die Route bestimmt werden. Diese wird mit api/[controller] angegeben. Daraus resultiert in dem Fall immer der Pfad api/vertrag/xxx. Dies hat den Vorteil, dass wir nicht in jeder Funktion gewisse Teile des Pfads doppelt schreiben müssen. 
Darüber hinaus muss der Logger und die benötigten Services per Dependency injection eingebunden werden.


Aufbau eines Endpoints

Alle Endpoints sollten folgenden Aufbau besitzen:

  • Http Request Methode mit Pfad => Funktionsname bzw. Abwandlung angeben und jeweilige Parameter mit Datentypen
  • Consume/Produces Types => Content-Types => In der Regel brauchen wir nur application/json (allgemein) => Diese werden vorher zentral in der Startup.cs eingestellt und nur genauer angegeben, wenn zusätzliche fehlen
  • ProducesResponseType => Rein zu Dokumentationszwecken gedacht, aber sinnvoll zum testen => Alle Rückgabetypen mit Statuscodes eintragen
  • Rückgabetyp => Sollte eigentlich immer IActionResult sein, da wir unterschiedliche Rückgabetypen haben wie unter ProducesResponseType zu sehen ist, außer bei asynchronen Aufrufen, dann sollte es Task<IActionResult> sein
  • Funktionsname => Titel der Funktion, wenn asynchron an den Namen immer ein Async anhängen
  • Try-Catch-HandleError => Für unerwartete Fehler wie z.B. in der Datenbank 

Ergebnisse Workshop 14./15. November 2017

nuGet packages

Es ist nicht sinnvoll, nuGet Packages in unsere Release-Zyklen einzubinden; dies widerspricht dem eigentlichen Sinn der nuGet Packages.

In einem Package sollen Funktionen umgesetzt werden, welche Produktunabhängig sind und allgemein Verwendet werden können, z.B. Mailversand, PDF Erstellung und Ähnliches

Empfehlung Herr Schmidt: 

Rückführung Produktspezifischer Packages in die jeweiligen Solutions

Neustrukturierung der Ordnerstruktur für Solutions

Alle Solutions in einem Ordner

Alle Webanwendungen in einem eigenen Ordner in einem Unterordner (‚web‘)

Alle Bibliotheken in einem eigenen Ordner in einigen wenigen Unterordnern (‚logic‘, ‚data‘)

Damit dann Kombination aus nuGet und Bibliotheken

Builds für Projekte automatisieren

Builds für nuGet Packages erstellen Symbole für Debugging, welche vorgehalten werden


Branches, Merges, etc.

Der aktuelle Stand kann so weiter geführt werden.

Das Verschieben von Branches kann möglicherweise in Zukunft wieder verfügbar sein. Derzeit gibt es keine andere Möglichkeit, als es so zu tun, wie wir es derzeit machen.

Herr Schmitt hat uns Alternativen zur derzeitigen Vorgehensweise aufgezeigt. Diese wären gggf. Zu diskutieren.


Event- und Fehlerlogging

Das Logging, so wie wir es derzeit betreiben ist weder performant noch sonst zu empfehlen.

Empfehlung Herr Schmidt: 

Einsatz von NLog

Umstellung aller Anwendungen auf einen Asynchronen Logger

Logging gegen einen WebService (in Azure)

Archivierung von Logs in Azure Storage

Ggf. Automatisiertes Herunterladen aus Azure Storage


Benutzer, Security

Eine eigene Benutzerverwaltung ist aufwendig, fehleranfällig und nur schwer abzusichern.

Empfehlung Herr Schmidt:

Microsoft Azure Active Directory

Vergleichsweise einfache Integration in bestehende Webanwendungen

Keine Verwendung mit VENTA möglich

�� Derzeit nur für Versicherungskunden

Integration in Azure Service Management, um APIs abzusichern (myPension z.B.)


Swagger

Der Einsatz von Swagger, so wie es derzeit bei uns verwendet wird, entspricht vorgesehenen Verwendung. Keine ToDos.


Oracle / Entities

Oracle ODP.NET ist nicht empfehlenswert, weil vergleichsweise langsam und schlechte Tool-Unterstützung.

DevArt for Oracle ist das Tool der Wahl für den Zugriff auf Oracle Datenbanken via Entities. Der fehlende Service seitens DevArt muss selbst geleistet werden: Neue Versionen als nuGet zur Verfügung stellen, eigene Versionshistorie vorhalten.


Sonstiges

Herr Schmitt empfiehlt die Anbindung unseres AD an Azure AD.

C# 7.0/8.0 bringt wenig sinnvolles Neues, was wir nicht schon kennen

ASP.NET Core bringt für uns keine Vorteile, solange wir nicht mit Docker und/oder anderen Betriebssystemen arbeiten.

Angular.js (oder React.js oder Vue) sind Frameworks, die interessant sein können und gesondert betrachtet werden müssten.

TypeScript als Ersatz für JavaScript ist empfehlenswert.

JavaScript in Webseiten selbst sollte überhaupt nicht benutzt werden, sondern immer in eigene Dateien (dann auch als TypeScript) ausgelagert werden.


Fotos


Themen_Workshop.pptx (578,3KB)