Slide 1

Slide 1 text

ASP.NET Core MVC und SignalR in Action! Einmal API mit allem, bitte. Sebastian Gingter Manuel Rauber @PhoenixHawk @ManuelRauber Consultant Consultant

Slide 2

Slide 2 text

Speakers [email protected] @manuelrauber https://manuel-rauber.com Microsoft MVP [email protected] @PhoenixHawk https://gingter.org/

Slide 3

Slide 3 text

Time Doing 09:00 – 10:30 Part I 10:30 – 11:00 ☕ 11:00 – 12:30 Part II 12:30 – 13:30 13:30 – 15:00 Part III 15:00 – 15:30 ☕ & 15:30 – 17:00 Part IV Timetable

Slide 4

Slide 4 text

• Lightweight service-based architecture • Functional services with dedicated interfaces • Use other services, like database or file system • (JSON-based) HTTPS Web APIs • Application push services via WebSocket • SignalR • Socket.io Target Architecture HTTP HTTPS WebSocket Service A Service B Service C Web APIs (ASP.NET, Node.js, …) HTML5-Application (Single-Page Application) Web Cordova Electron

Slide 5

Slide 5 text

• Functional services with dedicated interfaces • Strict REST services do not model real world • Better: Design interfaces according to use case • Single Web API can use multiple backend services • (JSON-based) HTTPS Web APIs • Embraces usage of common denominator • Content Negotation • HTTP Status Codes • Resources are mapped to URLs • Lightweight & scalable Target Architecture HTTP HTTPS WebSocket Service A Service B Service C Web APIs (ASP.NET, Node.js, …) AuthN & AuthZ Client

Slide 6

Slide 6 text

From specification to implementation .NET Standard & .NET Core

Slide 7

Slide 7 text

What exactly is it? • .NET Standard is an open source specification: https://github.com/dotnet/standard • Represents a common set of API to be implemented by all .NET platforms • .NET Standard replaces PCLs .NET Standard

Slide 8

Slide 8 text

One library to rule them all .NET tomorrow today! https://blogs.msdn.microsoft.com/dotnet/2016/09/26/introducing-net-standard/

Slide 9

Slide 9 text

.NET Core 3.0 Future

Slide 10

Slide 10 text

Overview • .NET Core is an open source implementation of the .NET Standard specification: • https://github.com/dotnet/core • Runs on Linux, macOS and Windows • CLI tools available • Supports C# and F# • Compatible to .NET Framework, Xamarin and Mono (due to .NET Standard) • Fully supported by Microsoft (LTS support three years after GA) .NET Core

Slide 11

Slide 11 text

Platform-specific APIs Some APIs are not available everywhere (e.g. Registry, Windows Identity, Reflection Emit) and will throw a PlatformNotSupportedException. .NET Core

Slide 12

Slide 12 text

IDEs .NET Core VS 2017/2019 VS Code JetBrains Rider VS for Mac

Slide 13

Slide 13 text

Use case depending alternatives • Node.js • JavaScript, TypeScript, CoffeeScript, … • Restify, Express, Koa.js • TypeORM, SequelizeJS, ORM • Node Package Manager, YARN • Java • Jersey, RESTful WebServices • Hibernate, ORM • Maven, Package Management • Ruby, Python, … .NET Core

Slide 14

Slide 14 text

Summary • Powerful language/tools and base for creating cross-platform .NET libs & apps • Good and growing API support • Targeting platform specific APIs could result in an error or conditional compilation • Cloud-ready • „No breaking changes between versions“ .NET Standard & .NET Core

Slide 15

Slide 15 text

No … No … breaking … No … breaking … changes … No … breaking … changes … between … No … breaking … changes … between … versions …

Slide 16

Slide 16 text

Ready for your next Todo App? ;-) The Sample

Slide 17

Slide 17 text

Security Token Service Identity Server Database Todo- API Push- API Realtime-Data Users Web-Server SPA (static files) Demo Architecture

Slide 18

Slide 18 text

