introducing asp.net core 2.0

Post on 23-Jan-2018

587 Views

Category:

Technology

4 Downloads

Preview:

Click to see full reader

TRANSCRIPT

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Introducing ASP.NET Core 2.0

@ardalis

Ardalis.com

Steve Smith

(in about an hour)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Weekly Dev TipsPodcast and Newsletter

• Ardalis.com/tips

• WeeklyDevTips.com

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Being updated for 2.0 – should be done this month

https://www.microsoft.com/net/learn/architecture

See also AspNetCoreQuickstart.com online course

Contact me for team training and/or mentoring

Free eBook and Sample

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Agenda – My ASP.NET Core Top 10 List

1. Why ASP.NET Core?

2. Using the CLI

3. Startup

4. Managing Dependencies

5. Managing Middleware

6. ASP.NET Core MVC and Web APIs

7. Tag Helpers

8. Razor Pages

9. Testing ASP.NET Core

10. What’s New in 2.0

Full online course w/demos at:AspNetCoreQuickstart.com

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

ASP.NET Core – What is it?

A new open-source and cross-platform framework for building modern cloud-based Web applications

using .NET

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Modular – NuGet Package-based

Cloud and Container Optimized – Smaller memory footprint

Open-Source with Contributions – even the docs

Fast! - 8x Faster than Node; 3x Faster than Go

Cross-Platform – Windows, Mac, Linux

Choice of Tools and Editors – Any Text Editor plus CLI, or Visual Studio

Goals

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Install SDKhttps://www.microsoft.com/net/download/core

Optional: Install Visual Studio 2017Install VS2017 .NET Core 2.0 Tools

Confirm Version:

Getting the Bits

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Visual Studio .NET Core Templates

Console App

Class Library

Unit Test

xUnit Test

ASP.NET Core

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

ASP.NET Core Project Templates

Empty

Web API

Web App

Web App (MVC)

Angular

React

React and Redux

Docker

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

New Web Projects with dotnet

dotnet new webEmpty Hello World Project

dotnet new mvcMVC Template

--auth Individual adds identity support

--use-local-db true uses localdb instead of SQLite

dotnet new webapi

dotnet new razorpages

dotnet new angular | react | reactredux

Use --help to view options in CLI

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

dotnet CLI Templates

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

dotnet new razor

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Razor Pages

Convention-Based Routes

No Controllers; No Actions

PageModel as CodebehindHandlers replace Actions

PageModel as ViewModel

Leverages existing MVC featuresModel Binding / Validation

Routing

Filters

Maintains Testability and Separation of Concerns

More in my Razor Pages article in September 2017 MSDN Magazine

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Section

Program.cs

ASP.NET Core Startup

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

var host = new WebHostBuilder().UseKestrel().UseContentRoot(Directory.GetCurrentDirectory()).UseIISIntegration().UseStartup<Startup>().Build();

host.Run();

WebHostBuilder (1.x)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public class Program{

public static void Main(string[] args){

BuildWebHost(args).Run();}

public static IWebHost BuildWebHost(string[] args) =>WebHost.CreateDefaultBuilder(args)

.UseStartup<Startup>()

.Build();}

WebHostBuilder (2.x)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore.Http;

class Program{

static void Main(string[] args){

new WebHostBuilder().UseKestrel().Configure(a => a.Run(c => c.Response.WriteAsync("Hi!"))).Build().Run();

}}

A Minimal ASP.NET Core App

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

using Microsoft.AspNetCore.Hosting;using Microsoft.AspNetCore.Http;using Microsoft.AspNetCore.Builder;using Microsoft.AspNetCore;

public class Program{

public static void Main(){

WebHost.CreateDefaultBuilder().Configure(app =>

app.Run(async (context) =>{

await context.Response.WriteAsync("Hello World!");}))

.Build()

.Run();}

}

A Minimal ASP.NET Core App (2.0)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Section

Startup.cs

ASP.NET Core Startup

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Startup

Constructor (optional)

ConfigureServices

Configure

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Constructor (optional)

Inject Dependencies (needed by Startup)

Set up configuration (done by default in 2.0)

