NET Core im Praxistest · • Beispiel Entity Framework Core (RC1, RC2, 1, 1.1, 1.1.1) • Und es...

Preview:

Citation preview

Senior Software Architect und Technology Advisor

Syrian Hadad

Wenn neue Technologie auf reale Anforderungen trifft

27. Juni 2017

.NET Core im Praxistest

400

Rechenzentrum Softwareentwicklung

Softwarelösungen im kantonalen Umfeld und für den Bund

1Lessons learned20’

Warum .NET Core?15’ 2 Die ersten Projekte

45’

3

Fragen und Antworten5Tipps & Tricks20’4

WARUM .NET CORE?

.NET Fairytale

.NET Fairytale

Es war einmal eine einfache, Windows-basierte Welt mit .NET

Linux-Freunde haben im 2004 veröffentlicht, es fristete jedoch lange nur ein Schattendasein

.NET für Windows aber entwickeltesich Jahr für Jahr munter weiter

Und wenn .NET nicht gestorben ist, dann lebt es noch heute…

Oder doch nicht?

• Halt, die Geschichte verlief irgendwie anders…

Es gab zwei Pfade…

j-photo-u1

Windows-onlyCross-plattform

Da gab es doch noch eine Liebeserklärung…

Es musste sich weiterentwickeln, aber wie?

Die ersten Strategien…

Was ist genau passiert?

2015 2016 2017

ASP.NET vNext ASP.NET 5

ASP.NET Core.NET Core

.NET Core 2.0.NET

Standard?

.NET Standard?

.NET Standard…

Sie mussten aber (technische) Schulden begleichen...

.NET CoreAPIs

.NET Framework APIs

SharedAPIs

Schuldenfrei

Wie wurden die Schulden beglichen?

Keine nativen GUIs wieWinForms oder WPF

ReflectionAPI umgebaut

Object.GetType() repräsentiertnicht mehr den vollen Reflection-Type

(«pay-for-play friendly»)

KeineApp Domains

«For code isolation we recommendprocesses and/or container»

Kein.NET RemotingMicrosoft emfpiehlt:

«a low-overhead plain textprotocol such as HTTP»

Keine Binary Serialisierung«[..] serialization should be a protocol

implemented on top of the available publicAPIs […] binary serialization requires intimate Knowledge […] which includes private state»

Kein SandboxingMicrosoft emfpiehlt:

«run under a user accountwith restricted permissions»

KeinSystem.Drawing

Kein:System.DataSystem.DirectoryServicesSystem.TransactionsSystem.Xml.XslSystem.Xml.SchemaSystem.Net.MailSystem.IO.PortsSystem.Workflow… Erscheinen teilweise in .NET Core 2.0

Wieso verzichtet man auf all das?

High-Performance und skalierbare Systeme

Docker Support

CLI Support (z.B. CI mit Bamboo, andere Entwicklungsumgebung)

Weil…

Und…

Cross-plattform (Tiefe Kosten im Betrieb)

Microservices Architektur

Open-Source (Tiefe Kosten in der Entwicklung)

Beweggründe der Bedag Informatik AG

Single-Page-ApplicationStrategie

Containerisierung Open-Source Strategie Betriebskosten senken

.NET Core recapC#Es kann wie gewohnt in C#, VB oder F# geschrieben werden

1

ModularLeichtgewichtig, da nur die nötigen Packages genutzt werden

2

Open-SourceDie Runtime, Libraries, Compiler, Sprachen und Tools sind alle unter GitHub publiziert

3

Cross-PlattformEinmal schreiben, überall nutzen4

Häufigere Deployments Den Puls der Weiterentwicklung

spüren, kurze Update-Zyklen8

CLIUnabhängigkeit vom Visual

Studio mit dem Command Line Interface

7

SchnellBenchmarkresultat: 8x schneller

als Node.js6

NuGetUpdates nur noch über NuGet, keine Windows Updates mehr,

dadurch entfallen die Major .NET Releases

5

.NETCore 7

6

5

4

82

3

1

C#8

DIE ERSTEN PROJEKTE

Projekte

PsyReg Online-Anmeldung

Anmeldung zur eidgenössischen

Prüfung für Gesundheitsberufe

Psychologieberuferegister

Kontext

Schichtenmodell

Screenshots

Security-Architekturcmp Security-Architektur

MedReg/Meduse Datenbank

Identity Store

MedReg Personenmodul / Meduse Web App

MedReg Web Services

Web Service Clients (MedReg)

Clients mit Webbrowser

Bedag IAM Bridge

PsyReg Web Frontend (AngularJS)

PsyReg REST Backend (.NET)

User Federation Provider

HTTPS (REST)

HTTPS (Bezug Ressourcen;Anwendung wird im Browserausgeführt)

HTTPS (Login Page)

OpenID Connect

OpenID Connect

HTTPS HTTPS

• OAuth2 und OpenID Connect• KeyCloak fungiert als Bridge• User werden in einem fremden

Identity Store gehalten• Authentifizierung Sache von