Security Token Service Identity Server Database Todo- API Push- API Realtime-Data Users Web-Server SPA (static files) Demo Architecture

Slide 19

Slide 19 text

Demo Client Application

Slide 20

Slide 20 text

Cross-Platform Web Application & Web APIs ASP.NET Core

Slide 21

Slide 21 text

Overview • Unifies MVC and Web APIs • Built-in dependency injection • Cloud-ready configuration system • HTTP Request Pipeline • Hostable in IIS or as Self Host • Everything’s a NuGet Package • Leads to having a lot packages installed (“Hello node_modules J”) • Built on .NET Core • Open Source, https://github.com/aspnet/Home • “Can I port my application to .NET Core?” • https://icanhasdot.net/ ASP.NET Core

Slide 22

Slide 22 text

Compared to ASP.NET ASP.NET Core • Runs on Linux, macOS, Windows • C#, F# • MVC & Web API, Razor Pages • New platform, new toolings • Multiple versions per machine • MSDN: “Ultra Performance” ASP.NET • Runs on Windows • C#, F#, VB.NET • MVC, Web API, WebForms, WebPages, SignalR • Mature platform • One version per machine • MSDN: “High Performance” ASP.NET Core

Slide 23

Slide 23 text

Hosting • Kestrel: ASP.NET Core’s Web Server • IISIntegration to host in IIS • Mandatory for App Services • Specifies a class used for Startup configuration ASP.NET Core public class Program { public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup() .Build(); host.Run(); } }

Slide 24

Slide 24 text

Startup • ConfigureServices: Used for configuring the built-in dependency injection • Configure: Used for configuring the HTTP pipeline via IApplicationBuilder ASP.NET Core public class Startup { public void ConfigureServices(IServiceCollection services) { } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { } }

Slide 25

Slide 25 text

Dependency Injection • Built-in dependency injection • Constructor injection should be preferred over direct DI container access • Overriding the container is possible, e.g. to use AutoFac instead • Throws an error when a dependency could not be resolved (e.g. wrong container configuration) ASP.NET Core

Slide 26

Slide 26 text

Dependency Injection • Supports three lifetimes • Transient: Creates an instance each it is requested • Scoped: Creates an instance once per request • Singleton: Creates an instance once per application ASP.NET Core public void ConfigureServices(IServiceCollection services) { services.AddTransient(); services.AddScoped(); services.AddSingleton(); }

Slide 27

Slide 27 text

Pipeline • Customizable HTTP pipeline • Every request will run through • Order in code defines the order of the pipeline • Nesting of pipelines is possible • IApplicationBuilder is used to define the pipeline ASP.NET Core https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware public void Configure(IApplicationBuilder app) { app.UseExceptionHandler("/Home/Error"); app.UseStaticFiles(); app.UseMvcWithDefaultRoute(); } Middleware 1 // Server logic next() // more logic Middleware 2 // Server logic next() // more logic Middleware 3 // Server logic // more logic Request Response Client Logging Authentication …

Slide 28

Slide 28 text

Multiple Environments • Support multiple environments like Development, Staging or Production out-of-box • Can be set via environment variable ASPNETCORE_ENVIRONMENT • Convention based application startup • Startup, StartupDevelopment, Startup{Environment} • Careful, using webhostBuilder.UseStartup() overrides this behavior • Configure, ConfigureDevelopment, Configure{Environment} • ConfigureServices, ConfigureDevelopmentServices, Configure{Environment}Services ASP.NET Core

Slide 29

Slide 29 text

Multiple Environments IHostingEnvironment for checking environment at runtime ASP.NET Core public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment() || env.IsProduction() || env.IsStaging() || env.IsEnvironment(”MyEnv")) { } }

Slide 30

Slide 30 text

Configuration System • ConfigurationBuilder is used to define configuration sources • Order is used for configuration overriding, later defined sources override previous defined • Optional sources and sources depending on the environment are possible ASP.NET Core public Startup(IHostingEnvironment env) { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); }

Slide 31

Slide 31 text