Set up Startup logging (done by default in 2.0)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public Startup(IHostingEnvironment env){

var builder = new ConfigurationBuilder().SetBasePath(env.ContentRootPath).AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

if (env.IsDevelopment()){

builder.AddUserSecrets<Startup>();}

builder.AddEnvironmentVariables();Configuration = builder.Build();

}

Startup Constructor (1.x)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public Startup(IConfiguration configuration){

Configuration = configuration;}

Startup Constructor (2.0)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Startup ConfigureServices

Add framework services needed by app to services collection

Add application services to services collection

Optional

Configure Options used by app components

Configure third-party containerStructureMap, Unity, Autofac, Ninject, Castle Windsor, etc.

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public void ConfigureServices(IServiceCollection services){

services.AddDbContext<ApplicationDbContext>(options =>options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

services.AddIdentity<ApplicationUser, IdentityRole>().AddEntityFrameworkStores<ApplicationDbContext>().AddDefaultTokenProviders();

services.AddMvc();

services.AddSingleton<IEmailSender, EmailSender>();}

Startup ConfigureServices (2.0)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public IServiceProvider ConfigureServices(IServiceCollection services){

services.AddDbContext<AppDbContext>(options =>options.UseInMemoryDatabase(Guid.NewGuid().ToString()));

services.AddMvc();

var container = new Container();container.Configure(config =>{

config.Scan(_ =>{

_.AssemblyContainingType(typeof(Startup)); // Web_.WithDefaultConventions();

});

config.For(typeof(IRepository<>)).Add(typeof(EfRepository<>));

config.Populate(services);});return container.GetInstance<IServiceProvider>();

}

Custom DI Container (Structuremap)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Startup.Configure

Configure the application request pipeline

Configure and arrange middleware

Optional

Configure logging for the application (done here by convention in 1.x; not required here in 2.x)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public void Configure(IApplicationBuilder app, IHostingEnvironment env){

if (env.IsDevelopment()){

app.UseDeveloperExceptionPage();app.UseBrowserLink();app.UseDatabaseErrorPage();

}else{

app.UseExceptionHandler("/Error");}

app.UseStaticFiles();app.UseAuthentication();app.UseMvc(routes =>{

routes.MapRoute(name: "default",template: "{controller}/{action=Index}/{id?}");

});}

Startup Configure (2.0)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Section

Built-in and Custom Middleware

Middleware

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

“Middleware are software components that are assembled into an application pipeline to handle requests and responses”

Each component in the pipeline is a request delegate.

Each delegate can invoke the next component in the chain, or short-circuit, returning back up the call chain

What is Middleware?

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public void Configure(IApplicationBuilder app){

// app.Run terminates the pipeline without calling any later middleware

app.Run(async context =>

{

await context.Response.WriteAsync("Hello, World!");

});}

Creating Middleware in Startup: Run

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public void Configure(IApplicationBuilder app){

// app.Use can execute code before and after other middleware

app.Use(async (context, next) =>

{

// do some work

// call the next middleware

await next.Invoke();

// do some additional work

});}

Creating Middleware in Startup: Use

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public void Configure(IApplicationBuilder app){

// app.Map can map a path to a function

app.Map(“hello”, HandleHello);

app.Run(async context =>

{

await context.Response.WriteAsync(“Invalid path!");

});}

public void HandleHello(IApplicationBuilder app){

app.Run(async context =>

{

await context.Response.WriteAsync(“Hello!");

});}

Creating Middleware in Startup: Map

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public class MyMiddleware{private readonly RequestDelegate _next;public MyMiddleware(RequestDelegate next){_next = next;

}public Task Invoke(HttpContext httpContext){return _next(httpContext);

}}

// Extension method used to add the middleware to the HTTP request pipeline.public static class MyMiddlewareExtensions{public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder){return builder.UseMiddleware<MyMiddleware>();

}}

Moving Middleware to its own classes

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Built-in Middleware : Diagnostics

UseDeveloperExceptionPage

UseDatabaseErrorPage – helps configure database

UseBrowserLink

UseExceptionHandler

UseStatusCodePages

UseWelcomePage

UseElmPage / UseElmCapture (preview)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Built-in Middleware

UseIdentity (UseAuthentication in 2.0)

UseStaticFiles

UseDefaultFiles

UseDirectoryBrowser (requires services)

UseFileServer (replaces/combines previous three)

UseRouter

UseMvc (replaces/wraps UseRouter; requires services)

UseRewriter (1.1)

UseResponseCompression (1.1)

UseResponseCaching (1.1, requires services)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Project Dependencies (1.x)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

New Project Dependencies (2.0)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

<Project Sdk="Microsoft.NET.Sdk.Web"><PropertyGroup><TargetFramework>netcoreapp2.0</TargetFramework><UserSecretsId>aspnet-NewIn2-718CDB27-A711-46D2-8222-38EB73FC1D4B</UserSecretsId>

</PropertyGroup><ItemGroup><PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /><PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0"

PrivateAssets="All" /><PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.0.0"

PrivateAssets="All" /></ItemGroup><ItemGroup><DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" /><DotNetCliToolReference Include="Microsoft.Extensions.SecretManager.Tools" Version="2.0.0" /><DotNetCliToolReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.0"

/></ItemGroup><ItemGroup><ProjectReference Include="..\NewIn2.Core\NewIn2.Core.csproj" />

</ItemGroup></Project>

Typical Project File (2.x)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Section

Keeping Code Modular and Loosely Coupled

Injecting Dependencies in ASP.NET Core

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Dependency Injection (DI)

Classes request dependencies instead of referencing directly

Dependent object instances are injected as parameters (or properties)

Allows for flexibility and modularity

Classes follow Explicit Dependencies Principle, Dependency Inversion Principle

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Explicit Dependencies Principle

Classes should express their requirements through their constructor

Direct use of specific collaborators creates hidden dependencies

Classes with hidden dependencies aren’t “honest” about what they require

Constructor should be a contract that specifies what the class requires

Learn more: http://deviq.com/explicit-dependencies-principle/

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Section

ASP.NET Core MVC(and Web APIs – they are ONE THING now!)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Controllers and Actions

Controllers are collections of actionsUseful for grouping actions into cohesive sets

Used by default for routing and URL generation (e.g. /{controllername}/{actioname})

Actions are methods that handle individual requestsEach request is routed to an action method

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

An MVC Action

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

public async Task OnGetAsync(string returnUrl = null){

if (!string.IsNullOrEmpty(ErrorMessage)){

ModelState.AddModelError(string.Empty, ErrorMessage);}

ExternalLogins = (await_signInManager.GetExternalAuthenticationSchemesAsync()).ToList();

ReturnUrl = returnUrl;}

Razor Pages Entry Point

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Routing to Actions

Default route specified in Startup Configure method

Attribute routing (at Controller and/or Action level)[Route(“products/index”)]

[Route(“products/update/{id})]

[Route(“home”)] on Controller and [Route(“about”)] on Action are combined into “home/about” route

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Attribute Routing Tips

Use default convention where possible

Define routes using attributes for non-default cases, especially for APIs

APIs should use HTTP verb attributes to define routes:[HttpGet]

[HttpGet(“{id}”)] // will combine with route specified on controller

Routes can use token replacement for [area], [controller], [action]:[Route(“[controller]/[action]”)]

Especially powerful when used with inheritance:[Route(“api/[controller]/[action]”)]public abstract class BaseApiController : Controller

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Accepting Data in Actions (Model Binding)

MVC uses model binding to convert data sent by requests into action parameters

Model binding takes place before the action is invoked

Parameters may be simple types, or complex objects

Data can come from named form values, route components, or query strings

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Model Validation

Model types can have validation rules specifiedActions should check model validation state before making changes to application state

if(ModelState.IsValid)

Avoid using data model types for model bindingThis can result in exposing more data to user changes than intended

Use [FromBody] to bind to data in the body of the request (JSON by default)

Use [BindProperty] to bind properties to non-GET requests (2.0)

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Tag Helpers

Replaces HTML Helpers (still available, but not recommended)

Render within HTML tags

Declarative, not Imperative

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Tag Helper Example

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Tag Helper Example

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Working With a Database Using EF Core

Add Entity Framework Core (EF Core) in ConfigureServices:

Also supports InMemory – Install this package:

and modify ConfigureServices:

services.AddDbContext<AppDbContext>(options =>options.UseInMemoryDatabase(“DbName”));

//options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Working with EF Core’s AppDbContext

Never directly instantiate your application’s DbContext type(s)

Instead, request from DI using constructor parameters

Recommendation

Follow the Dependency Inversion Principle and avoid having UI types depend on details

Using Entity Framework Core is an implementation detail

Instead depend on an abstraction over your persistence method

Common pattern for this: Repository

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Section

Testing ASP.NET Core AppsOne of my favorite new features!

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Configuring a TestServer

Use a WebHostBuilder

Configure like in your web projectModify for testing if necessary

Create a TestServer from this builder instance

Create an HttpClient using CreateClient()

Make requests to the app using the client instance

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Functional Testing ASP.NET Core Apps

Make a request using the HttpClient instance

Capture the response

Verify status code

Deserialize if necessary

Assert that the result included the values you expected

APIs are easy; views require a little more work to configure for testing

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

[Fact]public async Task ReturnTwoItems(){

var response = await _client.GetAsync("/api/todoitems");response.EnsureSuccessStatusCode();var stringResponse = await response.Content.ReadAsStringAsync();var result = JsonConvert.DeserializeObject<IEnumerable<ToDoItem>>

(stringResponse).ToList();

Assert.Equal(2, result.Count());Assert.Equal(1, result.Count(a => a.Title == "Test Item 1"));Assert.Equal(1, result.Count(a => a.Title == "Test Item 2"));

}

A Functional Test

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

protected HttpClient GetClient(){

var builder = new WebHostBuilder().UseContentRoot(Directory.GetCurrentDirectory()).UseStartup<Startup>().UseEnvironment("Testing"); // ensure ConfigureTesting is called in Startup

var server = new TestServer(builder);var client = server.CreateClient();

// client always expects json resultsclient.DefaultRequestHeaders.Clear();client.DefaultRequestHeaders.Accept.Add(

new MediaTypeWithQualityHeaderValue("application/json"));

return client;}

