Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Moderne APIs mit ASP.NET Core MVC und SignalR – End-to-End

Moderne APIs mit ASP.NET Core MVC und SignalR – End-to-End

Moderne APIs bieten neben der gängigen HTTPS-Interaktion auch die Möglichkeit zur Echtzeitkommunikation auf Basis von WebSockets. Mit Hilfe von Microsofts Open-Source-Plattform ASP.NET Core MVC und SignalR lassen sich im Handumdrehen Web-APIs und Push-Services entwickeln. Doch damit nicht genug: Weitere Themen wie Security, Rate-Limiting, eine sinnvolle Dokumentation und ein vernünftiges zentralisiertes Logging sind mit von der Partie. Und jeder dieser einzelnen Bereiche bietet uns eine neue Herausforderung. Sebastian Gingter und Manuel Rauber zeigen Ihnen in diesem Workshop, wie man mit .NET Core moderne APIs auf und für verschiedene Plattformen entwickeln kann. Zusätzlich wird durch den Einsatz von Entity Framework Core die Anbindung an verschiedene Datenbanken ermöglicht. Durch den Einsatz weiterer Open-Source-Bibliotheken fürs Logging oder zur automatischen Generierung einer Swagger/OpenAPI-Dokumentation ergänzen wir die API um weitere Funktionalitäten. Eine Client-Anwendung, das Deployment auf unterschiedliche Plattformen und das Deployment in die Cloud runden den Workshop ab – vollständig End-to-End eben!

GitHub: https://github.com/thinktecture/api-ms-summit-spring-2018-services-dotnetcore

Manuel Rauber

June 13, 2018

More Decks by Manuel Rauber