Options Pattern • Typed (nested) Configurations • Injectable • Runtime-reloadable ASP.NET Core public void ConfigureServices(IServiceCollection services) { services.Configure(Configuration.GetSection("PushServer")); } public class PushService { private readonly PushServerSettings _config; public PushService(IOptions settingsAccessor) { _config = settingsAccessor.Value; } }

Slide 32

Slide 32 text

Authentication • Middleware within the pipeline • “Plug & Play” solutions for authentication • ASP.NET Identity • IdentityServer 4, open source project • Different authentication schemes • Cookies • Bearer • Basic • External providers • Custom ASP.NET Core

Slide 33

Slide 33 text

Controllers • Two base classes for controllers • ControllerBase: Preferred for Web APIs, offers everything except Views • Controller: Preferred for MVC, inherits from ControllerBase and adds View capabilities • Offer various methods for returning a result • Ok() / NotFound() / StatusCodeResult() • FileResult() / FileContentResult() / FileStreamResult() • Offers access to authenticated user via User property • Can be asynchronous using async/await pattern • If enabled, automatic Content Negotiation ASP.NET Core

Slide 34

Slide 34 text

Routing • Routing: Mapping URLs to actions (methods within a controller) • Routing via definition in pipeline • Routing via attributes • Routing via custom routing handler • Support for all important HTTP verbs like GET, POST, PUT, DELETE ASP.NET Core public void Configure(IApplicationBuilder app) => app.UseMvc(routes => routes.MapRoute("api", "{controller}/{action}")); [Route("customers")] public class CustomerApiController : ControllerBase { [HttpGet("{id:int}")] public IActionResult Get(int id) { } }

Slide 35

Slide 35 text

Error Handling • Provides a developer exception page with detailed information about errors • Supports error page per status code or custom error pages • Supports custom error filter per action, controller or globally ASP.NET Core public void Configure(IApplicationBuilder app) { // Use in development only app.UseDeveloperExceptionPage(); // Simple status code error pages app.UseStatusCodePages(); // Custom error handler app.UseExceptionHandler("/error"); }

Slide 36

Slide 36 text

Swagger Help Pages • NuGet: Swashbuckle.AspNetCore • Swagger: Generates a swagger.json containing all information about your Web APIs • Swagger UI: Provides a basic UI to view the swagger.json ASP.NET Core public void ConfigureServices(IServiceCollection services) { services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new Info() { Title = "Awesome Customer API", Version = "1.0" }); }); } public void Configure(IApplicationBuilder app) { app.UseSwagger(); app.UseSwaggerUI(options => { options.SwaggerEndpoint("v1/swagger.json", "API v1"); }); }

Slide 37

Slide 37 text

Swagger Help Pages ASP.NET Core

Slide 38

Slide 38 text