KeyCloak (Bedag IAM Bridge)• Autorisierung Sache der

Anwendung (PsyReg)

Security in .NET Core

Umgesetzt mit Middleware

Am Anfang…

• Keine Möglichkeit, OIDC out-of-the-box zu nutzen• Middleware geschrieben:

• OpenIdConnectAuthenticator• IUserInfoReader, OpenIdConnectUserInfoReaderKeycloakOpenIdConnectUserInfoReader

• Autorisierung über Attribut im Controller:

Heute möglich…

Dependency Injection

Aber: Sehr «Basic», keine attraktiven Registrierungsmöglichkeiten:

• Built-In in ASP.NET Core

Transient„[…] Created each time they are requested. [...]“

Scoped„[…] Created once per request. [...]“

Singleton„[…] Singleton lifetime services are created thefirst time they are requested [...]“

Unsere Anforderungen…

• CQRS Pattern mit ICommandHandler und IQueryHandler• Generische Registrierung aller davon implementierenden

Klassen• Eine gute Lösung musste her

Unsere Lösung:

GenericsContainer.Register(typeof(ICommandHandler<>), Assembly.Load(someAssembly));

Container.RegisterConditional(typeof(IValidator<>), typeof(LeftValidator<>), c => c.ServiceType.GetGenericArguments().Single().Namespace.Contains("Left"));Container.RegisterConditional(typeof(IValidator<>), typeof(RightValidator<>), c => c.ServiceType.GetGenericArguments().Single().Namespace.Contains("Right"));

services.AddSingleton<IControllerActivator>(new SimpleInjectorControllerActivator(Container));services.UseSimpleInjectorAspNetRequestScoping(Container);

Aktivierung sehr simpel:

Open-Source

Schnell

Testing

• NUnit wurde durch xUnit als neuer Standard in der Bedag abgelöst

• xUnit gehört zur• Wird von Microsoft eingesetzt• «Echtes» Mocking erst seit kurzem möglich

• Wegen Reflection Umbau• Zuerst mehrheitlich Integrationstests

• Nun auch Unittests mit «Moq»mailClientMock.Verify(m => m.SendMail(It.IsAny<MailContentDto>()), Times.Exactly(2));

Probleme bei den Tests

• Integrationstests aufgebaut • Kestrel In-Memory Webserver • Entity Framework Core In-Memory DB

• Aber: DB prüfte die referentielle Integrität nicht

Unsere Lösung:

• Alternative SQLite In-Memory

• Entity Framework Core hat einen SQLite Provider• Referentielle Integrität?

• Wird überprüft

var connection = new SqliteConnection("DataSource=:memory:");

Entity Framework Core

DB-First ReloadEntity

Local(Cache)

LazyLoading

DataAnnotationsValidierungen

Direkte Many-to-Many

Verbindung

Was fehlt?

Sehr schnell

Sehr (zu) schlank

Entity Framework Core kann aber…

… problemlos produktiv eingesetzt werden:• Keine Killerfeatures die fehlen• DB-First funktioniert auch mit bestehenden Tabellen

• Teilweise umständlich:

• Attribute vs. «ModelBuilder» teilweise doppelspurig und verwirrend

ASP.NET Core mit Kestrel hervorragend

Services

• Bereitstellung von SOAP out-of-the-box nicht mehr möglich

• WCF nur als Client• Verwendet für die Anbindung von

MS SQL Server Reporting Services

Mailversand

• Open-Source..• https://github.com/jstedfast/MailKit

• Sehr einfache Verwendung

System.Net.Mail fehlt, was tun?

Continuous Integration

Auftrag: CI mit und

• Bitbucket basiert auf GIT• Integration nahtlos im Visual Studio

• Ausser «Pull Requests», die funktionieren nur mit GitHub

auf deployen

Bamboo

• Agent für den Buildprozess• .NET Core SDK (für die CLI) muss auf dem Agent installiert

werden

• Danach folgt Script um Script um Script…1. «dotnet restore» (jedes einzelne Projekt…)2. «dotnet build */**/project.json» (Alle Projekte auf einmal)3. «dotnet test» (jedes Testprojekt einzeln…)4. «dotnet publish»5. «msdeploy.exe …..»

msdeploy.exe• Muss auf dem Agent installiert werden (benötigt Windows)

• Verträgt sich mit ASP.NET Core nicht so richtig• -enableRule:AppOffline funktioniert nicht (Case sensitivity Problem wegen

app_offline.htm)• https://github.com/aspnet/AspNetCoreModule/issues/50

• Unsere Lösung:

• StopAppPool

• Deploy

• StartAppPool

msdeploy -verb:sync -source:recycleApp -dest:recycleApp="abc",computerName="https://abc/msdeploy.axd?site=abc",recycleMode="StopAppPool",authType="basic",userName="*",password="*" -allowUntrusted=true

msdeploy -verb:sync -source:contentpath="C:\temp\abc" -dest:contentPath="abc",computerName=https://abc/msdeploy.axd?site=abc,username="*",password="*",authType=basic -allowUntrusted=true