Other Decks in Programming


  1. Moderne APIs – End-to-End Mit ASP.NET Core Web APIs &

    SignalR Sebastian Gingter Manuel Rauber @PhoenixHawk @ManuelRauber Consultant Consultant
  2. 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 17:00 – open end '''' Timetable
  3. • 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
  4. • 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
  5. Challenges • Mastering different kind of base class libraries •

    Hard to reuse skills • Common denominator needed for code reusage • Hard to reuse code • Fiddling with a lot of interfaces • ”Having fun with retargeting PCLs” J • Implementation needed on each platform .NET today
  6. Common denominator – Flashback 2014 .NET today Platform Code Interfaces

    All others: Shared code with platform switches
  7. Benefits • One base library to learn, not one per

    .NET platform • Easy code reuse due to a bigger API surface area • .NET standard can be updated without having all platforms to be updated • Faster and independent update cycles .NET tomorrow
  8. 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 will replace PCLs .NET Standard “.NET Standard solves the code sharing problem for .NET developers across all platforms by bringing all the APIs that you expect and love across the environments that you need: desktop applications, mobile apps & games, and cloud services.” - Immo Landwerth https://blogs.msdn.microsoft.com/dotnet/2016/09/26/introducing-net-standard/
  9. 2.0 Differences to PCLs Portable Class Libraries .NET Standard .NET

    Standard Profile A Profile B Profile C Intersection Profile: Possible Platform targets … … 1.1 1.0 Higher versions are backwards compatible to lower versions.
  10. Versioning • Additive: Higher versions incorporate all APIs from previous

    versions. • There are no breaking changes between versions • Immutable: After shipping, the version is frozen .NET Standard
  11. Versioning • Higher version • more capabilities • more APIs

    • higher code reuse • less platform support • Lower version • less capabilities • less APIs • (maybe) lower code reuse • better platform support .NET Standard
  12. Targeting • Represented by NuGet package NetStandard.Library containing assembly netstandard.dll

    • in fact: everything’s a NuGet package within the new .NET Standard world • Build Time • .NET Standard bridges references to existing .NET Framework and PCL assemblies via type forwarding • Run Time • Each platform provides an implementation for netstandard.dll that type forwards to its own implementation .NET Standard 2.0
  13. Targeting @ Build Time .NET Standard 2.0 Your .NET Standard-based

    Class Library .NET Framework or PCL netstandard.dll mscorlib.dll netstandard!Object mscorlib!Object Different Type Identities Type Forwarding https://www.slideshare.net/terrajobst/net-standard-under-the-hood
  14. Targeting @ Build Time .NET Standard 2.0 Your .NET Standard-based

    Class Library .NET Framework or PCL netstandard.dll mscorlib.dll Type Forwarding mscorlib.dll mscorlib.dll Framework Assemblies https://www.slideshare.net/terrajobst/net-standard-under-the-hood
  15. Targeting @ Run Time .NET Standard 2.0 Your .NET Application

    Framework Assemblies Your .NET Standard-based Class Library netstandard.dll Type Forwarding https://www.slideshare.net/terrajobst/net-standard-under-the-hood
  16. Platform-specific APIs • .NET Standard (mostly) contains APIs that run

    everywhere • A small subset will throw PlatformNotSupportedException • e.g. Registry, Reflection Emit, Windows Identity .NET Standard
  17. Platform-specific APIs • Conditional compilation • VS 2017 provides information

    about type availability • IDE Tool • Roslyn Analyzer to find problematic APIs • https://github.com/terrajobst/platform-compat .NET Standard #if NETSTANDARD1_3 || NETSTANDARD1_4 var code = TypeCode.Boolean; #endif
  18. Summary • Simple, yet powerful idea for creating cross-platform-targeting .NET

    libraries and applications • Good and growing API support • No breaking changes between versions • Using platform code could shrink targeting platforms • Targeting platform specific APIs could result in an error or conditional compilation .NET Standard
  19. Security Token Service Identity Server Database Todo- API Push- API

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

    Realtime-Data Users Web-Server SPA (static files) Demo Architecture
  21. 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
  22. Deployment • Offers flexible deployment possibilities • included within the

    app (self-contained deployments) • multiple versions can be installed side-by-side (framework-dependent deployments) • can be installed per user or machine-wide • Cloud-ready .NET Core
  23. Application Models • Shipped with .NET Core • Console Applications

    • Built on top of .NET Core • ASP.NET Core .NET Core
  24. 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
  25. Summary • .NET Core is an implementation of .NET Standard

    • Runs cross-platform on Linux, macOS and Windows • Can be installed side-by-side • Cloud-ready .NET Core
  26. 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
  27. Compared to ASP.NET ASP.NET Core • Runs on Linux, macOS,

    Windows • C#, F# • MVC & Web API, Razor Pages • SignalR is in development • 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
  28. 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<Startup>() .Build(); host.Run(); } }
  29. 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) { } }
  30. 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
  31. 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<IIdGenerator, IdGenerator>(); services.AddScoped<ICustomerService, DatabaseCustomerService>(); services.AddSingleton<ICacheService, InMemoryCacheService>(); }
  32. 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 …
  33. 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<Startup>() overrides this behavior • Configure, ConfigureDevelopment, Configure{Environment} • ConfigureServices, ConfigureDevelopmentServices, Configure{Environment}Services ASP.NET Core
  34. 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")) { } }
  35. 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(); }
  36. 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
  37. 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
  38. 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) { } }
  39. 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"); }
  40. 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"); }); }
  41. • 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<SampleController> _logger; public SampleController(ILogger<SampleController> logger) { _logger = logger; } [HttpGet] public IActionResult Get(int listId, string listName) { _logger?.LogDebug($"{nameof(SendListCreated)}: {{ListId}}, {{ListName}}", listId, listName); // Useful code } }
  42. • 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<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting")) .Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies")) .AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>() .AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseIpRateLimiting(); }
  43. • 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
  44. • 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(); }
  45. • 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() }); }
  46. • Hypermedia as the engine of application state • Navigate

    from anywhere to everywhere • Usage of API without prior knowledge HATEOAS
  47. • Example: POST • Example: Pagination HATEOAS POST /items 201

    Created Location: https://api.io/item/3 GET /items?page=1&size=10 200 OK Link: <https://api.io/items?page=2&size=10>; rel=“next”, <https://api.io/items?page=9&size=10>; rel=“last”
  48. • 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
  49. 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>("/chathub"); }); }
  50. 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); } }
  51. 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);
  52. 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
  53. 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
  54. 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
  55. 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
  56. 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; } }
  57. Database Context • A database context (DbContext) represents a session

    to the database • Has one or multiple DbSet<EntityClass> 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<CustomerEntity> Customers { get; set; } }
  58. 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<SampleApplicationDbContext>(options => { options.UseSqlServer(Configuration.GetConnectionString("SampleApplication")); } ); } public class CustomerService { public CustomerService(SampleApplicationDbContext dbContext) { } }
  59. 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<CustomerEntity>() .HasKey(e => e.Id); modelBuilder.Entity<CustomerEntity>() .Property(e => e.FirstName) .IsRequired(); } }
  60. 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<CustomerEntity> List() { return _dbContext.Customers .OrderBy(c => c.Id) .ToList(); } }
  61. 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(); }
  62. 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<CustomerEntity> List() { return _dbContext.Customers .AsNoTracking() .ToList(); }
  63. 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 } }
  64. 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(); } }
  65. 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
  66. 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
  67. .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
  68. Thank you! Questions? Repository Sebastian Gingter Manuel Rauber @PhoenixHawk @manuelrauber

    Consultant Consultant https://github.com/thinktecture/api-ms-summit-spring-2018-services-dotnetcore