diff --git a/docs/architecture/blazor-for-web-forms-developers/app-startup.md b/docs/architecture/blazor-for-web-forms-developers/app-startup.md index 6fb76e5fd032f..e662ce9ddd0a5 100644 --- a/docs/architecture/blazor-for-web-forms-developers/app-startup.md +++ b/docs/architecture/blazor-for-web-forms-developers/app-startup.md @@ -3,7 +3,7 @@ title: App startup description: Learn how to define the startup logic for your app. author: csharpfritz ms.author: jefritz -ms.date: 11/20/2020 +ms.date: 12/2/2021 --- # App startup @@ -11,7 +11,7 @@ Applications that are written for ASP.NET typically have a `global.asax.cs` file ## Application_Start and Web Forms -The default web forms `Application_Start` method has grown in purpose over years to handle many configuration tasks. A fresh web forms project with the default template in Visual Studio 2019 now contains the following configuration logic: +The default web forms `Application_Start` method has grown in purpose over years to handle many configuration tasks. A fresh web forms project with the default template in Visual Studio 2022 now contains the following configuration logic: - `RouteConfig` - Application URL routing - `BundleConfig` - CSS and JavaScript bundling and minification @@ -22,60 +22,64 @@ With ASP.NET Core and Blazor, these methods are either simplified and consolidat ## Blazor Server Startup Structure -Blazor Server applications reside on top of an ASP.NET Core 3.0 or later version. ASP.NET Core web applications are configured through a pair of methods in the `Startup.cs` class on the root folder of the application. The Startup class's default content is listed below +Blazor Server applications reside on top of an ASP.NET Core 3.0 or later version. ASP.NET Core web applications are configured using a builder defined in *Program.cs* and optionally a `Startup` class defined in *Startup.cs*. Starting in .NET 6, the default choice is to set up the app in a single *Program.cs* file (but using a `Startup` class remains supported). + +In *Program.cs*, you configure the app's required services by adding them to the built-in services container and then set up the app's HTTP request pipeline. ```csharp -public class Startup +using BlazorApp3.Areas.Identity; +using BlazorApp3.Data; +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); +builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); +builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores(); +builder.Services.AddRazorPages(); +builder.Services.AddServerSideBlazor(); +builder.Services.AddScoped>(); +builder.Services.AddSingleton(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) { - public Startup(IConfiguration configuration) - { - Configuration = configuration; - } - - public IConfiguration Configuration { get; } - - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 - public void ConfigureServices(IServiceCollection services) - { - services.AddRazorPages(); - services.AddServerSideBlazor(); - services.AddSingleton(); - } - - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, IWebHostEnvironment env) - { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } - - app.UseHttpsRedirection(); - app.UseStaticFiles(); - - app.UseRouting(); - - app.UseEndpoints(endpoints => - { - endpoints.MapBlazorHub(); - endpoints.MapFallbackToPage("/_Host"); - }); - } - } -``` + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} + +app.UseHttpsRedirection(); + +app.UseStaticFiles(); -Like the rest of ASP.NET Core, the Startup class is created with dependency injection principles. The `IConfiguration` is provided to the constructor and stashed in a public property for later access during configuration. +app.UseRouting(); + +app.UseAuthentication(); +app.UseAuthorization(); + +app.MapBlazorHub(); +app.MapFallbackToPage("/_Host"); + +app.Run(); + +``` -The `ConfigureServices` method introduced in ASP.NET Core allows for the various ASP.NET Core framework services to be configured for the framework's built-in dependency injection container. The various `services.Add*` methods add services that enable features such as authentication, razor pages, MVC controller routing, SignalR, and Blazor Server interactions among many others. This method was not needed in web forms, as the parsing and handling of the ASPX, ASCX, ASHX, and ASMX files were defined by referencing ASP.NET in the web.config configuration file. More information about dependency injection in ASP.NET Core is available in the [online documentation](/aspnet/core/fundamentals/dependency-injection). +The various `services.Add*` methods add services that enable features such as authentication, razor pages, MVC controller routing, SignalR, and Blazor Server interactions among many others. This method was not needed in web forms, as the parsing and handling of the ASPX, ASCX, ASHX, and ASMX files were defined by referencing ASP.NET in the web.config configuration file. More information about dependency injection in ASP.NET Core is available in the [online documentation](/aspnet/core/fundamentals/dependency-injection). -The `Configure` method introduces the concept of the HTTP pipeline to ASP.NET Core. In this method, we declare from top to bottom the [Middleware](middleware.md) that will handle every request sent to our application. Most of these features in the default configuration were scattered across the web forms configuration files and are now in one place for ease of reference. +The `app.Use*` methods define the HTTP pipeline for ASP.NET Core apps. With these calls, we declare from top to bottom the [Middleware](middleware.md) that will handle every request sent to our application. Most of these features in the default configuration were scattered across the web forms configuration files and are now in one place for ease of reference. No longer is the configuration of the custom error page placed in a `web.config` file, but now is configured to always be shown if the application environment is not labeled `Development`. Additionally, ASP.NET Core applications are now configured to serve secure pages with TLS by default with the `UseHttpsRedirection` method call. @@ -83,11 +87,11 @@ Next, an unexpected configuration method is listed to `UseStaticFiles`. In ASP. The next line is the first that replicates one of the configuration options from web forms: `UseRouting`. This method adds the ASP.NET Core router to the pipeline and it can be either configured here or in the individual files that it can consider routing to. More information about routing configuration can be found in the [Routing section](pages-routing-layouts.md). -The final statement in this method defines the endpoints that ASP.NET Core is listening on. These routes are the web accessible locations that you can access on the web server and receive some content handled by .NET and returned to you. The first entry, `MapBlazorHub` configures a SignalR hub for use in providing the real-time and persistent connection to the server where the state and rendering of Blazor components is handled. The `MapFallbackToPage` method call indicates the web-accessible location of the page that starts the Blazor application and also configures the application to handle deep-linking requests from the client-side. You will see this feature at work if you open a browser and navigate directly to Blazor handled route in your application, such as `/counter` in the default project template. The request gets handled by the *_Host.cshtml* fallback page, which then runs the Blazor router and renders the counter page. +The final `app.Map*` statements define the endpoints that ASP.NET Core is listening on. These routes are the web accessible locations that you can access on the web server and receive some content handled by .NET and returned to you. The first entry, `MapBlazorHub` configures a SignalR hub for use in providing the real-time and persistent connection to the server where the state and rendering of Blazor components is handled. The `MapFallbackToPage` method call indicates the web-accessible location of the page that starts the Blazor application and also configures the application to handle deep-linking requests from the client-side. You will see this feature at work if you open a browser and navigate directly to Blazor handled route in your application, such as `/counter` in the default project template. The request gets handled by the *_Host.cshtml* fallback page, which then runs the Blazor router and renders the counter page. ## Upgrading the BundleConfig Process -Technologies for bundling assets like CSS stylesheets and JavaScript files have evolved significantly, with other technologies providing quickly evolving tools and techniques for managing these resources. To this end, we recommend using a Node command-line tool such as Grunt / Gulp / WebPack to package your static assets. +Technologies for bundling assets like CSS stylesheets and JavaScript files have changed significantly, with other technologies providing quickly evolving tools and techniques for managing these resources. To this end, we recommend using a Node command-line tool such as Grunt / Gulp / WebPack to package your static assets. The Grunt, Gulp, and WebPack command-line tools and their associated configurations can be added to your application and ASP.NET Core will quietly ignore those files during the application build process. You can add a call to run their tasks by adding a `Target` inside your project file with syntax similar to the following that would trigger a gulp script and the `min` target inside that script diff --git a/docs/architecture/blazor-for-web-forms-developers/architecture-comparison.md b/docs/architecture/blazor-for-web-forms-developers/architecture-comparison.md index baab3005b61d8..0aed78dc52e85 100644 --- a/docs/architecture/blazor-for-web-forms-developers/architecture-comparison.md +++ b/docs/architecture/blazor-for-web-forms-developers/architecture-comparison.md @@ -4,7 +4,7 @@ description: Learn how the architectures of ASP.NET Web Forms and Blazor compare author: danroth27 ms.author: daroth no-loc: [Blazor] -ms.date: 11/20/2020 +ms.date: 12/2/2021 --- # Architecture comparison of ASP.NET Web Forms and Blazor diff --git a/docs/architecture/blazor-for-web-forms-developers/components.md b/docs/architecture/blazor-for-web-forms-developers/components.md index a04914888319f..4bc95f4006aad 100644 --- a/docs/architecture/blazor-for-web-forms-developers/components.md +++ b/docs/architecture/blazor-for-web-forms-developers/components.md @@ -4,7 +4,7 @@ description: Learn how to build reusable UI components with Blazor and how they author: danroth27 ms.author: daroth no-loc: [Blazor] -ms.date: 09/18/2019 +ms.date: 12/2/2021 --- # Build reusable UI components with Blazor diff --git a/docs/architecture/blazor-for-web-forms-developers/data.md b/docs/architecture/blazor-for-web-forms-developers/data.md index 009e28f33a747..9caa164c87c10 100644 --- a/docs/architecture/blazor-for-web-forms-developers/data.md +++ b/docs/architecture/blazor-for-web-forms-developers/data.md @@ -4,7 +4,7 @@ description: Learn how to access and handle data in ASP.NET Web Forms and Blazor author: csharpfritz ms.author: jefritz no-loc: [Blazor] -ms.date: 11/20/2020 +ms.date: 12/2/2021 --- # Work with data diff --git a/docs/architecture/blazor-for-web-forms-developers/forms-validation.md b/docs/architecture/blazor-for-web-forms-developers/forms-validation.md index 892d8851c204d..b7a07c873cb0e 100644 --- a/docs/architecture/blazor-for-web-forms-developers/forms-validation.md +++ b/docs/architecture/blazor-for-web-forms-developers/forms-validation.md @@ -4,7 +4,7 @@ description: Learn how to build forms with client-side validation in Blazor. author: danroth27 ms.author: daroth no-loc: [Blazor, "Blazor WebAssembly"] -ms.date: 09/19/2019 +ms.date: 12/2/2021 --- # Forms and validation diff --git a/docs/architecture/blazor-for-web-forms-developers/hosting-models.md b/docs/architecture/blazor-for-web-forms-developers/hosting-models.md index b0fda94898df0..76df6a8f250a7 100644 --- a/docs/architecture/blazor-for-web-forms-developers/hosting-models.md +++ b/docs/architecture/blazor-for-web-forms-developers/hosting-models.md @@ -4,7 +4,7 @@ description: Learn the different ways to host a Blazor app, including in the bro author: danroth27 ms.author: daroth no-loc: [Blazor, WebAssembly] -ms.date: 11/20/2020 +ms.date: 12/2/2021 --- # Blazor app hosting models diff --git a/docs/architecture/blazor-for-web-forms-developers/index.md b/docs/architecture/blazor-for-web-forms-developers/index.md index 86ea2f37c8d78..89c147d808f4a 100644 --- a/docs/architecture/blazor-for-web-forms-developers/index.md +++ b/docs/architecture/blazor-for-web-forms-developers/index.md @@ -4,11 +4,11 @@ description: Learn how to build full-stack web apps with .NET using Blazor and . author: danroth27 ms.author: daroth no-loc: [Blazor, WebAssembly] -ms.date: 11/15/2021 +ms.date: 12/2/2021 --- # Blazor for ASP.NET Web Forms Developers -![Screenshot that shows the Serverless Apps e-book cover.](./media/index/blazor-for-aspnet-web-forms-developers.png) +![Blazor for ASP.NET Web Forms Developers e-book cover.](./media/index/blazor-for-aspnet-web-forms-developers.png) > DOWNLOAD available at: diff --git a/docs/architecture/blazor-for-web-forms-developers/introduction.md b/docs/architecture/blazor-for-web-forms-developers/introduction.md index 12042370e9935..5b35e215c6646 100644 --- a/docs/architecture/blazor-for-web-forms-developers/introduction.md +++ b/docs/architecture/blazor-for-web-forms-developers/introduction.md @@ -4,7 +4,7 @@ description: An introduction to Blazor and writing full-stack web apps with .NET author: danroth27 ms.author: daroth no-loc: [Blazor, WebAssembly] -ms.date: 11/20/2020 +ms.date: 12/2/2021 --- # An introduction to Blazor for ASP.NET Web Forms developers @@ -25,13 +25,13 @@ When .NET and ASP.NET Web Forms first shipped, the platform ecosystem looked muc Most modern web frameworks are now also open-source, which has a number of benefits. Users aren't beheld to a single project owner to fix bugs and add features. Open-source projects provide improved transparency on development progress and upcoming changes. Open-source projects enjoy contributions from an entire community, and they foster a supportive open-source ecosystem. Despite the risks of open-source, many consumers and contributors have found suitable mitigations that enable them to enjoy the benefits of an open-source ecosystem in a safe and reasonable way. Examples of such mitigations include contributor license agreements, friendly licenses, pedigree scans, and supporting foundations. -The .NET community has embraced both cross-platform support and open-source. .NET Core is an open-source and cross-platform implementation of .NET that runs on a plethora of platforms, including Windows, macOS, and various Linux distributions. Xamarin provides Mono, an open-source version of .NET. Mono runs on Android, iOS, and a variety of other form factors, including watches and smart TVs. Microsoft has released [.NET 5](https://devblogs.microsoft.com/dotnet/announcing-net-5-0/) that reconciled .NET Core and Mono into "a single .NET runtime and framework that can be used everywhere and that has uniform runtime behaviors and developer experiences." +The .NET community has embraced both cross-platform support and open-source. .NET Core is an open-source and cross-platform implementation of .NET that runs on a plethora of platforms, including Windows, macOS, and various Linux distributions. Xamarin provides Mono, an open-source version of .NET. Mono runs on Android, iOS, and a variety of other form factors, including watches and smart TVs. In 2020, Microsoft released [.NET 5](https://devblogs.microsoft.com/dotnet/announcing-net-5-0/) that reconciled .NET Core and Mono into "a single .NET runtime and framework that can be used everywhere and that has uniform runtime behaviors and developer experiences." -Will ASP.NET Web Forms benefit from the move to open-source and cross-platform support? The answer, unfortunately, is no, or at least not to the same extent as the rest of the platform. The .NET team [recently made it clear](https://devblogs.microsoft.com/dotnet/net-core-is-the-future-of-net/) that ASP.NET Web Forms won't be ported to .NET Core or .NET 5. Why is that? +Will ASP.NET Web Forms benefit from the move to open-source and cross-platform support? The answer, unfortunately, is no, or at least not to the same extent as the rest of the platform. The .NET team [made it clear](https://devblogs.microsoft.com/dotnet/net-core-is-the-future-of-net/) that ASP.NET Web Forms won't be ported to .NET Core or .NET 6. Why is that? There were efforts in the early days of .NET Core to port ASP.NET Web Forms. The number of breaking changes required were found to be too drastic. There's also an admission here that even for Microsoft, there's a limit to the number of web frameworks that it can support simultaneously. Perhaps someone in the community will take up the cause of creating an open-source and cross-platform version of ASP.NET Web Forms. The [source code for ASP.NET Web Forms](https://github.com/microsoft/referencesource) has been made available publicly in reference form. But for the time being, it seems ASP.NET Web Forms will remain Windows-only and without an open-source contribution model. If cross-platform support or open-source become important for your scenarios, then you'll need to look for something new. -Does this mean ASP.NET Web Forms is *dead* and should no longer be used? Of course not! As long as the .NET Framework ships as part of Windows, ASP.NET Web Forms will be a supported framework. For many Web Forms developers, the lack of cross-platform and open-source support is a non-issue. If you don't have a requirement for cross-platform support, open-source, or any of the other new features in .NET Core or .NET 5, then sticking with ASP.NET Web Forms on Windows is fine. ASP.NET Web Forms will continue to be a productive way to write web apps for many years to come. +Does this mean ASP.NET Web Forms is *dead* and should no longer be used? Of course not! As long as the .NET Framework ships as part of Windows, ASP.NET Web Forms will be a supported framework. For many Web Forms developers, the lack of cross-platform and open-source support is a non-issue. If you don't have a requirement for cross-platform support, open-source, or any of the other new features in .NET Core or .NET 6, then sticking with ASP.NET Web Forms on Windows is fine. ASP.NET Web Forms will continue to be a productive way to write web apps for many years to come. But there's another trend worth considering, and that's the shift to the client. @@ -47,7 +47,7 @@ But bridging two different platforms and ecosystems (.NET and JavaScript) comes In 2015, the major browser vendors joined forces in a W3C Community Group to create a new open web standard called WebAssembly. WebAssembly is a byte code for the Web. If you can compile your code to WebAssembly, it can then run on any browser on any platform at near native speed. Initial efforts focused on C/C++. The result was a dramatic demonstration of running native 3D graphics engines directly in the browser without plugins. WebAssembly has since been standardized and implemented by all major browsers. -Work on running .NET on WebAssembly was announced in late 2017 and released in 2020, including support from .NET 5. The ability to run .NET code directly in the browser enables full-stack web development with .NET. +Work on running .NET on WebAssembly was announced in late 2017 and released in 2020, including support in .NET 5 and beyond. The ability to run .NET code directly in the browser enables full-stack web development with .NET. ## Blazor: full-stack web development with .NET diff --git a/docs/architecture/blazor-for-web-forms-developers/media/index/blazor-for-aspnet-web-forms-developers.png b/docs/architecture/blazor-for-web-forms-developers/media/index/blazor-for-aspnet-web-forms-developers.png index 9f2e40cad22a8..d3f15e913aaae 100644 Binary files a/docs/architecture/blazor-for-web-forms-developers/media/index/blazor-for-aspnet-web-forms-developers.png and b/docs/architecture/blazor-for-web-forms-developers/media/index/blazor-for-aspnet-web-forms-developers.png differ diff --git a/docs/architecture/blazor-for-web-forms-developers/middleware.md b/docs/architecture/blazor-for-web-forms-developers/middleware.md index 3056df5ada6eb..3b69fcd604134 100644 --- a/docs/architecture/blazor-for-web-forms-developers/middleware.md +++ b/docs/architecture/blazor-for-web-forms-developers/middleware.md @@ -4,7 +4,7 @@ description: Learn about handling HTTP requests with modules, handlers, and midd author: danroth27 ms.author: daroth no-loc: [Blazor] -ms.date: 10/11/2019 +ms.date: 12/2/2021 --- # Modules, handlers, and middleware diff --git a/docs/architecture/blazor-for-web-forms-developers/migration.md b/docs/architecture/blazor-for-web-forms-developers/migration.md index ab819a9183763..e15a81aac5695 100644 --- a/docs/architecture/blazor-for-web-forms-developers/migration.md +++ b/docs/architecture/blazor-for-web-forms-developers/migration.md @@ -4,7 +4,7 @@ description: Learn how to approach migrating an existing ASP.NET Web Forms app t author: twsouthwick ms.author: tasou no-loc: [Blazor, WebAssembly] -ms.date: 11/20/2020 +ms.date: 12/2/2021 --- # Migrate from ASP.NET Web Forms to Blazor @@ -153,92 +153,86 @@ public class Global : HttpApplication, IContainerProviderAccessor } ``` -The preceding file becomes the `Startup` class in server-side Blazor: +The preceding file becomes the *Program.cs* file in server-side Blazor: ```csharp -public class Startup -{ - public Startup(IConfiguration configuration, IWebHostEnvironment env) - { - Configuration = configuration; - Env = env; - } +using eShopOnBlazor.Models; +using eShopOnBlazor.Models.Infrastructure; +using eShopOnBlazor.Services; +using log4net; +using System.Data.Entity; +using eShopOnBlazor; - public IConfiguration Configuration { get; } +var builder = WebApplication.CreateBuilder(args); - public IWebHostEnvironment Env { get; } +// add services - // This method gets called by the runtime. Use this method to add services to the container. - // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 - public void ConfigureServices(IServiceCollection services) - { - services.AddRazorPages(); - services.AddServerSideBlazor(); +builder.Services.AddRazorPages(); +builder.Services.AddServerSideBlazor(); - if (Configuration.GetValue("UseMockData")) - { - services.AddSingleton(); - } - else - { - services.AddScoped(); - services.AddScoped, CatalogDBInitializer>(); - services.AddSingleton(); - services.AddScoped(_ => new CatalogDBContext(Configuration.GetConnectionString("CatalogDBContext"))); - } - } +if (builder.Configuration.GetValue("UseMockData")) +{ + builder.Services.AddSingleton(); +} +else +{ + builder.Services.AddScoped(); + builder.Services.AddScoped, CatalogDBInitializer>(); + builder.Services.AddSingleton(); + builder.Services.AddScoped(_ => new CatalogDBContext(builder.Configuration.GetConnectionString("CatalogDBContext"))); +} - // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. - public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory) - { - loggerFactory.AddLog4Net("log4Net.xml"); +var app = builder.Build(); - if (Env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - } - else - { - app.UseExceptionHandler("/Home/Error"); - } +new LoggerFactory().AddLog4Net("log4Net.xml"); - // Middleware for Application_BeginRequest - app.Use((ctx, next) => - { - LogicalThreadContext.Properties["activityid"] = new ActivityIdHelper(ctx); - LogicalThreadContext.Properties["requestinfo"] = new WebRequestInfo(ctx); - return next(); - }); +if (app.Environment.IsDevelopment()) +{ + app.UseDeveloperExceptionPage(); +} +else +{ + app.UseExceptionHandler("/Home/Error"); +} - app.UseStaticFiles(); +// Middleware for Application_BeginRequest +app.Use((ctx, next) => +{ + LogicalThreadContext.Properties["activityid"] = new ActivityIdHelper(ctx); + LogicalThreadContext.Properties["requestinfo"] = new WebRequestInfo(ctx); + return next(); +}); - app.UseRouting(); +app.UseStaticFiles(); - app.UseEndpoints(endpoints => - { - endpoints.MapBlazorHub(); - endpoints.MapFallbackToPage("/_Host"); - }); +app.UseRouting(); - ConfigDataBase(app); - } +app.UseEndpoints(endpoints => +{ + endpoints.MapBlazorHub(); + endpoints.MapFallbackToPage("/_Host"); +}); + +ConfigDataBase(app); - private void ConfigDataBase(IApplicationBuilder app) +void ConfigDataBase(IApplicationBuilder app) +{ + using (var scope = app.ApplicationServices.CreateScope()) { - using (var scope = app.ApplicationServices.CreateScope()) - { - var initializer = scope.ServiceProvider.GetService>(); + var initializer = scope.ServiceProvider.GetService>(); - if (initializer != null) - { - Database.SetInitializer(initializer); - } + if (initializer != null) + { + Database.SetInitializer(initializer); } } } + +app.Run(); + ``` -One significant change you may notice from Web Forms is the prominence of DI. DI has been a guiding principle in the ASP.NET Core design. It supports customization of almost all aspects of the ASP.NET Core framework. There's even a built-in service provider that can be used for many scenarios. If more customization is required, it can be supported by many community projects. For example, you can carry forward your third-party DI library investment. +One significant change you may notice from Web Forms is the prominence of dependency injection (DI). DI has been a guiding principle in the ASP.NET Core design. It supports customization of almost all aspects of the ASP.NET Core framework. There's even a built-in service provider that can be used for many scenarios. If more customization is required, it can be supported by many community projects. For example, you can carry forward your third-party DI library investment. In the original eShop app, there's some configuration for session management. Since server-side Blazor uses ASP.NET Core SignalR for communication, the session state isn't supported as the connections may occur independent of an HTTP context. An app that uses the session state requires rearchitecting before running as a Blazor app. @@ -254,17 +248,15 @@ For more information on migrating modules and handlers, see [Migrate HTTP handle ## Migrate static files -To serve static files (for example, HTML, CSS, images, and JavaScript), the files must be exposed by middleware. Calling the `UseStaticFiles` method enables the serving of static files from the web root path. The default web root directory is *wwwroot*, but it can be customized. As included in the `Configure` method of eShop's `Startup` class: +To serve static files (for example, HTML, CSS, images, and JavaScript), the files must be exposed by middleware. Calling the `UseStaticFiles` method enables the serving of static files from the web root path. The default web root directory is *wwwroot*, but it can be customized. As included in the *Program.cs* file: ```csharp -public void Configure(IApplicationBuilder app) -{ - ... +... - app.UseStaticFiles(); +app.UseStaticFiles(); + +... - ... -} ``` The eShop project enables basic static file access. There are many customizations available for static file access. For information on enabling default files or a file browser, see [Static files in ASP.NET Core](/aspnet/core/fundamentals/static-files). @@ -590,18 +582,19 @@ It's common for secrets, such as database connection strings, to be stored withi JSON is the default configuration format; however, ASP.NET Core supports many other formats, including XML. There are also several community-supported formats. -The constructor in the Blazor project's `Startup` class accepts an `IConfiguration` instance through a DI technique known as constructor injection: +You can access configuration values from the builder in *Program.cs*: ```csharp -public class Startup +if (builder.Configuration.GetValue("UseMockData")) { - public Startup(IConfiguration configuration, IWebHostEnvironment env) - { - Configuration = configuration; - Env = env; - } - - ... + builder.Services.AddSingleton(); +} +else +{ + builder.Services.AddScoped(); + builder.Services.AddScoped, CatalogDBInitializer>(); + builder.Services.AddSingleton(); + builder.Services.AddScoped(_ => new CatalogDBContext(builder.Configuration.GetConnectionString("CatalogDBContext"))); } ``` diff --git a/docs/architecture/blazor-for-web-forms-developers/project-structure.md b/docs/architecture/blazor-for-web-forms-developers/project-structure.md index d68023ad4e48d..6f89d1509ecce 100644 --- a/docs/architecture/blazor-for-web-forms-developers/project-structure.md +++ b/docs/architecture/blazor-for-web-forms-developers/project-structure.md @@ -4,7 +4,7 @@ description: Learn how the project structures of ASP.NET Web Forms and Blazor pr author: danroth27 ms.author: daroth no-loc: [Blazor, WebAssembly] -ms.date: 11/20/2020 +ms.date: 12/2/2021 --- # Project structure for Blazor apps @@ -20,7 +20,7 @@ Blazor Server apps are .NET projects. The project file for the Blazor Server app - net5.0 + net6.0 @@ -32,13 +32,16 @@ The project file for a Blazor WebAssembly app looks slightly more involved (exac - net5.0 + net6.0 + enable - - - + + + + + @@ -46,13 +49,13 @@ The project file for a Blazor WebAssembly app looks slightly more involved (exac Blazor WebAssembly project targets `Microsoft.NET.Sdk.BlazorWebAssembly` instead of `Microsoft.NET.Sdk.Web` sdk because they run in the browser on a WebAssembly-based .NET runtime. You can't install .NET into a web browser like you can on a server or developer machine. Consequently, the project references the Blazor framework using individual package references. -By comparison, a default ASP.NET Web Forms project includes almost 300 lines of XML in its *.csproj* file, most of which is explicitly listing the various code and content files in the project. With the release of `.NET 5` both `Blazor Server` and `Blazor WebAssembly` app can easily share one unified runtime. +By comparison, a default ASP.NET Web Forms project includes almost 300 lines of XML in its *.csproj* file, most of which is explicitly listing the various code and content files in the project. Since the release of `.NET 5` both `Blazor Server` and `Blazor WebAssembly` app can easily share one unified runtime. Although they're supported, individual assembly references are less common in .NET projects. Most project dependencies are handled as NuGet package references. You only need to reference top-level package dependencies in .NET projects. Transitive dependencies are included automatically. Instead of using the *packages.config* file commonly found in ASP.NET Web Forms projects to reference packages, package references are added to the project file using the `` element. ```xml - + ``` @@ -61,29 +64,81 @@ Although they're supported, individual assembly references are less common in .N The Blazor Server app's entry point is defined in the *Program.cs* file, as you would see in a Console app. When the app executes, it creates and runs a web host instance using defaults specific to web apps. The web host manages the Blazor Server app's lifecycle and sets up host-level services. Examples of such services are configuration, logging, dependency injection, and the HTTP server. This code is mostly boilerplate and is often left unchanged. ```csharp -public class Program +using BlazorApp3.Areas.Identity; +using BlazorApp3.Data; +using Microsoft.AspNetCore.Components.Authorization; +using Microsoft.AspNetCore.Identity; +using Microsoft.EntityFrameworkCore; + +var builder = WebApplication.CreateBuilder(args); + +// Add services to the container. +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); +builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); +builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores(); +builder.Services.AddRazorPages(); +builder.Services.AddServerSideBlazor(); +builder.Services.AddScoped>(); +builder.Services.AddSingleton(); + +var app = builder.Build(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) { - public static void Main(string[] args) - { - CreateHostBuilder(args).Build().Run(); - } - - public static IHostBuilder CreateHostBuilder(string[] args) => - Host.CreateDefaultBuilder(args) - .ConfigureWebHostDefaults(webBuilder => - { - webBuilder.UseStartup(); - }); + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); } + +app.UseHttpsRedirection(); + +app.UseStaticFiles(); + +app.UseRouting(); + +app.UseAuthentication(); +app.UseAuthorization(); + +app.MapControllers(); +app.MapBlazorHub(); +app.MapFallbackToPage("/_Host"); + +app.Run(); ``` Blazor WebAssembly apps also define an entry point in *Program.cs*. The code looks slightly different. The code is similar in that it's setting up the app host to provide the same host-level services to the app. The WebAssembly app host doesn't, however, set up an HTTP server because it executes directly in the browser. -Blazor apps have a `Startup` class instead of a *Global.asax* file to define the startup logic for the app. The `Startup` class is used to configure the app and any app-specific services. In the Blazor Server app, the `Startup` class is used to set up the endpoint for the real-time connection used by Blazor between the client browsers and the server. In the Blazor WebAssembly app, the `Startup` class defines the root components for the app and where they should be rendered. We'll take a deeper look at the `Startup` class in the [App startup](./app-startup.md) section. +Blazor apps don't use a *Global.asax* file to define the startup logic for the app. Instead, this logic is contained in *Program.cs* or in a related `Startup` class that is referenced from *Program.cs*. Either way, this code is used to configure the app and any app-specific services. + +In a Blazor Server app, the *Program.cs* file shown is used to set up the endpoint for the real-time connection used by Blazor between the client browsers and the server. + +In a Blazor WebAssembly app, the *Program.cs* file defines the root components for the app and where they should be rendered: + +```csharp +using BlazorApp1; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; + +var builder = WebAssemblyHostBuilder.CreateDefault(args); +builder.RootComponents.Add("#app"); +builder.RootComponents.Add("head::after"); + +builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); + +await builder.Build().RunAsync(); +``` ## Static files -Unlike ASP.NET Web Forms projects, not all files in a Blazor project can be requested as static files. Only the files in the *wwwroot* folder are web-addressable. This folder is referred to the app's "web root". Anything outside of the app's web root *isn't* web-addressable. This setup provides an additional level of security that prevents accidental exposing of project files over the web. +Unlike ASP.NET Web Forms projects, not all files in a Blazor project can be requested as static files. Only the files in the *wwwroot* folder are web-addressable. This folder is referred to as the app's "web root". Anything outside of the app's web root *isn't* web-addressable. This setup provides an additional level of security that prevents accidental exposure of project files over the web. ## Configuration @@ -134,7 +189,7 @@ Where are the pages in the Blazor apps? Blazor doesn't define a separate file ex Routing in Blazor is handled client-side, not on the server. As the user navigates in the browser, Blazor intercepts the navigation and then renders the component with the matching route. -The component routes aren't currently inferred by the component's file location like they are with *.aspx* pages. This feature may be added in the future. Each route must be specified explicitly on the component. Storing routable components in a *Pages* folder has no special meaning and is purely a convention. +The component routes aren't currently inferred by the component's file location like they are with *.aspx* pages or ASP.NET Core Razor Pages. This feature may be added in the future. Each route must be specified explicitly on the component. Storing routable components in a *Pages* folder has no special meaning and is purely a convention. We'll look in greater detail at routing in Blazor in the [Pages, routing, and layouts](./pages-routing-layouts.md) section. @@ -149,7 +204,20 @@ To bootstrap Blazor, the app must: - Specify where on the page the root component (*App.Razor*) should be rendered. - Add the corresponding Blazor framework script. -In the Blazor Server app, the root component's host page is defined in the *_Host.cshtml* file. This file defines a Razor Page, not a component. Razor Pages use Razor syntax to define a server-addressable page, very much like an *.aspx* page. The `Html.RenderComponentAsync(RenderMode)` method is used to define where a root-level component should be rendered. The `RenderMode` option indicates the manner in which the component should be rendered. The following table outlines the supported `RenderMode` options. +In the Blazor Server app, the root component's host page is defined in the *_Host.cshtml* file. This file defines a Razor Page, not a component. Razor Pages use Razor syntax to define a server-addressable page, very much like an *.aspx* page. + +```razor +@page "/" +@namespace BlazorApp3.Pages +@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers +@{ + Layout = "_Layout"; +} + + +``` + +The `render-mode` attribute is used to define where a root-level component should be rendered. The `RenderMode` option indicates the manner in which the component should be rendered. The following table outlines the supported `RenderMode` options. |Option |Description | |------------------------------|------------------| @@ -157,11 +225,11 @@ In the Blazor Server app, the root component's host page is defined in the *_Hos |`RenderMode.ServerPrerendered`|First prerendered and then rendered interactively| |`RenderMode.Static` |Rendered as static content| -The script reference to *_framework/blazor.server.js* establishes the real-time connection with the server and then deals with all user interactions and UI updates. +The *_Layout.cshtml* file includes the default HTML for the app and its components. ```razor -@page "/" -@namespace BlazorApp1.Pages +@using Microsoft.AspNetCore.Components.Web +@namespace BlazorApp3.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @@ -169,35 +237,48 @@ The script reference to *_framework/blazor.server.js* establishes the real-time - BlazorApp1 + + - - @(await Html.RenderComponentAsync(RenderMode.ServerPrerendered)) - + @RenderBody() + +
+ + An error has occurred. This application may no longer respond until reloaded. + + + An unhandled exception has occurred. See browser dev tools for details. + + Reload + 🗙 +
+ ``` +The script reference to *_framework/blazor.server.js* establishes the real-time connection with the server and then deals with all user interactions and UI updates. + In the Blazor WebAssembly app, the host page is a simple static HTML file under *wwwroot/index.html*. The `
` element with id named `app` is used to indicate where the root component should be rendered. ```html - + - BlazorApp2 + BlazorApp1 - + @@ -212,23 +293,14 @@ In the Blazor WebAssembly app, the host page is a simple static HTML file under - ``` -The root component to render is specified in the app's `Program.Main` method with the flexibility to register services through dependency injection. For more information, see [ASP.NET Core Blazor dependency injection](/aspnet/core/blazor/fundamentals/dependency-injection?pivots=webassembly). +The root component to render is specified in the app's *Program.cs* file with the flexibility to register services through dependency injection. For more information, see [ASP.NET Core Blazor dependency injection](/aspnet/core/blazor/fundamentals/dependency-injection?pivots=webassembly). ```csharp -public class Program -{ - public static async Task Main(string[] args) - { - var builder = WebAssemblyHostBuilder.CreateDefault(args); - builder.RootComponents.Add("#app"); - - .... - .... - } -} +var builder = WebAssemblyHostBuilder.CreateDefault(args); +builder.RootComponents.Add("#app"); +builder.RootComponents.Add("head::after"); ``` ## Build output @@ -244,7 +316,7 @@ To run the Blazor WebAssembly app, choose one of the following approaches: - Run the client project directly using the development server. - Run the server project when hosting the app with ASP.NET Core. -Blazor WebAssembly apps can be debugged in both browser and Visual Studio.See [Debug ASP.NET Core Blazor WebAssembly](/aspnet/core/blazor/debug) for details. +Blazor WebAssembly apps can be debugged in both browser and Visual Studio. See [Debug ASP.NET Core Blazor WebAssembly](/aspnet/core/blazor/debug) for details. Both Blazor Server and Blazor WebAssembly apps support Hot Reload in Visual Studio. Hot Reload is a feature that automatically updates changes made to a Blazor app live, in the browser. You can toggle whether Hot Reload is enabled from its icon in the toolbar: diff --git a/docs/architecture/blazor-for-web-forms-developers/security-authentication-authorization.md b/docs/architecture/blazor-for-web-forms-developers/security-authentication-authorization.md index 7acf82e969dd1..755a28b2ca60c 100644 --- a/docs/architecture/blazor-for-web-forms-developers/security-authentication-authorization.md +++ b/docs/architecture/blazor-for-web-forms-developers/security-authentication-authorization.md @@ -4,7 +4,7 @@ description: Learn how to handle authentication and authorization in ASP.NET Web author: ardalis ms.author: daroth no-loc: [Blazor] -ms.date: 11/20/2020 +ms.date: 12/2/2021 --- # Security: Authentication and Authorization in ASP.NET Web Forms and Blazor @@ -214,7 +214,7 @@ Migrating from ASP.NET Web Forms and universal providers to ASP.NET Core Identit 1. Create ASP.NET Core Identity database schema in the destination database 2. Migrate data from universal provider schema to ASP.NET Core Identity schema -3. Migrate configuration from the `web.config` to middleware and services, typically in `Startup.cs` +3. Migrate configuration from the `web.config` to middleware and services, typically in *Program.cs* (or a `Startup` class) 4. Update individual pages using controls and conditionals to use tag helpers and new identity APIs. Each of these steps is described in detail in the following sections. @@ -259,64 +259,55 @@ To migrate your users from membership to the new identity tables, you should [fo It is possible to migrate user passwords but the process is much more involved. Requiring users to update their passwords as part of the migration process, and encouraging them to use new, unique passwords, is likely to enhance the overall security of the application. -### Migrating security settings from web.config to Startup.cs +### Migrating security settings from web.config to app startup -As noted above, ASP.NET membership and role providers are configured in the application's `web.config` file. Since ASP.NET Core apps are not tied to IIS and use a separate system for configuration, these settings must be configured elsewhere. For the most part, ASP.NET Core Identity is configured in the `Startup.cs` file. Open the web project that was created earlier (to generate the identity table schema) and review its `Startup.cs` file. +As noted above, ASP.NET membership and role providers are configured in the application's `web.config` file. Since ASP.NET Core apps are not tied to IIS and use a separate system for configuration, these settings must be configured elsewhere. For the most part, ASP.NET Core Identity is configured in the *Program.cs* file. Open the web project that was created earlier (to generate the identity table schema) and review its *Program.cs* (or *Startup.cs*) file. -The default ConfigureServices method adds support for EF Core and Identity: +This code adds support for EF Core and Identity: ```csharp -// This method gets called by the runtime. Use this method to add services to the container. -public void ConfigureServices(IServiceCollection services) -{ - services.AddDbContext(options => - options.UseSqlServer( - Configuration.GetConnectionString("DefaultConnection"))); - - services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true) - .AddEntityFrameworkStores(); - - services.AddRazorPages(); -} +// Add services to the container. +var connectionString = builder.Configuration.GetConnectionString("DefaultConnection"); +builder.Services.AddDbContext(options => + options.UseSqlServer(connectionString)); +builder.Services.AddDatabaseDeveloperPageExceptionFilter(); +builder.Services.AddDefaultIdentity(options => + options.SignIn.RequireConfirmedAccount = true) + .AddEntityFrameworkStores(); ``` The `AddDefaultIdentity` extension method is used to configure Identity to use the default `ApplicationDbContext` and the framework's `IdentityUser` type. If you're using a custom `IdentityUser`, be sure to specify its type here. If these extension methods aren't working in your application, check that you have the appropriate using statements and that you have the necessary NuGet package references. For example, your project should have some version of the `Microsoft.AspNetCore.Identity.EntityFrameworkCore` and `Microsoft.AspNetCore.Identity.UI` packages referenced. -Also in `Startup.cs` you should see the necessary middleware configured for the site. Specifically, `UseAuthentication` and `UseAuthorization` should be set up, and in the proper location. +Also in *Program.cs* you should see the necessary middleware configured for the site. Specifically, `UseAuthentication` and `UseAuthorization` should be set up, and in the proper location. ```csharp - -// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. -public void Configure(IApplicationBuilder app, IWebHostEnvironment env) +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) { - if (env.IsDevelopment()) - { - app.UseDeveloperExceptionPage(); - app.UseDatabaseErrorPage(); - } - else - { - app.UseExceptionHandler("/Error"); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); - } + app.UseMigrationsEndPoint(); +} +else +{ + app.UseExceptionHandler("/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); +} - app.UseHttpsRedirection(); - app.UseStaticFiles(); +app.UseHttpsRedirection(); - app.UseRouting(); +app.UseStaticFiles(); - app.UseAuthentication(); - app.UseAuthorization(); +app.UseRouting(); - app.UseEndpoints(endpoints => - { - endpoints.MapRazorPages(); - }); -} +app.UseAuthentication(); +app.UseAuthorization(); + +//app.MapControllers(); +app.MapBlazorHub(); +app.MapFallbackToPage("/_Host"); ``` -ASP.NET Identity does not configure anonymous or role-based access to locations from `Startup.cs`. You will need to migrate any location-specific authorization configuration data to filters in ASP.NET Core. Make note of which folders and pages will require such updates. You will make these changes in the next section. +ASP.NET Identity does not configure anonymous or role-based access to locations from *Program.cs*. You will need to migrate any location-specific authorization configuration data to filters in ASP.NET Core. Make note of which folders and pages will require such updates. You will make these changes in the next section. ### Updating individual pages to use ASP.NET Core Identity abstractions diff --git a/docs/architecture/blazor-for-web-forms-developers/state-management.md b/docs/architecture/blazor-for-web-forms-developers/state-management.md index 374fbbca360bd..10bdae5a01fe4 100644 --- a/docs/architecture/blazor-for-web-forms-developers/state-management.md +++ b/docs/architecture/blazor-for-web-forms-developers/state-management.md @@ -3,11 +3,11 @@ title: State management description: Learn different approaches for managing state in ASP.NET Web Forms and Blazor. author: csharpfritz ms.author: jefritz -ms.date: 05/15/2020 +ms.date: 12/2/2021 --- # State management -State management is a key concept of Web Forms applications, facilitated through View State, Session State, Application State, and Postback features. These stateful features of the framework helped to hide the state management required for an application and allow application developers to focus on delivering their functionality. With ASP.NET Core and Blazor, some of these features have been relocated and some have been removed altogether. This chapter reviews how to maintain state and deliver the same functionality with the new features in Blazor. +State management is a key concept of Web Forms applications, facilitated through ViewState, Session State, Application State, and Postback features. These stateful features of the framework helped to hide the state management required for an application and allow application developers to focus on delivering their functionality. With ASP.NET Core and Blazor, some of these features have been relocated and some have been removed altogether. This chapter reviews how to maintain state and deliver the same functionality with the new features in Blazor. ## Request state management with ViewState