msdeploy -verb:sync -source:recycleApp -dest:recycleApp="abc",computerName="https://abc/msdeploy.axd?site=abc",recycleMode="StartAppPool",authType="basic",userName="*",password="*" -allowUntrusted=true

LESSONS LEARNED

IIS und ASP.NET Core sind nicht die besten Freunde

• «Kestrel» ist eigener Webserver, IIS nur «Durchlauferhitzer» (Reverse Proxy)

Falls etwas nicht funktioniert, aktualisiere alles…

• Wenn du komische Fehler erhältst, aktualisiere alle deine NuGet-Packages…

Stell dich auf wöchentliche Updates ein…

• Beispiel Entity Framework Core (RC1, RC2, 1, 1.1, 1.1.1)

• Und es werden wirklich Fehler korrigiert…“The column prefix 't0' does not match with a table name or alias name used in the query. No column name was specified for column 1 of 't1’” mit Entity Framework Core 1.1

Mit Entity Framework Core 1.1.1 hats danach tatsächlich keinen Fehler mehr gegeben…

Halte Ausschau nach Alternativen

GDI+ oder System.Net.Mailfehlen dir?

Es gibt (fast) immer eine Alternative…

Die reelle Gefahr für einen Wildwuchs an Frameworks besteht jedoch

Verlass dich auf nichts…

Du hast dich voll auf project.json eingestellt und findest es genial?-> Microsoft wechselt es aus mit dem XML-basierten File *.csproj

Du hast eine tolle Middleware geschrieben?-> Nach einem Update (z.B. auf 1.1.1) funktioniert sie eventuell nicht mehr..

Entscheide, welche Plattform du unterstützen willst…

• Gebt die richtige «RIDs» bei den Runtimes an:

Damit «dotnet publish» auch das richtige tut..

CI ist (aktuell) hart, aber…

• Microsoft lässt «project.json» fallen• «csproj» für «msbuild» wird (wieder) eingeführt• Stufenabhängige Konfiguration für appsettings wieder

möglich• Entwicklung, Test, Produktion etc.

https://docs.microsoft.com/en-us/dotnet/core/tools/cli-msbuild-architecture

Anordnung der Middleware ist enorm wichtig

(ASP).NET Core ist einfach besser…

Gegenüber ASP.NET MVC oder WebForms professioneller, wartbarer und macht einfach mehr Spass:

DependencyInjection

Identity Kestrel ServicesLogging Options Startup

Middleware Testing Entity Framework

Core

und mehr

TIPPS & TRICKS

Hosting von ASP.NET Core auf dem IIS

• Installation vom «.NET Core Windows Server Hosting bundle»• Neustart IIS

• net stop was /y • net start w3svc

• Im Program.cs muss UseIISIntegration() ausgeführt werden:var host = new WebHostBuilder().UseKestrel().UseContentRoot(Directory.GetCurrentDirectory()).UseIISIntegration().UseStartup<Startup>().Build();

Code:

Hosting von ASP.NET Core auf dem IIS

Konfiguration:

Deployment: (dotnet publish)

ASP.NET Core auf dem IIS

• Im IIS Manager eine neue Website erstellen• Application Pool -> «No Managed Code»

• Umgebungsvariable «dotnet» muss gesetzt sein• Sonst:

IIS:

Zu beachten

Entity Framework DbSet-Naming-Problematik

• “EF Core: Table names now taken from DbSet names (starting in RC2)” https://github.com/aspnet/Announcements/issues/167

public DbSet<User> Users Tabellenname wird als «Users» erwartet

Umgehung:protected override void OnModelCreating(ModelBuilder modelBuilder){

foreach (var entity in modelBuilder.Model.GetEntityTypes()){

entity.Relational().TableName = entity.DisplayName();}

}

Entity Framework Core mit PostgreSQL

• Nuget «Npgsql»• Code kann belassen werden, wichtig aber:

protected override void OnModelCreating(ModelBuilder modelBuilder){

modelBuilder.HasPostgresExtension("uuid-ossp");}

var optionsBuilder = new DbContextOptionsBuilder();optionsBuilder.UseNpgsql("ConnectionString");

Bei der Registrierung von DI (Startup):

DbContext:

Generische Registrierung

• Wie komme ich zu den Assemblies nur meiner Projekte?Container.Register(typeof(ICommandHandler<>), Assembly.Load(assemblies?));

var libraries = from lib in DependencyContext.Default.RuntimeLibrarieswhere lib.Type == "project"select lib;

var assemblies = libraries.Select(name => Assembly.Load(new AssemblyName(name.Name)));

Macht auch Integrationstests

• In-Memory Webserver• In-Memory DB• Akzeptanzkriterien testen• Beispiel auf meinem GitHub

• syh-42

HERZLICHEN DANK FÜR DIE AUFMERKSAMKEITDIE FRAGERUNDE IST NUN ERÖFFNET…

Recommended