https://aka.ms/aspnetcore-makeover ## [Slides](https://www.slideshare.net/jongalloway/aspnet-core-one-hour-makeover-147543558) ## Outline * Intro (goals/non-goals/what you'll learn) * Pick The Right Starting Template * Web Application (no auth) * Web API * SPA * Other templates (teaser) * Source Control and Solution Structure * editorconfig * gitignore * Maintainability * Tests * Health Checks * Debug Footer * Front End * Bootstrap * Front end build? * [Libman](https://docs.microsoft.com/en-us/aspnet/core/client-side/libman/libman-vs?view=aspnetcore-2.2) * SEO * Performance (no way we'll get to this in 50 minutes...) * ANCM * Tiered Compilation * Language feature opt-in * Caching * Miniprofiler * Creating your own templates ## Code Snippets ### FunctionalTests.cs ```csharp using Microsoft.AspNetCore.Mvc.Testing; using OneHour.Web; using System; using System.Threading.Tasks; using Xunit; namespace WebApp.Tests { public class BasicTests : IClassFixture> { private readonly WebApplicationFactory _factory; public BasicTests(WebApplicationFactory factory) { _factory = factory; } [Theory] [InlineData("/")] [InlineData("/Index")] [InlineData("/Privacy")] public async Task Get_EndpointsReturnSuccessAndCorrectContentType(string url) { // Arrange var client = _factory.CreateClient(); // Act var response = await client.GetAsync(url); // Assert response.EnsureSuccessStatusCode(); // Status Code 200-299 Assert.Equal("text/html; charset=utf-8", response.Content.Headers.ContentType.ToString()); } [Fact] public async Task Get_HealthCheckReturnsHealthy() { // Arrange var client = _factory.CreateClient(); // Act var response = await client.GetAsync("/health"); // Assert response.EnsureSuccessStatusCode(); // Status Code 200-299 Assert.Equal("Healthy", response.Content.ReadAsStringAsync().Result); } } } ``` ### libman.json ```json { "version": "1.0", "defaultProvider": "cdnjs", "libraries": [ { "library": "jquery@3.3.1", "files": [ "jquery.min.js", "jquery.js", "jquery.min.map" ], "destination": "wwwroot/lib/jquery/dist" }, { "provider": "unpkg", "library": "bootstrap@4.1.3", "destination": "wwwroot/lib/bootstrap/", "files": [ "dist/css/bootstrap.css", "dist/css/bootstrap-grid.css", "dist/css/bootstrap-reboot.css", "dist/js/bootstrap.js" ] }, { "provider": "unpkg", "library": "ionicons@4.5.5", "destination": "wwwroot/lib/ionicons", "files": [ "dist/css/ionicons.min.css" ] } ] } ``` ### Sitemap Extension ```csharp using Ducksoft.NetCore.Razor.Sitemap.Models; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; namespace OneHour.Web.Utility { public static class SitemapExtensions { public static IServiceCollection ConfigureMvcRazorPages(this IServiceCollection services, CompatibilityVersion version, string startPageUrl = "", string startPageArea = "") { services.AddMvc() .SetCompatibilityVersion(version) .AddRazorPagesOptions(options => { var isSupportAreas = !string.IsNullOrWhiteSpace(startPageArea); options.AllowAreas = isSupportAreas; options.AllowMappingHeadRequestsToGetHandler = true; if (isSupportAreas) { options.Conventions.AddAreaPageRoute(startPageArea, startPageUrl, string.Empty); } else if (!string.IsNullOrWhiteSpace(startPageUrl)) { options.Conventions.AddPageRoute(startPageUrl, string.Empty); } }) .AddRazorPagesOptions(options => { options.Conventions.Add(new SitemapRouteConvention()); }) .AddRazorPagesOptions(options => { options.Conventions.AddPageRoute("/Sitemap", "sitemap.xml"); }); return services; } } } ``` ### .template.config/template.json ```json { "$schema": "http://json.schemastore.org/template", "author": "YOUR NAME", "classifications": [ "ASP.NET Core", "Solution" ], "identity": "[YOUR NAME].AspNetCoreSolutionTemplateTemplate.CSharp", "name": "ASP.NET Core One Hour", "shortName": "aspnetonehour", "sourceName": "OneHour" } ``` ## References and Other Good Stuff ### An Opinionated Approach to ASP.NET Core (Scott Allen) * [An Opinionated Approach to ASP.NET Core - NDC - YouTube](https://www.youtube.com/watch?v=qxb62AErRWw) * [.NET Core Opinion #1 - Structuring a Repository](https://odetocode.com/blogs/scott/archive/2018/08/28/net-core-opinion-1-structuring-a-repository.aspx) * [.NET Core Opinion #2 - Managing a Repository Structure](https://odetocode.com/blogs/scott/archive/2018/09/06/net-core-opinion-2-ndash-managing-a-repository-structure.aspx) * [.NET Core Opinion #3 - Other Folders To Include in the Source Repository](https://odetocode.com/blogs/scott/archive/2018/09/13/net-core-opinion-3-ndash-other-folders-to-include.aspx) * [.NET Core Opinion #4 - Increase Productivity with Dev Scripts](https://odetocode.com/blogs/scott/archive/2018/09/21/net-core-opinion-4-ndash-increase-productivity-with-dev.aspx) * [.NET Core Opinion #5 - Deployment Scripts and Templates](https://odetocode.com/blogs/scott/archive/2018/10/17/net-core-opinion-5-deployment-scripts-and-templates.aspx) * [.NET Core Opinion #6 - Be Wary of GUI Build Tools](https://odetocode.com/blogs/scott/archive/2018/10/29/net-core-opinion-6-ndash-be-wary-of-gui.aspx) * [Community blogger's transcription](https://codingblast.com/asp-net-core-best-practices/) ### Grab Bag * [ASP.NET Core 2.2 Goes Bootstrap 4](https://www.telerik.com/blogs/aspnet-core-22-goes-bootstrap-4) * [ASP.NET Core Architect David Fowler's Hidden Gems in 2.1](https://www.hanselman.com/blog/ASPNETCoreArchitectDavidFowlersHiddenGemsIn21.aspx) ### Existing Template Solutions * [ASP.NET Boilerplate](https://aspnetboilerplate.com/) * [.NET Boxed](https://github.com/Dotnet-Boxed/Templates/blob/master/Docs/API.md) ### Stuff I Wish I'd Had Time For * [Dev Adventures .NET Core project setup. - Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=dnikolovv.dev-adventures-project-setup) * [dotnet templates](https://dotnetnew.azurewebsites.net/) * [madskristensen/PhotoGallery: ASP.NET Core Photo Gallery](https://github.com/madskristensen/PhotoGallery) * [madskristensen/AspNetCoreTemplatePack](https://github.com/madskristensen/AspNetCoreTemplatePack) * [Custom templates for dotnet new - .NET Core CLI ](https://docs.microsoft.com/en-us/dotnet/core/tools/custom-templates) * [Xabaril/AspNetCore.Diagnostics.HealthChecks: Enterprise HealthChecks for ASP.NET Core Diagnostics Package](https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks) * [Web Applications with ASP.NET Core Architecture and Patterns guidance (Updated for .NET Core 2.0) ](https://blogs.msdn.microsoft.com/dotnet/2017/08/09/web-apps-aspnetcore-architecture-guidance/) * [ASP.NET Core - Best practices (tips and tricks) - an opinionated approach - Part 1 ](https://www.codementor.io/ibrahimsuta/asp-net-core-best-practices-tips-and-tricks-an-opinionated-approach-part-1-ffpj26mju) * [ASP.NET Core Best Practices Archives - CodingBlast](https://codingblast.com/tag/asp-net-core-best-practices/) * [Top 13 ASP.NET Core Features You Need to Know](https://stackify.com/asp-net-core-features/) * [gothinkster/aspnetcore-realworld-example-app: ASP.NET Core backend implementation for RealWorld](https://github.com/gothinkster/aspnetcore-realworld-example-app) * [Cache in-memory in ASP.NET Core ](https://docs.microsoft.com/en-us/aspnet/core/performance/caching/memory?view=aspnetcore-2.2) * [VahidN/EFSecondLevelCache.Core: Entity Framework Core Second Level Caching Library](https://github.com/VahidN/EFSecondLevelCache.Core/) * [SteffenMangold/EntityFrameworkCore.Cacheable: EntityFrameworkCore second level cache](https://github.com/SteffenMangold/EntityFrameworkCore.Cacheable) * [dotnet-architecture/eShopOnWeb: Sample ASP.NET Core 2.1 reference application, powered by Microsoft, demonstrating a layered application architecture with monolithic deployment model. Download 130+ page eBook PDF from docs folder.](https://github.com/dotnet-architecture/eShopOnWeb) * [MiniProfiler for .NET : ASP.NET Core](https://miniprofiler.com/dotnet/AspDotNetCore) * [ASP.NET Core Best Practices - Opinionated Approach - CodingBlast](https://codingblast.com/asp-net-core-best-practices/) * [url redirection - Redirect asp.net core 2.0 urls to lowercase - Stack Overflow](https://stackoverflow.com/questions/48469342/redirect-asp-net-core-2-0-urls-to-lowercase?noredirect=1&lq=1) * AddOptions (strongly typed) * https://github.com/AArnott/Nerdbank.GitVersioning/blob/master/doc/dotnet.md * https://dotnetthoughts.net/how-to-display-app-version-in-aspnet-core/ * https://github.com/JosephWoodward/GlobalExceptionHandlerDotNet * https://nugetmusthaves.com/Category/ASP.NET?page=4 * https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.2 * https://docs.microsoft.com/en-us/aspnet/core/performance/performance-best-practices?view=aspnetcore-2.2