Configurating the Client

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Runtime Store – Precompiles meta-package and eliminates need to deploy its packages

.NET Standard 2.0 – Much larger BCL available cross-platform

DI-Enabled Authentication

Kestrel improvements – now supports edge (Internet-facing) deployment

Hosting environment can inject dependencies and code into apps

Automatic CSRF protection

Automatic Razor view compilation

New Tag Helper Components

IHostedService – start/stop services when application starts/stops

VB support (console, class libraries)

EF Core Owned Entities, Global filters, DbContext Pooling

More New Stuff in 2.0

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Demonstration

Razor Pagesand

EF Core New Features

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

Migration from 1.x to 2.0 Tips1. Update TargetFramework to netcoreapp2.0

2. Update global.json to version 2.0.0 (if used)

3. Update package references. Use new MS.AspNetCore.All 2.0.0 package. Includes EF Core 2.0.

4. Update other packages to 2.0.0 if needed.

5. Update .NET Core CLI Tools

6. Change PackageTargetFallback to AssetTargetFallback

7. Update Main in Program.cs

8. Make sure you're not doing DB setup in Startup.Configure. Move it to Main in Program.cs.

9. Remove MvcRazorCompileOnPublish = true from .csproj files -- it is now on by default. If targeting .NET Framework, need to reference ViewCompilation package.

10. If you're not explicitly using App Insights, remove from .csproj, program.cs, and your _Layout file.

11. Migrate Auth/Identity to 2.0

No Content Here(Reserved for Watermark)

Copyright © 2016, DevIQ, Inc.

ASP.NET Core is the future of Microsoft’s platform

Lots of cool demos I didn’t have time to show.

Check out AspNetCoreQuickstart.com

Use qltechcon2017 for 20% off

Subscribe to WeeklyDevTips.com

Connect with me on Twitter: @ardalis

Thanks!

Summary

top related