• Built-in logging • Third party logging solutions (e.g. Serilog, Nlog) can be easily integrated without changing the logging API Logging public class SampleController : ControllerBase { private readonly ILogger _logger; public SampleController(ILogger logger) { _logger = logger; } [HttpGet] public IActionResult Get(int listId, string listName) { _logger?.LogDebug($"{nameof(SendListCreated)}: {{ListId}}, {{ListName}}", listId, listName); // Useful code } }

Slide 39

Slide 39 text

• https://github.com/stefanprodan/AspNetCoreRateLimit • Public APIs • DDoS protection • Pay per request APIs • Rates for “expensive” resources • Rates per timeframe: Hour, Minute, Second • How? • IP-based • Account-based Rate Limiting public void ConfigureServices(IServiceCollection services) { services .Configure(Configuration.GetSection("IpRateLimiting")) .Configure(Configuration.GetSection("IpRateLimitPolicies")) .AddSingleton() .AddSingleton(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseIpRateLimiting(); }

Slide 40

Slide 40 text

• Tell client that the data did not change • HTTP Status Code 304 • Two standardized options • Last Modified Header: Did data change since …? • Etag-Header: Checksum of data • e.g.: https://github.com/KevinDockx/HttpCacheHeaders Reduce traffic Initial request GET /item/1 OK 200 Etag: 123123123123 Following request GET /item/1 If-None-Match: 123123123123 304 Not Modified

Slide 41

Slide 41 text

• Supported by all modern browsers • Supported by most servers • Reduces traffic by up to 70 % • But • more computation on server and client • is not always smaller • https://docs.microsoft.com/en-us/aspnet/core/performance/response-compression GZIP public void ConfigureServices(IServiceCollection services) { services.AddResponseCompression(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseResponseCompression(); }

Slide 42

Slide 42 text

• Via URL (api.com/v1/item/1) • Via Accept-Header • Via Custom-Header • https://github.com/Microsoft/aspnet-api-versioning Versioning public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddApiVersioning(); } } [ApiVersion("1.0")] [Route("[controller]")] public class PeopleController : Controller { [HttpGet] public IActionRoute Get() => Ok(new[] { new Person() }); }

Slide 43

Slide 43 text

• Hypermedia as the engine of application state • Navigate from anywhere to everywhere • Usage of API without prior knowledge HATEOAS

Slide 44

Slide 44 text

• Example: POST • Example: Pagination HATEOAS POST /items 201 Created Location: https://api.io/item/3 GET /items?page=1&size=10 200 OK Link: ; rel=“next”, ; rel=“last”

Slide 45

Slide 45 text

• Bi-directional real time communication server <-> client • Integrates into the whole ASP.NET Core universe (Routing, Dependency Injection) • No jQuery dependency on client-side anymore!!!!111 • Usable not only on client-side JavaScript, but in Node.js or Web Workers • Browser support: IE 11, all evergreens SignalR

Slide 46

Slide 46 text

Integrate into ASP.NET Core pipeline Add NuGet “Microsoft.AspNetCore.SignalR” (included by default) SignalR public void ConfigureServices(IServiceCollection services) { services.AddSignalR(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseSignalR(routes => { routes.MapHub("/chathub"); }); }

Slide 47

Slide 47 text

Hub • Represents a high-level pipeline allowing clients and servers to call methods on each other. • Bridges dispatching messages between client and server to easily call methods. • Strongly-typed parameters, model binding • Text protocol on JSON, binary protocol on MessagePack SignalR Hubs Endpoints Clients Transport WebSocket Server-Sent Events Long Polling Built on top of Text/Binary protocol via JSON/MessagePack public class ChatHub : Hub { public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("ReceiveMessage", user, message); } }

Slide 48

Slide 48 text

JavaScript Client • Install via NPM: @aspnet/signalr • Don’t forget CORS! • Possibility to receive and invoke methods • Third party modules for RxJS integration SignalR const connection = new signalR.HubConnection( "/chathub", { logger: signalR.LogLevel.Information }); connection.on("ReceiveMessage", (user, message) => { // Do something with the payload }); // Send something (e.g. via button) connection.invoke("SendMessage", user, message).catch(err => console.error); // Start the connection connection.start().catch(err => console.error);

Slide 49

Slide 49 text

Summary • Unifies MVC and Web APIs • Built-in dependency injection • Cloud-ready • HTTP Pipeline & Configuration System • Several hosting options • Help Pages via Swagger • Don’t forget gzip, versioning, rate limiting, … • SignalR enables real time connections for server à client communication scenarios ASP.NET Core

Slide 50

Slide 50 text

Lightweight & cross-platform data access EntityFramework Core

Slide 51

Slide 51 text

Overview • Open source implementation: https://github.com/aspnet/EntityFramework • Lightweight & cross-platform version of .NET’s full-fledged EntityFramework • Support different database providers • MS SQL • SQLite • Postgres • InMemory • Offers Commandline Tools • Code First, Database First • Migrations EntityFramework Core

Slide 52

Slide 52 text

Compared to EntityFramework 6 • EntityFramework Core does offer the following features, but some of them are still in development • Complex value types (without an ID) • Spatial data (geography, geometry) (in development) • Graphical visualization of the model (Model First) (in development) • Complex LINQ-Queries • Many-to-Many without a joining entity (in development) • Lazy Loading • Stored Procedures • Data Seeding (via model definition) • Full list available at https://docs.microsoft.com/en-us/ef/efcore-and-ef6/features EntityFramework Core

Slide 53

Slide 53 text

NuGet Package & CLI • Core Package: Microsoft.EntityFrameworkCore • Database Provider Packages • MS SQL: Microsoft.EntityFrameworkCore.SqlServer • Postgres: Npgsql.EntityFrameworkCore.PostgreSQL • SQLite: Microsoft.EntityFrameworkCore.SQLite • CLI Tools • Powershell: Microsoft.EntityFrameworkCore.Tools • cmd/bash: Microsoft.EntityFrameworkCore.Tools.DotNet • Careful: cmd/bash is not installable via NuGet, only by editing .csproj directly EntityFramework Core

Slide 54

Slide 54 text

Model • Working with EntityFramework Core is based on a model • A model is a simple class with specific attributes EntityFramework Core public class CustomerEntity { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Required] public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } }

Slide 55

Slide 55 text

Database Context • A database context (DbContext) represents a session to the database • Has one or multiple DbSet to query the database • Allows executing raw SQL queries EntityFramework Core public class SampleApplicationDbContext : DbContext { public SampleApplicationDbContext(DbContextOptions options) : base(options) { // Overriding constructor is necessary to make use of DbContextOptions } public DbSet Customers { get; set; } }

Slide 56

Slide 56 text

Database Context • DbContext can be added to the dependency injection • Services can request a DbContext via constructor injection EntityFramework Core public void ConfigureServices(IServiceCollection services) { services.AddDbContext(options => { options.UseSqlServer(Configuration.GetConnectionString("SampleApplication")); } ); } public class CustomerService { public CustomerService(SampleApplicationDbContext dbContext) { } }

Slide 57

Slide 57 text

Fluent API • Instead of using attributes to define a model, the Fluent API can be used • Fluent API has a richer API than the attributes for more complex scenarios EntityFramework Core public class SampleApplicationDbContext : DbContext { protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity() .HasKey(e => e.Id); modelBuilder.Entity() .Property(e => e.FirstName) .IsRequired(); } }

Slide 58

Slide 58 text

Querying • LINQ for database querying • Simple selects • Ordering • Grouping • Limiting • Can load related data • Eager Loading • Explicitly • Lazy Loading (soon) EntityFramework Core public class CustomerService { private readonly SampleApplicationDbContext _dbContext; public CustomerService(SampleApplicationDbContext dbContext) { _dbContext = dbContext; } public ICollection List() { return _dbContext.Customers .OrderBy(c => c.Id) .ToList(); } }

Slide 59

Slide 59 text

Saving • Tracks changes on entities per default • Writes back changes to the database when the DbContext is saved EntityFramework Core public void Update() { var entity = _dbContext.Customers.First(); entity.FirstName = "Max"; _dbContext.SaveChanges(); }

Slide 60

Slide 60 text

Saving • Related data is also saved on change tracked entities • Use AsNoTracking() when querying to not track changes, e.g. for read-only scenarios EntityFramework Core public ICollection List() { return _dbContext.Customers .AsNoTracking() .ToList(); }

Slide 61

Slide 61 text

Transactions • SaveChanges() calls done as a transaction by default • Custom transaction can be create by using DbContext.Database.BeginTransaction() EntityFramework Core using (var transaction = _dbContext.Database.BeginTransaction()) { try { _dbContext.Customers.Add(new CustomerEntity { FirstName = "Max" }); _dbContext.SaveChanges(); _dbContext.Customers.Add(new CustomerEntity { FirstName = "Erika" }); _dbContext.SaveChanges(); transaction.Commit(); } catch (Exception e) { // TODO: Handle exception } }

Slide 62

Slide 62 text

Migrations • Needs the PowerShell or cmd/bash tools installed • Add Migrations via • PowerShell: Add-Migration MigrationName • cmd/bash: dotnet ef migrations add MigrationName • Custom database initializer is needed to actually apply the migrations on startup EntityFramework Core public class DatabaseInitializer { public void Migrate() { _dbContext.Database.Migrate(); } }

Slide 63

Slide 63 text

Summary • Cross-platform version of .NET’s EntityFramework • Not all features are supported yet • Offers PowerShell and cmd/bash toolings • Supports transactions & migrations • Support multiple database providers and an InMemory database for testing EntityFramework Core

Slide 64

Slide 64 text

Better safe than sorry Unit & Integration Testing

Slide 65

Slide 65 text

Overview • Well-known „.NET toolbelt“ can be used • Xunit, Nunit • Moq • Fluent Assertions • EntityFramework Core can be mocked for unit testing • Additionally it has an in-memory provider for integration testing Unit & Integration Testing

Slide 66

Slide 66 text

Unit Testing Sample Unit & Integration Testing public class TodoServiceUnitTests { [Fact] public void GetAllLists_should_return_lists() { // in-memory sample-data data IQueryable lists = new List() { { Name = "First list" } }.AsQueryable(); var mockSet = new Mock>(); mockSet.As>().Setup(m => m.Provider).Returns(lists.Provider); // ... more mock setup var mockContext = new Mock(); mockContext.Setup(c => c.Lists).Returns(mockSet.Object); var sub = new TodoService(null, mockContext.Object); var actual = sub.GetAllLists(); actual.Should().NotBeEmpty().And.HaveCount(2); actual.First().Value.Should().Be("First list"); } }

Slide 67

Slide 67 text

The cloud is just someone else‘s computer Deployment

Slide 68

Slide 68 text

Docker • Docker is just one of multiple possibilities for deploying the application • Runs on • Microsoft Azure: Container Registry, Container Services, Container Instances • Amazon EC2 Container Services • Google Cloud Platform • IBM Bluemix Container Services • Runnable via • Simple Azure (Linux-based) Web Apps • Docker Swarm • Kubernetes Deployment

Slide 69

Slide 69 text

Docker in Azure • Multi-step Docker Image • Build Image • Runtime Image • Runtime Image will be published to container host • Fully Continuous Delivery compatible Deployment # Build Image FROM microsoft/dotnet:2.1-sdk-alpine AS build-env WORKDIR /app COPY *.csproj ./ RUN dotnet restore COPY . ./ RUN dotnet publish -c Release -o out # Build runtime image FROM microsoft/dotnet:2.1-aspnetcore-runtime-alpine WORKDIR /app COPY --from=build-env /app/out . ENTRYPOINT ["dotnet", “MyApplication.dll"]

Slide 70

Slide 70 text

Summary • .NET Standard makes it easier to create multi-targeting code (replacing PCLs) • .NET Standard 2.0 can target existing .NET code to reuse your existing business logic • ASP.NET Core provides a cross-platform possibility for MVC & Web APIs • ASP.NET Core is cloud-ready and offers a customizable HTTP pipeline • EntityFramework Core provides cross-platform and cross-database capabilities .NET Core & ASP.NET Core & EntityFramework Core

Slide 71

Slide 71 text

.NET Standard MSDN https://docs.microsoft.com/en-us/dotnet/articles/standard/library Introducing .NET Standard https://blogs.msdn.microsoft.com/dotnet/2016/09/26/introducing-net-standard/ .NET Core MSDN https://docs.microsoft.com/en-us/dotnet/articles/core/ ASP.NET Core MVC MSDN https://docs.microsoft.com/en-us/aspnet/core/mvc/overview ASP.NET Core Web API MSDN https://docs.microsoft.com/en-us/aspnet/core/mvc/web-api/ EntityFramework Core MSDN https://docs.microsoft.com/en-us/ef/ Resources

Slide 72

Slide 72 text

Thank you! Questions? Repository Sebastian Gingter Manuel Rauber @PhoenixHawk @manuelrauber Consultant Consultant https://github.com/thinktecture/api-ms-summit-spring-2019-services-dotnetcore