diff --git a/docs/architecture/porting-existing-aspnet-apps/app-startup-differences.md b/docs/architecture/porting-existing-aspnet-apps/app-startup-differences.md index 89033be178c0b..4d341cbecf1dc 100644 --- a/docs/architecture/porting-existing-aspnet-apps/app-startup-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/app-startup-differences.md @@ -7,21 +7,21 @@ ms.date: 11/13/2020 # App startup differences between ASP.NET MVC and ASP.NET Core -ASP.NET MVC applications lived entirely within Internet Information Server (IIS), the primary web server available on Windows operating systems. Unlike ASP.NET MVC, ASP.NET Core applications are executable applications. You can run them from the command line, using `dotnet run`. They have an entry point method like all C# programs, typically `public static void main()` or a similar variation (perhaps with arguments or async support). This is perhaps the biggest architectural difference between ASP.NET Core and ASP.NET MVC, and is one of several differences that allows ASP.NET Core to run on non-Windows systems. +ASP.NET MVC apps lived entirely within Internet Information Server (IIS), the primary web server available on Windows operating systems. Unlike ASP.NET MVC, ASP.NET Core apps are executable apps. You can run them from the command line, using `dotnet run`. They have an entry point method like all C# programs, typically `public static void main()` or a similar variation (perhaps with arguments or async support). This is perhaps the biggest architectural difference between ASP.NET Core and ASP.NET MVC, and is one of several differences that allows ASP.NET Core to run on non-Windows systems. ## ASP.NET MVC Startup -Hosted within IIS, ASP.NET applications rely on IIS to instantiate certain objects and call certain methods when a request arrives. ASP.NET creates an instance of the `Global.asax` file's class, which derives from `HttpApplication`. When the first request is received, before handling the request itself, ASP.NET calls the `Application_Start` method in the `Global.asax` file's class. Any logic that needs to run when the ASP.NET MVC application begins can be added to this method. +Hosted within IIS, ASP.NET apps rely on IIS to instantiate certain objects and call certain methods when a request arrives. ASP.NET creates an instance of the `Global.asax` file's class, which derives from `HttpApplication`. When the first request is received, before handling the request itself, ASP.NET calls the `Application_Start` method in the `Global.asax` file's class. Any logic that needs to run when the ASP.NET MVC app begins can be added to this method. -Many NuGet packages for ASP.NET MVC and Web API use the [WebActivator](https://github.com/davidebbo/WebActivator) package to let them run some code during application startup. By convention, this code would typically be added to an `App_Start` folder and would be configured via attribute to run either immediately before or just after `Application_Start`. +Many NuGet packages for ASP.NET MVC and Web API use the [WebActivator](https://github.com/davidebbo/WebActivator) package to let them run some code during app startup. By convention, this code would typically be added to an `App_Start` folder and would be configured via attribute to run either immediately before or just after `Application_Start`. -It's also possible to use the [Open Web Interface for .NET (OWIN) and Project Katana with ASP.NET MVC](https://docs.microsoft.com/aspnet/aspnet/overview/owin-and-katana/getting-started-with-owin-and-katana). When doing so, the application will include a `Startup.cs` file that is responsible for setting up request middleware in a way that's very similar to how ASP.NET Core behaves. +It's also possible to use the [Open Web Interface for .NET (OWIN) and Project Katana with ASP.NET MVC](https://docs.microsoft.com/aspnet/aspnet/overview/owin-and-katana/getting-started-with-owin-and-katana). When doing so, the app will include a `Startup.cs` file that is responsible for setting up request middleware in a way that's very similar to how ASP.NET Core behaves. If you need to run code when your ASP.NET MVC app starts up, it will typically use one of these approaches. ## ASP.NET Core Startup -As noted previously, ASP.NET Core applications are standalone programs. As such, they typically include a `Program.cs` file containing the entry point for the application. A typical such file is shown in Figure 2-1. +As noted previously, ASP.NET Core apps are standalone programs. As such, they typically include a `Program.cs` file containing the entry point for the app. A typical example of this file is shown in Figure 2-1. ```csharp public class Program @@ -42,11 +42,11 @@ public class Program **Figure 2-1**. A typical ASP.NET Core Program.cs file. -The code shown in Figure 2-1 creates a *host* for the application, builds it, and runs it. The ASP.NET Core application runs within the host configured by the `IHostBuilder` shown. While it's possible to completely configure an ASP.NET Core app using the `IHostBuilder`, typically the bulk of this work is done in a `Startup` class. +The code shown in Figure 2-1 creates a *host* for the app, builds it, and runs it. The ASP.NET Core app runs within the host configured by the `IHostBuilder` shown. While it's possible to completely configure an ASP.NET Core app using the `IHostBuilder`, typically the bulk of this work is done in a `Startup` class. The `Startup` class exposes two methods to the host: `ConfigureServices` and `Configure`. The `ConfigureServices` method is used to define the services the app will use and their respective lifetimes. The `Configure` method is used to define how each request to the app will be handled by setting up a request pipeline composed of middleware. -In addition to code related to configuring the application's services or request pipeline, apps may have other code that must run when the app begins. Such code is typically placed in `Program.cs` or registered as an `IHostedService` which will be started by the [generic host](https://docs.microsoft.com/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-3.1) when the application starts. +In addition to code related to configuring the app's services or request pipeline, apps may have other code that must run when the app begins. Such code is typically placed in `Program.cs` or registered as an `IHostedService`, which will be started by the [generic host](https://docs.microsoft.com/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-3.1) when the app starts. The `IHostedService` interface just exposes two methods, `StartAsync` and `StopAsync`. You register the interface in `ConfigureServices` and the host does the rest, calling the `StartAsync` method before the app starts up. diff --git a/docs/architecture/porting-existing-aspnet-apps/architectural-differences.md b/docs/architecture/porting-existing-aspnet-apps/architectural-differences.md index 320864ee196ab..ad8febf237354 100644 --- a/docs/architecture/porting-existing-aspnet-apps/architectural-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/architectural-differences.md @@ -13,7 +13,7 @@ There are many architectural differences between ASP.NET MVC on .NET Framework a ## Breaking changes -Because .NET Core is a complete rewrite of .NET, designed from the ground up to be cross-platform, there are many [breaking changes between the two frameworks](https://docs.microsoft.com/dotnet/core/compatibility/fx-core). The following sections identify specific differences between how ASP.NET MVC and ASP.NET Core apps are designed and developed, but take care also to examine the documentation to determine which framework libraries you're using that may need to be changed. In many cases, a replacement NuGet package exists to fill in any gaps left between .NET Framework and .NET Core. In rare cases, you may need to find a third-party solution or implement new custom code to address incompatibilities. +.NET Core is a cross-platform rewrite of .NET Framework. There are many [breaking changes between the two frameworks](https://docs.microsoft.com/dotnet/core/compatibility/fx-core). The following sections identify specific differences between how ASP.NET MVC and ASP.NET Core apps are designed and developed. Take care to also examine the documentation to determine which framework libraries you're using that may need to change. In many cases, a replacement NuGet package exists to fill in any gaps left between .NET Framework and .NET Core. In rare cases, you may need to find a third-party solution or implement new custom code to address incompatibilities. >[!div class="step-by-step"] >[Previous](additional-migration-resources.md) diff --git a/docs/architecture/porting-existing-aspnet-apps/authentication-differences.md b/docs/architecture/porting-existing-aspnet-apps/authentication-differences.md index b4961fc1d3786..87248592187f6 100644 --- a/docs/architecture/porting-existing-aspnet-apps/authentication-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/authentication-differences.md @@ -1,11 +1,11 @@ --- -title: Comparing Authentication and Authorization between ASP.NET MVC and ASP.NET Core +title: Compare Authentication and Authorization between ASP.NET MVC and ASP.NET Core description: A summary of authentication and authorization differences between ASP.NET MVC and ASP.NET Core. author: ardalis ms.date: 11/13/2020 --- -# Comparing authentication and authorization between ASP.NET MVC and ASP.NET Core +# Compare authentication and authorization between ASP.NET MVC and ASP.NET Core In ASP.NET MVC 5, authentication is configured in `Startup.Auth.cs` in the `App_Start` folder. In ASP.NET Core MVC, this configuration occurs in `Startup.cs`. Authentication and authorization are performed using middleware added to the request pipeline in `ConfigureServices`: @@ -28,13 +28,13 @@ app.UseEndpoints(endpoints => It's important to add the auth middleware in the appropriate location in the middleware pipeline. Only requests that make it to the middleware will be impacted by it. For instance, if a call to `UseStaticFiles()` was placed above the code shown here, it wouldn't be protected by authentication and authorization. -In ASP.NET MVC and Web API, applications often refer to the current user using the `ClaimsPrincipal.Current` property. This property isn't set in ASP.NET Core, and any behavior in your app that depends on it will need to [migrate from ClaimsPrincipal.Current](https://docs.microsoft.com/aspnet/core/migration/claimsprincipal-current) by using the `User` property on `ControllerBase` or getting access to the current `HttpContext` and referencing its `User` property. If neither of these solutions is an option, services can request the User as an argument, in which case it must be supplied from elsewhere in the app, or the `IHttpContextAccessor` can be requested and used to get the `HttpContext`. +In ASP.NET MVC and Web API, apps often refer to the current user using the `ClaimsPrincipal.Current` property. This property isn't set in ASP.NET Core, and any behavior in your app that depends on it will need to [migrate from ClaimsPrincipal.Current](https://docs.microsoft.com/aspnet/core/migration/claimsprincipal-current) by using the `User` property on `ControllerBase` or getting access to the current `HttpContext` and referencing its `User` property. If neither of these solutions is an option, services can request the User as an argument, in which case it must be supplied from elsewhere in the app, or the `IHttpContextAccessor` can be requested and used to get the `HttpContext`. ## Authorization -Authorization defines what a given user can do within the app. It's separate from authentication, which is concerned merely with identifying who the user is. ASP.NET Core provides a simple, declarative role and a rich policy-based model for authorization. Specifying that a resource requires authorization is often as simple as adding the `[Authorize]` attribute to the action or controller. If you're migrating to Razor Pages from MVC views, you should [specify conventions for authorization when you configure Razor Pages in Startup](https://docs.microsoft.com/aspnet/core/security/authorization/razor-pages-authorization). +Authorization defines what a given user can do within the app. It's separate from authentication, which is concerned merely with identifying who the user is. ASP.NET Core provides a simple, declarative role and a rich, policy-based model for authorization. Specifying that a resource requires authorization is often as simple as adding the `[Authorize]` attribute to the action or controller. If you're migrating to Razor Pages from MVC views, you should [specify conventions for authorization when you configure Razor Pages in Startup](https://docs.microsoft.com/aspnet/core/security/authorization/razor-pages-authorization). -Authorization in ASP.NET Core may be as simple as prohibiting anonymous users while allowing authenticated users. Or it can scale up to support role-based, claims-based, or policy-based authorization approaches. For more information on these approaches, see the documentation on [authorization in ASP.NET Core](https://docs.microsoft.com/aspnet/core/security/authorization/introduction). It's likely you'll find that one of them is fairly closely aligned with your current authorization approach. +Authorization in ASP.NET Core may be as simple as prohibiting anonymous users while allowing authenticated users. Or it can scale up to support role-based, claims-based, or policy-based authorization approaches. For more information on these approaches, see the documentation on [authorization in ASP.NET Core](https://docs.microsoft.com/aspnet/core/security/authorization/introduction). You'll likely find that one of them is closely aligned with your current authorization approach. ## References diff --git a/docs/architecture/porting-existing-aspnet-apps/choose-net-core-version.md b/docs/architecture/porting-existing-aspnet-apps/choose-net-core-version.md index 9129c9f827b24..a6dcedb4851f5 100644 --- a/docs/architecture/porting-existing-aspnet-apps/choose-net-core-version.md +++ b/docs/architecture/porting-existing-aspnet-apps/choose-net-core-version.md @@ -9,11 +9,11 @@ ms.date: 11/13/2020 The largest consideration for most organizations when choosing a version of .NET Core to target is the support lifecycle. Long Term Support (LTS) releases ship less frequently but have a longer support window than Current (non-LTS) releases. Currently, LTS releases are scheduled to ship every other year. Customers can choose which releases to target, and can install different releases of .NET Core side by side on the same machine. LTS releases will receive only critical and compatible fixes throughout their lifecycle. Current releases will receive these same fixes and will also be updated with compatible innovations and features. LTS releases are supported for three years after their initial release. Current releases are supported for three months after a subsequent Current or LTS release. -Most customers looking to migrate a large .NET Framework application to .NET Core today are probably looking for a stable destination, given that they haven't already made the move to an earlier version of .NET Core. In this case, the best .NET Core version to target for the migration is .NET Core 3.1, which is the current LTS version. Support for .NET Core 3.1 ends in December 2022. The next planned LTS release will be .NET 6.0, slated to ship in November 2021. +Most customers looking to migrate a large .NET Framework app to .NET Core today are probably looking for a stable destination, given that they haven't already made the move to an earlier version of .NET Core. In this case, the best .NET Core version to target for the migration is .NET Core 3.1, which is the current LTS version. Support for .NET Core 3.1 ends in December 2022. The next planned LTS release will be .NET 6.0, slated to ship in November 2021. -Updating from .NET Core 3.1 to .NET 5.0 (the next version) is relatively straightforward and certainly will require substantially less effort than porting from .NET Framework to .NET Core. For this reason, the recommendation for most customers is to upgrade to .NET Core 3.1 first. Then decide whether the next update should be to the latest current release (.NET 5.0) or to wait for the next LTS release (.NET 6.0) before upgrading further. +Updating from .NET Core 3.1 to .NET 5.0 (the next version) requires much less effort than porting from .NET Framework to .NET Core. For this reason, the recommendation for most customers is to upgrade to .NET Core 3.1 first. Then decide whether the next update should be to the latest current release (.NET 5.0) or to wait for the next LTS release (.NET 6.0) before upgrading further. -This book assumes .NET Framework applications will be upgraded to .NET Core 3.1. +This book assumes .NET Framework apps will be upgraded to .NET Core 3.1. ## References diff --git a/docs/architecture/porting-existing-aspnet-apps/comparing-razor-pages-aspnet-mvc.md b/docs/architecture/porting-existing-aspnet-apps/comparing-razor-pages-aspnet-mvc.md index 6b9e36233620f..7f0c11bc47729 100644 --- a/docs/architecture/porting-existing-aspnet-apps/comparing-razor-pages-aspnet-mvc.md +++ b/docs/architecture/porting-existing-aspnet-apps/comparing-razor-pages-aspnet-mvc.md @@ -1,11 +1,11 @@ --- -title: Comparing Razor Pages to ASP.NET MVC +title: Compare Razor Pages to ASP.NET MVC description: Razor Pages offer a better way to organize responsibilities than traditional MVC views for page-based apps. Learn how they compare to the traditional ASP.NET MVC approach in this section. author: ardalis ms.date: 11/13/2020 --- -# Comparing Razor Pages to ASP.NET MVC +# Compare Razor Pages to ASP.NET MVC Razor Pages is the preferred way to create page- or form-based apps in ASP.NET Core. From the [docs](https://docs.microsoft.com/aspnet/core/razor-pages/), "Razor Pages can make coding page-focused scenarios easier and more productive than using controllers and views." If your ASP.NET MVC app makes heavy use of views, you may want to consider migrating from actions and views to Razor Pages. diff --git a/docs/architecture/porting-existing-aspnet-apps/configuration-differences.md b/docs/architecture/porting-existing-aspnet-apps/configuration-differences.md index bf11405ab30c3..5edfbb44fe476 100644 --- a/docs/architecture/porting-existing-aspnet-apps/configuration-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/configuration-differences.md @@ -13,7 +13,7 @@ How configuration values are stored and read changed dramatically between ASP.NE In ASP.NET apps, configuration uses the built-in .NET configuration files, *web.config* in the app folder and *machine.config* on the server. Most ASP.NET MVC and Web API apps store any settings they need in the configuration file's appsettings or connection strings elements. Some also use custom configuration sections that can be mapped to a settings class. -Configuration in .NET Framework applications is accessed using the `System.Configuration.ConfigurationManager` class. Unfortunately, this class provides static access to the configuration elements. As a result, very few ASP.NET MVC apps tend to abstract access to their configuration settings or inject them where needed. Instead, most .NET Framework apps tend to directly access the configuration system anywhere the app needs to use a setting. +Configuration in a .NET Framework app is accessed using the `System.Configuration.ConfigurationManager` class. Unfortunately, this class provides static access to the configuration elements. As a result, very few ASP.NET MVC apps tend to abstract access to their configuration settings or inject them where needed. Instead, most .NET Framework apps tend to directly access the configuration system anywhere the app needs to use a setting. Typical ASP.NET MVC configuration access: @@ -24,9 +24,9 @@ string connString = ConfigurationManager.ConnectionStrings["DefaultConnection"] ## ASP.NET Core configuration -In ASP.NET Core apps, configuration is, itself, configurable. However, most apps use a set of defaults provided as part of the standard project templates and the `ConfigureWebHostDefaults` method used in them. The default settings use JSON formatted files, with the ability to override settings in the base `appsettings.json` file with environment-specific files like `appsettings.Development.json`. Additionally, the default configuration system further overrides all file-based settings with any environment variable that exists for the same named setting. This is useful in a number of scenarios and is especially useful when deploying to a hosting environment, since it eliminates the need to worry about whether deploying configuration files will accidentally overwrite important production configuration settings. +In ASP.NET Core apps, configuration is, itself, configurable. However, most apps use a set of defaults provided as part of the standard project templates and the `ConfigureWebHostDefaults` method used in them. The default settings use JSON formatted files, with the ability to override settings in the base `appsettings.json` file with environment-specific files like `appsettings.Development.json`. Additionally, the default configuration system further overrides all file-based settings with any environment variable that exists for the same named setting. This is useful in many scenarios and is especially useful when deploying to a hosting environment, since it eliminates the need to worry about whether deploying configuration files will accidentally overwrite important production configuration settings. -Accessing configuration values can be done in a number of ways in .NET Core. Because dependency injection is built into .NET Core, configuration values are generally accessed through an interface that is injected into classes that need them. This can involve passing a large interface like `IConfiguration`, but usually it's better to pass just the settings required by the class using the [options pattern](https://docs.microsoft.com/aspnet/core/fundamentals/configuration/options). +Accessing configuration values can be done in many ways in .NET Core. Because dependency injection is built into .NET Core, configuration values are generally accessed through an interface that is injected into classes that need them. This can involve passing a large interface like `IConfiguration`, but usually it's better to pass just the settings required by the class using the [options pattern](https://docs.microsoft.com/aspnet/core/fundamentals/configuration/options). Figure 2-2 shows how to pass `IConfiguration` into a Razor Page and access configuration settings from it: diff --git a/docs/architecture/porting-existing-aspnet-apps/controller-differences.md b/docs/architecture/porting-existing-aspnet-apps/controller-differences.md index b579541c7bce1..dc863b5dcdf0e 100644 --- a/docs/architecture/porting-existing-aspnet-apps/controller-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/controller-differences.md @@ -1,5 +1,5 @@ --- -title: Comparing controllers in ASP.NET MVC and ASP.NET Core +title: Compare controllers in ASP.NET MVC and ASP.NET Core description: ASP.NET Core MVC controllers are similar to ASP.NET MVC 5 and Web API 2 controllers, but there are important differences. This section examines the differences and steps needed to port apps from ASP.NET MVC and Web API 2 to ASP.NET Core. author: ardalis ms.date: 11/13/2020 @@ -7,9 +7,9 @@ ms.date: 11/13/2020 # Compare controllers in ASP.NET MVC and Web API with controllers in ASP.NET Core -In ASP.NET MVC 5 and Web API 2, there were two different `Controller` base types. MVC controllers inherited from `Controller`; Web API controllers inherited from `ApiController`. In ASP.NET Core, this is no longer the case, and the object hierarchy has been merged. It is recommended that API controllers in ASP.NET Core inherit from `ControllerBase` and add the `[ApiController]` attribute. Standard view-based MVC controllers should inherit from `Controller`. +In ASP.NET MVC 5 and Web API 2, there were two different `Controller` base types. MVC controllers inherited from `Controller`; Web API controllers inherited from `ApiController`. In ASP.NET Core, this object hierarchy has been merged. It's recommended that API controllers in ASP.NET Core inherit from `ControllerBase` and add the `[ApiController]` attribute. Standard view-based MVC controllers should inherit from `Controller`. -In both frameworks, controllers are used to organize sets of action methods. Filters and routes can be applied on a controller level in addition to at the action level. These conventions can be extended further through the use of custom base `Controller` types with default behavior and attributes applied to them. +In both frameworks, controllers are used to organize sets of action methods. Filters and routes can be applied on a controller level in addition to at the action level. These conventions can be extended further by using custom base `Controller` types with default behavior and attributes applied to them. In ASP.NET MVC, content negotiation isn't supported. ASP.NET Web API 2 does support content negotiation, as does ASP.NET Core. Using [content negotiation](https://docs.microsoft.com/aspnet/core/web-api/advanced/formatting), the format of the content returned to a request can be determined by headers the client provides indicating its preferred manner of receiving the content. diff --git a/docs/architecture/porting-existing-aspnet-apps/dependency-injection-differences.md b/docs/architecture/porting-existing-aspnet-apps/dependency-injection-differences.md index 3afc03d850494..1292a0a3db75a 100644 --- a/docs/architecture/porting-existing-aspnet-apps/dependency-injection-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/dependency-injection-differences.md @@ -15,7 +15,7 @@ Although dependency injection isn't built into ASP.NET MVC or Web API, many apps - [StructureMap](http://structuremap.github.io/) *(deprecated)* - [Castle Windsor](http://www.castleproject.org/projects/windsor/) -If your ASP.NET MVC application isn't using dependency injection, you will probably want to investigate the built-in support for DI in ASP.NET Core. Dependency injection helps keep modules in your app loosely coupled from one another, and enables better testability and adherence to principles like [SOLID](https://www.weeklydevtips.com/episodes/047). +If your ASP.NET MVC app isn't using dependency injection, you will probably want to investigate the built-in support for DI in ASP.NET Core. Dependency injection helps keep modules in your app loosely coupled from one another, and enables better testability and adherence to principles like [SOLID](https://www.weeklydevtips.com/episodes/047). If your app does use dependency injection, then probably your best course of action is to see if the container you're using supports ASP.NET Core. If so, you may be able to continue using it and your custom configuration rules describing your type mappings and lifetimes. @@ -23,7 +23,7 @@ Either way, you should consider using the built-in support for dependency inject ## Dependency injection in ASP.NET Core -ASP.NET Core assumes apps will use dependency injection. It's not just built into the framework, but is required in order to bring support for framework features into your ASP.NET Core apps. In application startup, a call is made to `ConfigureServices` which is responsible for registering all of the types that the DI container (service collection/service provider) can create and inject in the app. Built-in ASP.NET Core features like Entity Framework Core, Identity, and even MVC are brought into the app by configuring them as services in the `ConfigureServices` method. +ASP.NET Core assumes apps will use dependency injection. It's not just built into the framework, but is required in order to bring support for framework features into your ASP.NET Core apps. In app startup, a call is made to `ConfigureServices` which is responsible for registering all of the types that the DI container (service collection/service provider) can create and inject in the app. Built-in ASP.NET Core features like Entity Framework Core, Identity, and even MVC are brought into the app by configuring them as services in the `ConfigureServices` method. In addition to using the default implementation, apps can still use custom containers. The [documentation covers how to replace the default service container](https://docs.microsoft.com/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1#default-service-container-replacement). diff --git a/docs/architecture/porting-existing-aspnet-apps/deployment-scenarios.md b/docs/architecture/porting-existing-aspnet-apps/deployment-scenarios.md index 82426e887d282..1292b8a49f509 100644 --- a/docs/architecture/porting-existing-aspnet-apps/deployment-scenarios.md +++ b/docs/architecture/porting-existing-aspnet-apps/deployment-scenarios.md @@ -28,33 +28,33 @@ Fortunately, IIS is a very feature-rich web server, and two features it has had As a reverse proxy, IIS can route traffic matching certain patterns to entirely separate apps, potentially on different servers. -Using just the URL Rewrite module (perhaps combined with host headers), IIS can easily support multiple web sites, each potentially running different versions of .NET. A large web application might be deployed as a collection of individual sites, each responding to different IP addresses and/or host headers, or as a single web site with one or more sub-applications in it responding to certain URL paths (which doesn't even require URL Rewrite). +Using just the URL Rewrite module (perhaps combined with host headers), IIS can easily support multiple web sites, each potentially running different versions of .NET. A large web app might be deployed as a collection of individual sites, each responding to different IP addresses and/or host headers, or as a single web site with one or more sub-applications in it responding to certain URL paths (which doesn't even require URL Rewrite). **Note:** Subdomains typically refer to the portion of a domain preceding the top two levels. For example, in the domain `api.contoso.com`, `api` is a subdomain of the `contoso.com` domain (which itself is composed of the `contoso` domain name and the `.com` top-level domain or TLD). URL paths refer to portion of the URL that follows the domain name, starting with a `/`. The URL `https://contoso.com/api` has a path of `/api`. -There are pros and cons to using the same or different subdomains (and domains) to host a single application. Features like cookies and intra-app communication using mechanisms like [CORS](https://docs.microsoft.com/aspnet/core/security/cors) may require more configuration to work properly in distributed apps. However, apps that use different subdomains can more easily use DNS to route requests to entirely different network destinations, and so can more easily be deployed to many different servers (virtual or otherwise) without the need for IIS to act as a reverse proxy. +There are pros and cons to using the same or different subdomains (and domains) to host a single app. Features like cookies and intra-app communication using mechanisms like [CORS](https://docs.microsoft.com/aspnet/core/security/cors) may require more configuration to work properly in distributed apps. However, apps that use different subdomains can more easily use DNS to route requests to entirely different network destinations, and so can more easily be deployed to many different servers (virtual or otherwise) without the need for IIS to act as a reverse proxy. In the example described above, assume the API endpoints are designated as the first part of the app to be ported to ASP.NET Core. In this case, a new ASP.NET Core app is created and hosted in IIS as a separate web *application* within the existing ASP.NET MVC web *site*. Since it will be added as a child of the original web site and will be named `api`, its default route should no longer begin with `api/` (keeping this would result in it matching URLs of the form `/api/api/endpoint`). -Figure 5-1 shows how the ASP.NET Core 2.1 `api` application appears in IIS Manager as a part of the existing `DotNetMvcApp` site. +Figure 5-1 shows how the ASP.NET Core 2.1 `api` app appears in IIS Manager as a part of the existing `DotNetMvcApp` site. -![IIS Manager showing api application within .NET Framework site](./media/Figure5-1.png) +![IIS Manager showing api app within .NET Framework site](./media/Figure5-1.png) -**Figure 5-1**. .NET Framework Site with .NET Core application in IIS. +**Figure 5-1**. .NET Framework Site with .NET Core app in IIS. -The `DotNetMvcApp` site is hosted as an MVC 5 app running on .NET Framework version 4.7.2. It has its own IIS application pool configured in integrated mode and running .NET CLR Version v4.0.30319. The `api` application is an ASP.NET Core app running on .NET Framework version 4.6.1 (`net461`). It was added to the `DotNetMvcApp` as a new IIS application and configured to use its own Application Pool. Its Application Pool is also running in integrated mode but is configured with a .NET CLR version of `No Managed Code` since it will be executed using the [ASP.NET Core Module](https://docs.microsoft.com/aspnet/core/host-and-deploy/aspnet-core-module?view=aspnetcore-2.1). The version of the ASP.NET Core app is just an example; it could also be configured to run on .NET Core 3.1 or .NET 5, though at that point it would no longer be able to target .NET Framework libraries (see [Choose the Right .NET Core Version](choose-net-core-version.md)) +The `DotNetMvcApp` site is hosted as an MVC 5 app running on .NET Framework version 4.7.2. It has its own IIS app pool configured in integrated mode and running .NET CLR Version v4.0.30319. The `api` app is an ASP.NET Core app running on .NET Framework version 4.6.1 (`net461`). It was added to the `DotNetMvcApp` as a new IIS app and configured to use its own Application Pool. Its Application Pool is also running in integrated mode but is configured with a .NET CLR version of `No Managed Code` since it will be executed using the [ASP.NET Core Module](https://docs.microsoft.com/aspnet/core/host-and-deploy/aspnet-core-module?view=aspnetcore-2.1). The version of the ASP.NET Core app is just an example; it could also be configured to run on .NET Core 3.1 or .NET 5.0, though at that point it would no longer be able to target .NET Framework libraries (see [Choose the Right .NET Core Version](choose-net-core-version.md)) Configured in this manner, the only change that must be made in order for the ASP.NET Core app's APIs to be routed properly is to change its default route template from `[Route("[api/controller]")]` to `[Route("[controller]")]`. Alternately the ASP.NET Core app can be another top-level web site in IIS. In this case, you can configure the original site to use a rewrite rule (with [URL Rewrite](https://www.iis.net/downloads/microsoft/url-rewrite)) that will redirect to the other app if the path starts with `/api`. The ASP.NET Core app can use a different host header for its route so that it doesn't conflict with the main app but can still respond to requests using root-based routes. -As an example, the same ASP.NET Core app used in Figure 5-1 can be deployed to another folder configured as an IIS web site. The site should use an application pool configured just as before, with `No Managed Code`. Configure its bindings to respond to a unique host name on the server, such as `api.contoso.com`. To configure URL Rewrite to rewrite requests matching `/api` just add a new inbound rule at the IIS server (or individual site) level. Match the pattern `^/api(.*)` and specify an Action type of `Rewrite` and a Rewrite URL of `api.contoso.com/{R:1}`. The combination of using `(.*)` in the matching pattern and `{R:1}` in the rewrite URL will ensure the rest of the path gets used with the new URL. With this in place, separate sites on the same IIS server can coexist running separate versions of .NET, but they can be made to appear to the Internet as one web application. Figure 5-2 shows the rewrite rule as configured in IIS with the separate web site. +As an example, the same ASP.NET Core app used in Figure 5-1 can be deployed to another folder configured as an IIS web site. The site should use an app pool configured just as before, with `No Managed Code`. Configure its bindings to respond to a unique host name on the server, such as `api.contoso.com`. To configure URL Rewrite to rewrite requests matching `/api` just add a new inbound rule at the IIS server (or individual site) level. Match the pattern `^/api(.*)` and specify an Action type of `Rewrite` and a Rewrite URL of `api.contoso.com/{R:1}`. The combination of using `(.*)` in the matching pattern and `{R:1}` in the rewrite URL will ensure the rest of the path gets used with the new URL. With this in place, separate sites on the same IIS server can coexist running separate versions of .NET, but they can be made to appear to the Internet as one web app. Figure 5-2 shows the rewrite rule as configured in IIS with the separate web site. ![IIS Manager showing URL Rewrite rule to route subfolder requests to separate web site](./media/Figure5-2.png) **Figure 5-2**. Rewrite rule to rewrite subfolder requests to another web site. -If your app requires single sign-on between different sites or applications within IIS, refer to the documentation on [how to share authentication cookies among ASP.NET apps](https://docs.microsoft.com/aspnet/core/host-and-deploy/iis/) for detailed instructions on supporting this scenario. +If your app requires single sign-on between different sites or apps within IIS, refer to the documentation on [how to share authentication cookies among ASP.NET apps](https://docs.microsoft.com/aspnet/core/host-and-deploy/iis/) for detailed instructions on supporting this scenario. ## Summary diff --git a/docs/architecture/porting-existing-aspnet-apps/deployment-strategies.md b/docs/architecture/porting-existing-aspnet-apps/deployment-strategies.md index 0a495844a08f5..7d782c66e5b3e 100644 --- a/docs/architecture/porting-existing-aspnet-apps/deployment-strategies.md +++ b/docs/architecture/porting-existing-aspnet-apps/deployment-strategies.md @@ -7,27 +7,30 @@ ms.date: 11/13/2020 # Deployment strategies -One consideration as you plan the migration of your large ASP.NET app to ASP.NET Core is how you will deploy the new app. With ASP.NET, deployment options were limited to IIS on Windows. With ASP.NET Core, a much wider array of deployment options are available. +One consideration as you plan the migration of your large ASP.NET app to ASP.NET Core is how you'll deploy the new app. With ASP.NET, deployment options were limited to IIS on Windows. With ASP.NET Core, a much wider array of deployment options is available. ## Cross-platform options -Because .NET Core supports Linux, you may now find some hosting options available that weren't a consideration previously. Linux-based hosting may be preferable either because your organization has infrastructure or expertise, or because hosting providers offer attractive features or pricing for Linux-based hosting. .NET Core opens to door to these options. +Because .NET Core supports Linux, you'll find some hosting options available that weren't a consideration previously. Linux-based hosting may be preferable for the following reasons: + +* Your organization has infrastructure or expertise. +* Hosting providers offer attractive features or pricing for Linux-based hosting. + +.NET Core opens to door to these options. ## Cloud native development -Most organizations today are leveraging cloud platforms for at least some of their software capabilities. With a migration of an app to .NET Core, it's a good time to consider whether the app should be purposefully written with cloud hosting in mind. Such *cloud native* apps are better able to leverage cloud capabilities like serverless, microservices, and can be less concerned with the low level details of how and where they may be deployed. +Most organizations today are using cloud platforms for at least some of their software capabilities. With an app migration to .NET Core, it's a good time to consider whether the app should be purposefully written with cloud hosting in mind. Such *cloud native* apps are better able to apply cloud capabilities like serverless, microservices, and can be less concerned with the low-level details of how and where they may be deployed. Learn more about cloud native app development in this free e-book, [Architecting Cloud Native .NET Applications for Azure](/dotnet/architecture/cloud-native/). -## Leveraging containers +## Leverage containers Modern apps often leverage containers as a means of reducing variation between hosting environments. By deploying an app to a particular container, the container-hosted app will run the same whether it's running on a developer's laptop or in production. As part of a migration to .NET Core, it may make sense to consider whether the app would benefit from deployment via container, either as a full monolith or broken up into multiple smaller containerized apps. -TODO: Add figure showing migration to container-hosted app or apps. - ## Side-by-side deployment options -Migrating large .NET Framework apps to .NET Core often requires a substantial effort. Most organizations will want to be able to break this effort up in some fashion, so that pieces of the app can be migrated and deployed in production before the entire migration is complete. Running both the original ASP.NET application and its newly-migrated ASP.NET Core sub-app(s) side by side is a frequently cited goal. This can be achieved through a number of mechanisms including leveraging IIS routing, which is covered in [chapter 5](deployment-scenarios.md). Other options include leveraging application gateways or cloud design patterns like [backends for frontends](https://docs.microsoft.com/azure/architecture/patterns/backends-for-frontends) to manage sets of ASP.NET Web APIs and ASP.NET Core API endpoints. +Migrating large .NET Framework apps to .NET Core often requires a substantial effort. Most organizations will want to be able to break this effort up in some fashion, so that pieces of the app can be migrated and deployed in production before the entire migration is complete. Running both the original ASP.NET app and its newly-migrated ASP.NET Core sub-app(s) side by side is a frequently cited goal. This can be achieved through a number of mechanisms including leveraging IIS routing, which is covered in [chapter 5](deployment-scenarios.md). Other options include leveraging app gateways or cloud design patterns like [backends for frontends](https://docs.microsoft.com/azure/architecture/patterns/backends-for-frontends) to manage sets of ASP.NET Web APIs and ASP.NET Core API endpoints. ## IIS on Windows diff --git a/docs/architecture/porting-existing-aspnet-apps/example-migration-eshop.md b/docs/architecture/porting-existing-aspnet-apps/example-migration-eshop.md index ea0d552b1ca90..87d954a3a1d8a 100644 --- a/docs/architecture/porting-existing-aspnet-apps/example-migration-eshop.md +++ b/docs/architecture/porting-existing-aspnet-apps/example-migration-eshop.md @@ -9,7 +9,7 @@ ms.date: 11/13/2020 [!INCLUDE [book-preview](../../../includes/book-preview.md)] -In this chapter you'll see how to migrate a .NET Framework app to .NET Core. The chapter will examine a sample online store app written for ASP.NET 5 and will go leverage many of the concepts and tools described earlier in this book. You'll find the starting point application in the [eShopModernizing GitHub repository](https://github.com/dotnet-architecture/eShopModernizing). There are several different starting point apps; this chapter will focus on the `eShopLegacyMVCSolution`. +In this chapter you'll see how to migrate a .NET Framework app to .NET Core. The chapter will examine a sample online store app written for ASP.NET 5.0 and will go leverage many of the concepts and tools described earlier in this book. You'll find the starting point app in the [eShopModernizing GitHub repository](https://github.com/dotnet-architecture/eShopModernizing). There are several different starting point apps; this chapter will focus on the `eShopLegacyMVCSolution`. The initial version of the project is shown in Figure 4-1. It's a fairly standard ASP.NET MVC 5 app. @@ -19,7 +19,7 @@ The initial version of the project is shown in Figure 4-1. It's a fairly standar ## Run ApiPort to identify problematic APIs -The first step in preparing to migrate is to run the ApiPort tool to get a sense of how many .NET Framework APIs the app calls, and how many of these have .NET Standard or .NET Core equivalents. Focus primarily on your own app's logic, not third party dependencies, and pay attention to System.Web dependencies that will need to be ported. The ApiPort tool was introduced in the last chapter on [understanding and updating dependencies](/understand-update-dependencies.md). +The first step in preparing to migrate is to run the ApiPort tool to get a sense of how many .NET Framework APIs the app calls, and how many of these have .NET Standard or .NET Core equivalents. Focus primarily on your own app's logic, not third-party dependencies, and pay attention to `System.Web` dependencies that will need to be ported. The ApiPort tool was introduced in the last chapter on [understanding and updating dependencies](/understand-update-dependencies.md). After [installing and configuring the ApiPort tool](https://docs.microsoft.com/dotnet/standard/analyzers/portability-analyzer), run the analysis from within Visual Studio, as shown in Figure 4-2. @@ -35,13 +35,13 @@ Choose the web project's assembly from the project's `/bin` folder, as shown in If your solution includes several projects, you can choose all of them. The eShop sample includes just a single MVC project. -Once the report is generated, open the file and review the results. The summary provides a high level view of what percentage of .NET Framework calls your app is making have compatible versions. Figure 4-4 shows the summary for the eShop MVC project. +Once the report is generated, open the file and review the results. The summary provides a high-level view of what percentage of .NET Framework calls your app is making have compatible versions. Figure 4-4 shows the summary for the eShop MVC project. ![Figure 4-4](media/Figure4-4.png) **Figure 4-4. ApiPort summary.** -For this app, about 80% of the .NET Framework calls are compatible, meaning 20% will need to be addressed in some way as part of the porting process. Viewing the details reveals that all of the incompatible calls are part of `System.Web`, which is an expected incompatibility. The dependencies on `System.Web` calls will be addressed when the app's controllers and related classes are migrated in a later step. Figure 4-5 lists some of the specific types found by the tool: +For this app, about 80 percent of the .NET Framework calls are compatible, meaning 20 percent will need to be addressed in some way as part of the porting process. Viewing the details reveals that all of the incompatible calls are part of `System.Web`, which is an expected incompatibility. The dependencies on `System.Web` calls will be addressed when the app's controllers and related classes are migrated in a later step. Figure 4-5 lists some of the specific types found by the tool: ![Figure 4-5](media/Figure4-5.png) @@ -51,7 +51,7 @@ Most of the incompatible types refer to `Controller` and various related attribu ## Update project files and NuGet reference syntax -The next step is to migrate from the older .csproj file structure to the newer, simpler one introduced with .NET Core. In doing so, you will also migrate from using a `packages.config` file for NuGet references to using `` elements in the project file. +The next step is to migrate from the older *.csproj* file structure to the newer, simpler one introduced with .NET Core. In doing so, you'll also migrate from using a `packages.config` file for NuGet references to using `` elements in the project file. The original project's `eShopLegacyMVC.csproj` file is 418 lines long. A sample of it is shown in Figure 4-6, which includes a miniature view of the entire file on the right side to offer a sense of its overall size and complexity. @@ -59,25 +59,25 @@ The original project's `eShopLegacyMVC.csproj` file is 418 lines long. A sample **Figure 4-6. The eShopLegacyMVC.csproj file structure.** -A common way to create a new project file for an existing ASP.NET project is to create a new ASP.NET Core app using `dotnet new` or `File - New - Project` in Visual Studio. Then files can be copied from the old project to the new one to complete the migration. +A common way to create a new project file for an existing ASP.NET project is to create a new ASP.NET Core app using `dotnet new` or **File** > **New** > **Project** in Visual Studio. Then files can be copied from the old project to the new one to complete the migration. -In addition to the C# project file, NuGet dependencies are stored in a separate 45 line long `packages.config` file, shown in Figure 4-7. +In addition to the C# project file, NuGet dependencies are stored in a separate 45-line `packages.config` file, as shown in Figure 4-7. ![Figure 4-7](media/Figure4-7.png) **Figure 4-7. The packages.config file.** -After upgrading to the new csproj file format, you can migrate `packages.config` in class library projects using Visual Studio (this functionality doesn't work with ASP.NET projects, however). [Learn more about migrating package.config to PackageReference in Visual Studio](https://docs.microsoft.com/nuget/consume-packages/migrate-packages-config-to-package-reference). If you have a large number of projects to migrate, [this community tool may help](https://github.com/MarkKharitonov/NuGetPCToPRMigrator). +After upgrading to the new *.csproj* file format, you can migrate `packages.config` in class library projects using Visual Studio. This functionality doesn't work with ASP.NET projects, however. [Learn more about migrating package.config to PackageReference in Visual Studio](https://docs.microsoft.com/nuget/consume-packages/migrate-packages-config-to-package-reference). If you have a large number of projects to migrate, [this community tool may help](https://github.com/MarkKharitonov/NuGetPCToPRMigrator). ## Create new ASP.NET Core project -Add a new ASP.NET Core project to the existing app's solution to make moving files easier, as most of the work can be done from within Visual Studio's Solution Explorer. In Visual Studio, right-click on your app's solution and choose Add New Project. Choose ASP.NET Core web application, and give the new project a name as shown in Figure 4-8. +Add a new ASP.NET Core project to the existing app's solution to make moving files easier, as most of the work can be done from within Visual Studio's **Solution Explorer**. In Visual Studio, right-click on your app's solution and choose **Add New Project**. Choose **ASP.NET Core web application**, and give the new project a name as shown in Figure 4-8. ![Figure 4-8](media/Figure4-8.png) **Figure 4-8. Add new ASP.NET Core web application.** -The next dialog will ask you to choose which template to use. Select the Empty template, and be sure to also change the dropdown from .NET Core to .NET Framework, and select ASP.NET Core 2.2 as shown in Figure 4-9. +The next dialog will ask you to choose which template to use. Select the **Empty** template, and be sure to also change the dropdown from .NET Core to .NET Framework, and select ASP.NET Core 2.2 as shown in Figure 4-9. ![Figure 4-9](media/Figure4-9.png) @@ -85,7 +85,7 @@ The next dialog will ask you to choose which template to use. Select the Empty t ### Migrating NuGet Packages -Since the built-in migration tool for migrating `packages.config` to PackageReference doesn't work on ASP.NET projects, you can use a community tool instead, or migrate by hand. A community tool I've used is available here and uses an XSL sheet to transform from one format to the other. To use it, first copy the `packages.config` file to the newly created ASP.NET Core project folder. Make a backup of your files (this script will remove the `package.config` file from all folders under where you run the script). Then run these commands from the project folder (or for the entire solution if you prefer): +Since the built-in migration tool for migrating `packages.config` to `` doesn't work on ASP.NET projects, you can use a community tool instead, or migrate by hand. A community tool I've used is available here and uses an XSL file to transform from one format to the other. To use it, first copy the `packages.config` file to the newly created ASP.NET Core project folder. Make a backup of your files (this script will remove the `package.config` file from all folders under where you run the script). Then run these commands from the project folder (or for the entire solution if you prefer): ```powershell iwr https://git.io/vdKaV -OutFile Convert-ToPackageReference.ps1 @@ -95,7 +95,7 @@ iwr https://git.io/vdKar -OutFile Convert-ToPackageReference.xsl The first two commands download files so that they exist locally; the last line runs the script. After running it, try to build the new project. You'll most likely get some errors. To resolve them, you'll want to eliminate some references (like most of the `Microsoft.AspNet` and `System` packages), and you may need to remove some `xmlns` attributes. -In most ASP.NET MVC apps, many client-side dependencies like Bootstrap and jQuery were deployed using NuGet packages. In .NET Core, NuGet packages are only used for server side functionality; client files should be managed through other means. Review the list of `PackageReference` elements added and remove and make note of any that are for client libraries, including: +In most ASP.NET MVC apps, many client-side dependencies like Bootstrap and jQuery were deployed using NuGet packages. In .NET Core, NuGet packages are only used for server-side functionality; client files should be managed through other means. Review the list of `` elements added and remove and make note of any that are for client libraries, including: - bootstrap - jQuery @@ -104,23 +104,23 @@ In most ASP.NET MVC apps, many client-side dependencies like Bootstrap and jQuer - popper.js - Respond -The static client files installed by NuGet for these packages will be copied over to the new project's `wwwroot` folder and hosted from there. It's worth considering whether these files are still needed by the app, and whether it makes sense to continue hosting them or to use a content delivery network (CDN) instead. Managing versions of these libraries can be done at build time using tools like [LibMan](https://docs.microsoft.com/aspnet/core/client-side/libman/) or [npm](https://www.npmjs.com/). Figure 4-10 shows the full eShopPorted.csproj file after migrating package references using the conversion tool shown and removing unnecessary packages. +The static client files installed by NuGet for these packages will be copied over to the new project's `wwwroot` folder and hosted from there. It's worth considering whether these files are still needed by the app, and whether it makes sense to continue hosting them or to use a content delivery network (CDN) instead. Managing versions of these libraries can be done at build time using tools like [LibMan](https://docs.microsoft.com/aspnet/core/client-side/libman/) or [npm](https://www.npmjs.com/). Figure 4-10 shows the full *eShopPorted.csproj* file after migrating package references using the conversion tool shown and removing unnecessary packages. ![Figure 4-10](media/Figure4-10.png) **Figure 4-10. Package References in the eShopPorted.csproj file.** -Note that the package references can be further compacted by making the `1.0.0.0` element a `Version=1.0.0.0` attribute on ``. +The package references can be further compacted by making the `1.0.0.0` element a `Version=1.0.0.0` attribute on ``. ### Migrate static files -Any static files the app uses, including third party scripts and frameworks but also custom images and stylesheets, must be copied from the old project to the new one. In ASP.NET MVC apps, files were typically accessed based on their location within the project folder. In ASP.NET Core apps, these static files will be accessed based on their location within the `wwwroot` folder. For the eShop project, there are static files in the `Content`, `fonts`, `Images`, `Pics`, and `Scripts` folders. The empty project template used in the previous step doesn't include this folder by default, or the middleware needed for it to work, so you'll need to add them. +Any static files the app uses, including third-party scripts and frameworks but also custom images and stylesheets, must be copied from the old project to the new one. In ASP.NET MVC apps, files were typically accessed based on their location within the project folder. In ASP.NET Core apps, these static files will be accessed based on their location within the `wwwroot` folder. For the eShop project, there are static files in the `Content`, `fonts`, `Images`, `Pics`, and `Scripts` folders. The empty project template used in the previous step doesn't include this folder by default, or the middleware needed for it to work, so you'll need to add them. Add a `wwwroot` folder to the root of the project. Add `Microsoft.AspNetCore.StaticFiles` NuGet package (version 2.2.0). -In `Startup.cs` add a call to `app.UseStaticFiles()` to the `Configure` method: +In `Startup.cs`, add a call to `app.UseStaticFiles()` to the `Configure` method: ```csharp public void Configure(IApplicationBuilder app, IHostingEnvironment env) @@ -151,7 +151,7 @@ Next the `ViewModel` folder, with its one class, is copied over. It's an easy on Next the `Services` folder is copied over. This folder's classes depend on Entity Framework classes from the `Models` folder, which is why it needed to be copied after that folder. Fortunately, it too builds without errors. -That leaves the `Controllers` folder and its two `Controller` classes. After copying the folder to the new project and building, there are seven build errors. Four of them are related to `ViewBag` access and say `Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'` which I solve by adding a NuGet package reference to C#: +That leaves the `Controllers` folder and its two `Controller` classes. After copying the folder to the new project and building, there are seven build errors. Four of them are related to `ViewBag` access and say `Missing compiler required member 'Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create'`, which is solved by adding a NuGet package reference to C#: ```xml @@ -191,9 +191,9 @@ private void AddUriPlaceHolder(CatalogItem item) } ``` -Both `this.Url` and `this.Request` cause compiler errors. Looking at how this code is used, its purpose is to build a link to the `PicController` action that renders image files. The same one we just discovered could probably be replace with direct links to the static files located in `wwwroot`. For now it's worth commenting this out and adding a `TODO:` comment to reference the pics another way. +Both `this.Url` and `this.Request` cause compiler errors. Looking at how this code is used, its purpose is to build a link to the `PicController` action that renders image files. The same one we just discovered could probably be replace with direct links to the static files located in `wwwroot`. For now, it's worth commenting this out and adding a `TODO:` comment to reference the pics another way. - It's worth noting here that the base `Controller` class used by the `CatalogController` class in which this code appears is still referring to `System.Web.Mvc.Controller`. No doubt there will be more errors to fix once we update this to use ASP.NET Core. First, remove the `using System.Web.Mvc;` line from the list of using statements in `CatalogController`. Next, add the NuGet package `Microsoft.AspNetCore.Mvc`. Finally, add a new using statement, `using Microsoft.AspNetCore.Mvc;` and build the app again. +It's worth noting here that the base `Controller` class used by the `CatalogController` class in which this code appears is still referring to `System.Web.Mvc.Controller`. No doubt there will be more errors to fix once we update this to use ASP.NET Core. First, remove the `using System.Web.Mvc;` line from the list of `using` statements in `CatalogController`. Next, add the NuGet package `Microsoft.AspNetCore.Mvc`. Finally, add a `using Microsoft.AspNetCore.Mvc;` statement, and build the app again. This time there are 16 errors: @@ -202,7 +202,7 @@ This time there are 16 errors: - `HttpNotFound` does not exist (3) - `SelectList` not found (8) -Once more let's review these errors one by one. First, `SelectList` can be fixed by adding `using Microsoft.AspNetCore.Mvc.Rendering;` which eliminates half of the errors. +Once more, let's review these errors one by one. First, `SelectList` can be fixed by adding `using Microsoft.AspNetCore.Mvc.Rendering;` which eliminates half of the errors. All references to `return HttpNotFound();` should be replaced with `return NotFound();`. @@ -315,7 +315,7 @@ The last step in migrating is to take the app startup tasks from `Global.asax` a ### Configure MVC -The original ASP.NET MVC app has the following code in its `Application_Start` in `Global.asax`, which runs when the application starts up: +The original ASP.NET MVC app has the following code in its `Application_Start` in `Global.asax`, which runs when the app starts up: ```csharp protected void Application_Start() @@ -449,9 +449,9 @@ protected IContainer RegisterContainer() This code configures an [Autofac](https://autofac.org/) container, reads a config setting to determine whether real or mock data should be used, and passes this setting into an Autofac module (found in the app's `/Modules` directory). Fortunately, Autofac supports .NET Core, so the module can be migrated directly. Copy the folder into the new project and updates the class's namespace and it should compile. -ASP.NET Core has built-in support for dependency injection, but you can wire up a third party container such as Autofac easily if necessary. In this case, since the app is already configured to use Autofac, the simplest solution is to maintain its usage. To do so, the `ConfigureServices` method signature must be modified to return an `IServiceProvider`, and the Autofac container instance must be configured and returned from the method. +ASP.NET Core has built-in support for dependency injection, but you can wire up a third-party container such as Autofac easily if necessary. In this case, since the app is already configured to use Autofac, the simplest solution is to maintain its usage. To do so, the `ConfigureServices` method signature must be modified to return an `IServiceProvider`, and the Autofac container instance must be configured and returned from the method. -**Note:** In .NET Core 3.0 and later the process for integrating a third party DI container has changed. +**Note:** In .NET Core 3.0 and later the process for integrating a third-party DI container has changed. Part of configuring Autofac requires a call to `builder.Populate(services)`. This extension is found in the `Autofac.Extensions.DependencyInjection` NuGet package, which must be installed before the code will compile. diff --git a/docs/architecture/porting-existing-aspnet-apps/hosting-differences.md b/docs/architecture/porting-existing-aspnet-apps/hosting-differences.md index 9cb44be946e07..196259a645b73 100644 --- a/docs/architecture/porting-existing-aspnet-apps/hosting-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/hosting-differences.md @@ -7,7 +7,7 @@ ms.date: 11/13/2020 # Hosting differences between ASP.NET MVC and ASP.NET Core -ASP.NET MVC apps are hosted in IIS, and may rely on IIS configuration for their behavior. This often includes [IIS modules](https://docs.microsoft.com/iis/get-started/introduction-to-iis/iis-modules-overview). As part of reviewing an application to prepare to port it from ASP.NET MVC to ASP.NET Core, teams should identify which modules, if any, they're using from the list of IIS Modules installed on their server. +ASP.NET MVC apps are hosted in IIS, and may rely on IIS configuration for their behavior. This often includes [IIS modules](https://docs.microsoft.com/iis/get-started/introduction-to-iis/iis-modules-overview). As part of reviewing an app to prepare to port it from ASP.NET MVC to ASP.NET Core, teams should identify which modules, if any, they're using from the list of IIS Modules installed on their server. [ASP.NET Core apps can run on a number of different servers](https://docs.microsoft.com/aspnet/core/fundamentals/servers/). The default cross platform server, Kestrel, is a good default choice. Apps running in Kestrel can be hosted by IIS, running in a separate process. On Windows, apps can also run in process on IIS or using HTTP.sys. Kestrel is generally recommended for best performance. HTTP.sys can be used in scenarios where the app is exposed to the Internet and required capabilities are supported by HTTP.sys but not Kestrel. diff --git a/docs/architecture/porting-existing-aspnet-apps/identify-migration-sequence.md b/docs/architecture/porting-existing-aspnet-apps/identify-migration-sequence.md index 61096ef0a91bf..67ffe270ccab3 100644 --- a/docs/architecture/porting-existing-aspnet-apps/identify-migration-sequence.md +++ b/docs/architecture/porting-existing-aspnet-apps/identify-migration-sequence.md @@ -1,21 +1,21 @@ --- -title: Identifying sequence of projects to migrate +title: Identify sequence of projects to migrate description: Large apps typically aren't migrated to new platforms all at once, but in a series of smaller steps. Learn how to plan the steps for migrating an ASP.NET MVC app to ASP.NET Core. author: ardalis ms.date: 11/13/2020 --- -# Identifying sequence of projects to migrate +# Identify sequence of projects to migrate -For solutions that involve multiple front-end apps, it's usually best to migrate these one by one. It may make sense to create a solution that only includes one front-end app and its dependencies so you can easily identify the scope of work involved. Solutions are very lightweight and you can include projects in multiple solutions if needed. So take advantage of solutions as an organizational tool when migrating. +For solutions that involve multiple front-end apps, it's best to migrate the apps one by one. For example, create a solution that only includes one front-end app and its dependencies so you can easily identify the scope of work involved. Solutions are lightweight, and you can include projects in multiple solutions if needed. So take advantage of solutions as an organizational tool when migrating. -Once you've identified the ASP.NET app you wish to migrate and have its dependent projects located with it (ideally in a solution), the next step is to identify framework and NuGet dependencies. Having identified all dependencies, the simplest migration approach is a "bottom up" approach, in which the lowest level dependencies are migrated first, then the next level of dependencies, until eventually the only thing left is the front-end app. Figure 3-1 shows an example set of projects composing an app, with low-level class libraries at the bottom and the ASP.NET MVC project at the top. +Once you've identified the ASP.NET app to migrate and have its dependent projects located with it (ideally in a solution), the next step is to identify framework and NuGet dependencies. Having identified all dependencies, the simplest migration approach is a "bottom up" approach. With this approach, the lowest level of dependencies is migrated first. Then the next level of dependencies is migrated, until eventually the only thing left is the front-end app. Figure 3-1 shows an example set of projects composing an app. The low-level class libraries are at the bottom, and the ASP.NET MVC project is at the top. ![Project dependencies](./media/Figure3-1.png) **Figure 3-1. Project dependencies graph.** -Choose a particular front-end application, an ASP.NET MVC 5 / Web API 2 project. Identify its dependencies in the solution, and map out their dependencies until you have a complete list. A diagram like the one shown in Figure 3-1 may be useful when mapping out project dependencies. Visual Studio may be able to produce a [dependency diagram for your solution](https://docs.microsoft.com/visualstudio/modeling/create-layer-diagrams-from-your-code), depending on which edition you're using. [The .NET Portability Analyzer](https://docs.microsoft.com/dotnet/standard/analyzers/portability-analyzer) can also produce dependency diagrams. +Choose a particular front-end app, an ASP.NET MVC 5 / Web API 2 project. Identify its dependencies in the solution, and map out their dependencies until you have a complete list. A diagram like the one shown in Figure 3-1 may be useful when mapping out project dependencies. Visual Studio can produce a [dependency diagram for your solution](https://docs.microsoft.com/visualstudio/modeling/create-layer-diagrams-from-your-code), depending on which edition you're using. [The .NET Portability Analyzer](https://docs.microsoft.com/dotnet/standard/analyzers/portability-analyzer) can also produce dependency diagrams. Figure 3-2 shows the installer for the [.NET Portability Analyzer Visual Studio extension](https://marketplace.visualstudio.com/items?itemName=ConnieYau.NETPortabilityAnalyzer): @@ -29,31 +29,40 @@ The extension supports Visual Studio 2017 and later. Once installed, you configu **Figure 3-3. Configure the .NET Portability Analyzer.** -Running the analyzer will produce a report with details for each assembly describing how compatible they are with a given target, such as .NET Core 3.1 or .NET Standard 2.0. This can help teams assess the effort that will be required to port a particular project to a particular target. The details of this analysis are covered in the next section. +The analyzer produces a detailed report for each assembly. The report: -Once you've mapped out the projects and their relationships with one another, you're ready to begin planning the order in which you'll migrate the projects. You typically want to begin with projects that have no dependencies, and then work your way up the tree to the projects that depend on these projects. +* Describes how compatible each project is with a given target framework, such as .NET Core 3.1 or .NET Standard 2.0. +* Helps teams assess the effort required to port a particular project to a particular target framework. -In the example shown in Figure 3-1, you would start with the *Contoso.Utils* project, since it doesn't depend on any other projects. Next, *Contoso.Data* since it only depends on "Utils". Then migrate the "BusinessLogic" library, and finally the front-end ASP.NET "Web" project. Following this "bottom up" approach works well for relatively small and well-factored apps that can be migrated as a unit once all of their projects have migrated. Larger apps with more complexity or just more code that will take longer to migrate may need to consider more incremental strategies. +The details of this analysis are covered in the next section. + +Once you've mapped out the projects and their relationships with one another, you're ready to determine the order in which you'll migrate the projects. Begin with projects that have no dependencies. Then, work your way up the tree to the projects that depend on these projects. + +In the example shown in Figure 3-1, you would start with the *Contoso.Utils* project, since it doesn't depend on any other projects. Next, *Contoso.Data* since it only depends on "Utils". Then migrate the "BusinessLogic" library, and finally the front-end ASP.NET "Web" project. Following this "bottom up" approach works well for relatively small and well-factored apps that can be migrated as a unit once all of their projects have migrated. Larger apps with more complexity, or more code that will take longer to migrate, may need to consider more incremental strategies. ## Unit tests -Missing from the previous diagrams are unit test projects. Hopefully there are tests covering at least some of the existing behavior of the libraries being ported. If you have unit tests, it's best to convert them first so that you can continue testing changes in the product you're working on. Because porting to .NET Core is such a significant change to your codebase, it's highly recommended to port your test projects so that you can run tests as you port your code over. MSTest, xUnit, and NUnit all work on .NET Core. If you don't have any tests for your app currently, consider building some characterization tests that simply verify the system's current behavior, so that once the migration is complete you can confirm this behavior remains unchanged. +Missing from the previous diagrams are unit test projects. Hopefully there are tests covering at least some of the existing behavior of the libraries being ported. + +If you have unit tests, it's best to convert those projects first. You'll want to continue testing changes in the project you're working on. Remember that porting to .NET Core is a significant change to your codebase. + +MSTest, xUnit, and NUnit all work on .NET Core. If you don't currently have tests for your app, consider building some characterization tests that verify the system's current behavior. The benefit is that once the migration is complete, you can confirm the app's behavior remains unchanged. ## Considerations for migrating many apps -Some organizations will have many different apps to migrate, and migrating each one by hand may require too many resources to be tenable. In these situations, some degree of automation is recommended. The steps followed in this chapter can be automated, so that structural changes like project file differences and updates to common packages are performed by scripts. These scripts can be refined as they are run iteratively on more and more projects, examining whatever manual steps are required for each project and automating them if possible. Using this approach, the organization should grow faster and better at porting their apps over time, with more and better automation support each step of the way. +Some organizations will have many different apps to migrate, and migrating each one by hand may require too many resources to be tenable. In these situations, some degree of automation is recommended. The steps followed in this chapter can be automated. Structural changes, like project file differences and updates to common packages, can be applied by scripts. These scripts can be refined as they're run iteratively on more projects. On each run, examine whatever manual steps are required for each project. Automate those manual steps, if possible. Using this approach, the organization should grow faster and better at porting their apps over time, with improved automation support each step of the way. Watch an overview of how to employ this approach in this [dotNetConf presentation by Lizzy Gallagher of Mastercard](https://www.youtube.com/watch?v=C-2haqb60No). The five phases employed in this presentation included: -- Migrate 3rd party NuGet dependencies -- Migrate apps to use new .csproj file format +- Migrate third-party NuGet dependencies +- Migrate apps to use new *.csproj* file format - Migrate apps to ASP.NET Core (targeting .NET Framework) - Update internal NuGet dependencies to .NET Standard - Update all apps to target .NET Core 3.1 -When automating a large suite of apps, it helps significantly if they follow consistent coding guidelines and project organization. Automation efforts rely on this consistency to be effective. In addition to parsing and migrating project files, common code patterns such as differences in how controller actions are declared or how they return results can be migrated automatically. +When automating a large suite of apps, it helps significantly if they follow consistent coding guidelines and project organization. Automation efforts rely on this consistency to be effective. In addition to parsing and migrating project files, common code patterns can be migrated automatically. Some code pattern examples include differences in how controller actions are declared or how they return results. -For example, a migration script could search files matching `**Controller.cs` for lines of code matching one of these patterns: +For example, a migration script could search files matching `Controller.cs` for lines of code matching one of these patterns: ```csharp return new HttpStatusCodeResult(200); @@ -61,7 +70,7 @@ For example, a migration script could search files matching `**Controller.cs` fo return new HttpStatusCodeResult(HttpStatusCode.OK); ``` -These can be replaced in ASP.NET Core with: +In ASP.NET Core, either of the preceding lines of code can be replaced with: ```csharp return Ok(); @@ -69,7 +78,13 @@ These can be replaced in ASP.NET Core with: ## Summary -The best approach to porting a large .NET app to .NET Core is to identify project dependencies, analyze what's required to port each project, and start from the bottom up. You can use the .NET Portability Analyzer to determine how compatible existing libraries may be with target platforms. Having a suite of automated tests will help ensure no breaking changes creep in as the app is ported, and should be among the first projects ported. +The best approach to porting a large .NET Framework app to .NET Core is to: + +1. Identify project dependencies. +1. Analyze what's required to port each project. +1. Start from the bottom up. + +You can use the .NET Portability Analyzer to determine how compatible existing libraries may be with target platforms. Automated tests will help ensure no breaking changes are introduced as the app is ported. These test projects should be among the first projects ported. ## References diff --git a/docs/architecture/porting-existing-aspnet-apps/identity-differences.md b/docs/architecture/porting-existing-aspnet-apps/identity-differences.md index 16795d4c9f075..17c4e48692059 100644 --- a/docs/architecture/porting-existing-aspnet-apps/identity-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/identity-differences.md @@ -5,7 +5,7 @@ author: ardalis ms.date: 11/13/2020 --- -# Comparing ASP.NET Identity and ASP.NET Core Identity +# Compare ASP.NET Identity and ASP.NET Core Identity In ASP.NET MVC, identity features are typically configured in `IdentityConfig.cs` in the `App_Start` folder. Review how this is configured in the existing app, and compare it to the [configuration required for ASP.NET Core Identity](https://docs.microsoft.com/aspnet/core/security/authentication/identity-configuration) in `Startup.cs`. diff --git a/docs/architecture/porting-existing-aspnet-apps/incremental-migration-strategies.md b/docs/architecture/porting-existing-aspnet-apps/incremental-migration-strategies.md index 52ac2865507b7..469d00182ce99 100644 --- a/docs/architecture/porting-existing-aspnet-apps/incremental-migration-strategies.md +++ b/docs/architecture/porting-existing-aspnet-apps/incremental-migration-strategies.md @@ -1,23 +1,23 @@ --- title: Strategies for migrating incrementally -description: What strategies can teams adopt that will allow them to migrate large applications from ASP.NET MVC to .NET Core in an incremental fashion? +description: What strategies can teams adopt that will allow them to migrate large apps from ASP.NET MVC to .NET Core in an incremental fashion? author: ardalis ms.date: 11/13/2020 --- # Strategies for migrating incrementally -The biggest challenge with migrating any large application is figuring out how to break the very large process up into smaller pieces. There are several strategies that can be applied for this purpose, including breaking up the app into horizontal layers such as UI, data access, business logic, or breaking up the app into separate, smaller apps. Another strategy that can help in this regard is to upgrade some or all of the application to different framework versions on the way to a recent .NET Core release. +The biggest challenge with migrating any large app is figuring out how to break the very large process up into smaller pieces. There are several strategies that can be applied for this purpose, including breaking up the app into horizontal layers such as UI, data access, business logic, or breaking up the app into separate, smaller apps. Another strategy that can help in this regard is to upgrade some or all of the app to different framework versions on the way to a recent .NET Core release. -Consider the challenge of migrating a large ASP.NET 4.5 application. One approach would be to migrate directly from .NET 4.5 to .NET Core 3.1. However, this approach would need to account for every breaking change between these two frameworks and versions, which are substantial. +Consider the challenge of migrating a large ASP.NET 4.5 app. One approach would be to migrate directly from .NET 4.5 to .NET Core 3.1. However, this approach would need to account for every breaking change between these two frameworks and versions, which are substantial. -One recent addition to the .NET ecosystem that helps with interoperability between different .NET frameworks is [.NET Standard](https://dotnet.microsoft.com/platform/dotnet-standard). .NET Standard allows libraries to build against the agreed on set of common APIs, ensuring they can be used in any .NET application. .NET Standard 2.0 is notable because covers the vast majority of base class library functionality used by most .NET and .NET Core applications. Unfortunately, the earliest version of .NET with support for .NET Standard 2.0 is .NET Framework 4.6.1. +One recent addition to the .NET ecosystem that helps with interoperability between different .NET frameworks is [.NET Standard](https://dotnet.microsoft.com/platform/dotnet-standard). .NET Standard allows libraries to build against the agreed upon set of common APIs, ensuring they can be used in any .NET app. .NET Standard 2.0 is notable because it covers the vast majority of base class library functionality used by most .NET Framework and .NET Core apps. Unfortunately, the earliest version of .NET with support for .NET Standard 2.0 is .NET Framework 4.6.1. -Thus, one approach to incrementally upgrade a .NET Framework 4.5 system would be to first update its class libraries to .NET 4.6.1 and then to modify these libraries to be .NET Standard class libraries (using multi-targeting and conditional compilation, if required). This step can be helpful in scenarios where app dependencies require .NET Framework and cannot easily be ported directly to use .NET Standard and .NET Core. Since .NET Framework libraries can be consumed by ASP.NET Core 2.1 apps, the next step would be to migrate some or all of the web functionality of the app to ASP.NET Core 2.1 (as described in the [previous chapter](choose-net-core-version.md)). +Thus, one approach to incrementally upgrade a .NET Framework 4.5 system would be to first update its class libraries to .NET Framework 4.6.1. Then, modify these libraries to be .NET Standard class libraries (using multi-targeting and conditional compilation, if required). This step can be helpful in scenarios where app dependencies require .NET Framework and cannot easily be ported directly to use .NET Standard and .NET Core. Since .NET Framework libraries can be consumed by ASP.NET Core 2.1 apps, the next step would be to migrate some or all of the web functionality of the app to ASP.NET Core 2.1 (as described in the [previous chapter](choose-net-core-version.md)). -Once the app is running on ASP.NET Core 2.1, migrating it to ASP.NET Core 3.1 in isolation is relatively straightforward. The most likely challenge that will occur during this step will be updating any incompatible dependencies to support .NET Core and possibly higher versions of .NET Standard. For apps that don't have problematic dependencies on .NET Framework-only libraries, there is little reason to upgrade to ASP.NET Core 2.1; porting directly to ASP.NET Core 3.1 makes more sense and will require less effort. +Once the app is running on ASP.NET Core 2.1, migrating it to ASP.NET Core 3.1 in isolation is relatively straightforward. The most likely challenge that will occur during this step will be updating any incompatible dependencies to support .NET Core and possibly higher versions of .NET Standard. For apps that don't have problematic dependencies on .NET Framework-only libraries, there's little reason to upgrade to ASP.NET Core 2.1. Porting directly to ASP.NET Core 3.1 makes more sense and requires less effort. -By the time the application is running on .NET Core 3.1, migrating to the current .NET 5.0 release should be relatively painless. The process primarily involves updating the target framework of your project files and their associated NuGet package dependencies. While there are a number of [breaking changes to consider](/dotnet/core/compatibility/3.1-5.0), most applications shouldn't require substantial modification to move from .NET Core 3.1 to .NET 5.0. The primary decision factor in [choosing between .NET Core 3.1 and .NET 5.0 will likely be support](choose-net-core-version.md). +By the time the app is running on .NET Core 3.1, migrating to the current .NET 5.0 release should be relatively painless. The process primarily involves updating the target framework of your project files and their associated NuGet package dependencies. While there are a number of [breaking changes to consider](/dotnet/core/compatibility/3.1-5.0), most apps shouldn't require substantial modification to move from .NET Core 3.1 to .NET 5.0. The primary decision factor in [choosing between .NET Core 3.1 and .NET 5.0 will likely be support](choose-net-core-version.md). ## References diff --git a/docs/architecture/porting-existing-aspnet-apps/index.md b/docs/architecture/porting-existing-aspnet-apps/index.md index db147e7f8bcb5..71a3ce8b7001a 100644 --- a/docs/architecture/porting-existing-aspnet-apps/index.md +++ b/docs/architecture/porting-existing-aspnet-apps/index.md @@ -45,23 +45,23 @@ Participants and Reviewers: > **Nish Anil**, Senior Program Manager, .NET team, Microsoft > **Mike Rousos**, Principal Software Engineer, .NET team, Microsoft -> +> **Scott Addie**, Senior Content Developer, .NET team, Microsoft ## Version -This guide has been written to cover **.NET Core 3.1** version along with many additional updates related to the same “wave” of technologies (that is, Azure and additional third-party technologies) coinciding in time with the .NET Core 3.1 release. Updating from .NET Core 3.1 to .NET 5 (the next version) is relatively straightforward and certainly will require substantially less effort than porting from .NET to .NET Core. Migrating from .NET 4.x to .NET 5 will be similar to migrating to .NET Core 3.1; see [choosing the right .NET Core version](choose-net-core-version.md) for more details. +This guide has been written to cover **.NET Core 3.1** version along with many additional updates related to the same “wave” of technologies (that is, Azure and additional third-party technologies) coinciding in time with the .NET Core 3.1 release. Updating from .NET Core 3.1 to .NET 5.0 (the next version) is relatively straightforward and certainly will require substantially less effort than porting from .NET Framework to .NET Core. Migrating from .NET Framework 4.x to .NET 5.0 will be similar to migrating to .NET Core 3.1. For more information, see [choosing the right .NET Core version](choose-net-core-version.md). ## Who should use this guide -The audience for this guide is mainly developers, development leads, and architects who are interested in learning how to move their existing applications written for ASP.NET MVC and Web API (.NET 4.x) to .NET Core. ASP.NET Web Forms developers may also benefit from this guide, but should be sure to read [Blazor for ASP.NET Web Forms Developers](https://docs.microsoft.com/dotnet/architecture/blazor-for-web-forms-developers/) e-book as well. +The audience for this guide is mainly developers, development leads, and architects who are interested in learning how to move their existing apps written for ASP.NET MVC and Web API (.NET Framework 4.x) to .NET Core. ASP.NET Web Forms developers may also benefit from this guide, but should be sure to read [Blazor for ASP.NET Web Forms Developers](https://docs.microsoft.com/dotnet/architecture/blazor-for-web-forms-developers/) e-book as well. -A secondary audience is technical decision-makers who are making plans for when to move their applications to .NET Core. +A secondary audience is technical decision-makers who are making plans for when to move their apps to .NET Core. -Note that the target audience for this book is .NET developers with large, existing apps that run on ASP.NET MVC and Web API. Apps built on ASP.NET Web Forms are outside of the focus of this book, though much of the information comparing .NET and .NET Core may still be relevant. +Note that the target audience for this book is .NET developers with large, existing apps that run on ASP.NET MVC and Web API. Apps built on ASP.NET Web Forms are outside of the focus of this book, though much of the information comparing .NET Framework and .NET Core may still be relevant. ## How you can use this guide -You can read this book straight through, as we expect many readers to do. This will provide you first with considerations for whether you should port your app at all, followed by architectural differences between .NET and .NET Core. From there you'll learn strategies for migrating a large solution over time, and how to port a real application. Next, the book includes deployment scenarios that may help you address the need to run different apps while appearing as a single app to users. The book concludes with two case studies describing real applications that have made the move from ASP.NET MVC to ASP.NET Core. +You can read this book straight through, as we expect many readers to do. This will provide you first with considerations for whether you should port your app at all, followed by architectural differences between .NET and .NET Core. From there you'll learn strategies for migrating a large solution over time, and how to port a real app. Next, the book includes deployment scenarios that may help you address the need to run different apps while appearing as a single app to users. The book concludes with two case studies describing real apps that have made the move from ASP.NET MVC to ASP.NET Core. Whether or not you choose to start from the first chapter, you can also refer (back) to any of these chapters to learn about specific topics: diff --git a/docs/architecture/porting-existing-aspnet-apps/introduction.md b/docs/architecture/porting-existing-aspnet-apps/introduction.md index 232ffdb19590b..232e31e231482 100644 --- a/docs/architecture/porting-existing-aspnet-apps/introduction.md +++ b/docs/architecture/porting-existing-aspnet-apps/introduction.md @@ -1,6 +1,6 @@ --- title: Introduction to porting apps to .NET Core -description: This chapter covers a list of considerations for teams considering migrating existing ASP.NET applications to .NET Core. +description: This chapter covers a list of considerations for teams considering migrating existing ASP.NET apps to .NET Core. author: ardalis ms.date: 11/13/2020 --- @@ -13,7 +13,7 @@ ms.date: 11/13/2020 It's important to keep in mind that [.NET Core is the Future of .NET](https://devblogs.microsoft.com/dotnet/net-core-is-the-future-of-net/). To quote this article: -> New applications should be built on .NET Core. .NET Core is where future investments in .NET will happen. Existing applications are safe to remain on .NET Framework which will be supported. Existing applications that want to take advantage of the new features in .NET should consider moving to .NET Core. As we plan into the future, we will be bringing in even more capabilities to the platform. +> New apps should be built on .NET Core. .NET Core is where future investments in .NET will happen. Existing apps are safe to remain on .NET Framework which will be supported. Existing apps that want to take advantage of the new features in .NET should consider moving to .NET Core. As we plan into the future, we will be bringing in even more capabilities to the platform. However, upgrading your app to ASP.NET Core will require some effort, and that effort should be balanced against business value and objectives. .NET Framework apps have a very long life ahead of them, with support built into Windows for the foreseeable future. What are some of the questions you should consider before deciding migration to .NET Core is appropriate? What are the expected advantages? What are the tradeoffs? How much effort is involved? These obvious questions are just the beginning, but make for a great starting point as teams consider how to support their customers' needs with apps today and tomorrow. diff --git a/docs/architecture/porting-existing-aspnet-apps/logging-differences.md b/docs/architecture/porting-existing-aspnet-apps/logging-differences.md index 19ac53a359bdc..2d8fac10779ea 100644 --- a/docs/architecture/porting-existing-aspnet-apps/logging-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/logging-differences.md @@ -7,15 +7,15 @@ ms.date: 11/13/2020 # Logging differences between ASP.NET MVC and ASP.NET Core -Application logging provides important diagnostic information, especially for apps running in production. ASP.NET Core introduces a new system for adding standardized logging to any app. Existing ASP.NET MVC and Web API apps most likely will be using third party logging solutions, which likely continue to be supported on ASP.NET Core. +Application logging provides important diagnostic information, especially for apps running in production. ASP.NET Core introduces a new system for adding standardized logging to any app. Existing ASP.NET MVC and Web API apps most likely will be using third-party logging solutions, which likely continue to be supported on ASP.NET Core. ## ASP.NET MVC logging -There is no built-in logging solution in ASP.NET MVC and Web API apps. Instead, most apps use third party logging solutions like [log4net](https://www.nuget.org/packages/log4net/), [NLog](https://www.nuget.org/packages/NLog/), or [Serilog](https://www.nuget.org/packages/Serilog). Many teams also choose to roll their own logging solution. Logging frameworks typically support multiple "sinks" (or targets or appenders) for log output, such as text files, databases, or even emails. They use configuration to determine which levels of log messages from which parts of the system are routed to different sinks. Teams should review how logging is performed within the app as well as how logging is [configured](configuration-differences.md) when considering how to migrate their app's logging to .NET Core. +There is no built-in logging solution in ASP.NET MVC and Web API apps. Instead, most apps use third-party logging solutions like [log4net](https://www.nuget.org/packages/log4net/), [NLog](https://www.nuget.org/packages/NLog/), or [Serilog](https://www.nuget.org/packages/Serilog). Many teams also choose to roll their own logging solution. Logging frameworks typically support multiple "sinks" (or targets or appenders) for log output, such as text files, databases, or even emails. They use configuration to determine which levels of log messages from which parts of the system are routed to different sinks. Teams should review how logging is performed within the app as well as how logging is [configured](configuration-differences.md) when considering how to migrate their app's logging to .NET Core. ## ASP.NET Core logging -In ASP.NET Core, [logging is a built-in feature](https://docs.microsoft.com/aspnet/core/fundamentals/logging/) that can be configured and extended when the app starts up. Third party loggers, including all of the ones mentioned above, can be hooked into ASP.NET Core to enhance its functionality. +In ASP.NET Core, [logging is a built-in feature](https://docs.microsoft.com/aspnet/core/fundamentals/logging/) that can be configured and extended when the app starts up. Third-party loggers, including all of the ones mentioned above, can be hooked into ASP.NET Core to enhance its functionality. ASP.NET Core logging uses categories and levels to control what is logged and how. Classes typically use instances of the `ILogger` interface, with the class's type used as the generic `T` type. In this scenario, the class's fully qualified name is used as the category. Loggers can also be created with a custom category using an `ILoggerFactory`. Log levels range from the most detailed, `Trace`, to the most important, `Critical`. Using configuration, apps can specify what minimum level of logging should be included on a per-category (with wildcards) basis. @@ -36,7 +36,7 @@ Support for logging in ASP.NET Core is extensive and flexible. [Refer to the doc ## Migrate logging -How you migrate your .NET Framework app's logging to .NET Core will largely depend on how the app is logging now. If it's using a third-party NuGet package, refer to the upgrade documentation for that package. Most likely the upgrade path will be fairly straightforward. If you're using your own logging solution, you'll need to migrate it yourself, or consider this an opportunity to migrate to a third party solution or the built-in support in ASP.NET Core. +How you migrate your .NET Framework app's logging to .NET Core will largely depend on how the app is logging now. If it's using a third-party NuGet package, refer to the upgrade documentation for that package. Most likely the upgrade path will be fairly straightforward. If you're using your own logging solution, you'll need to migrate it yourself, or consider this an opportunity to migrate to a third-party solution or the built-in support in ASP.NET Core. You can reference the `Microsoft.Extensions.Logging` package from .NET Framework apps as long as they are using NuGet version 4.3 or higher and are on .NET Framework 4.6.1 or higher. Once your app has referenced this package, you can convert your logging statements to use the new extensions prior to migrating the app to .NET Core. This can provide a stepping stone toward full migration, since the app can continue running on .NET Framework while logging using the newer extensions package. diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure3-1.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure3-1.png index 2f1c546b0a11e..13737607920ea 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure3-1.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure3-1.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure3-2.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure3-2.png index 41120d75dec18..322162b0ebabe 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure3-2.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure3-2.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure3-3.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure3-3.png index 2ded7a27fae26..532ee24e9cd4a 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure3-3.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure3-3.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure3-4.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure3-4.png index a6cc63671b56a..0564e206d1f35 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure3-4.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure3-4.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure3-5.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure3-5.png index c418dce6794a2..bb6188363d6fa 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure3-5.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure3-5.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-1.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-1.png index 335683fa3a387..f949f05acfa30 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-1.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-1.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-10.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-10.png index bc20c9a9868e7..dee4a9432c5a3 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-10.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-10.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-11.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-11.png index 0e2fe5798d985..6f8fa684b0f38 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-11.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-11.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-12.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-12.png index 2fe6599c32b05..f35ca06e8f2ed 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-12.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-12.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-2.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-2.png index 49f37d9e03681..f9e9c173f82f2 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-2.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-2.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-3.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-3.png index a93e398c789f9..ce0d6db945986 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-3.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-3.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-4.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-4.png index 08462e60522b1..555fe82a73c5f 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-4.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-4.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-5.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-5.png index 1b85cf707740e..83f232027c01d 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-5.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-5.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-6.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-6.png index 8a0d343abeee6..bc320c7272275 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-6.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-6.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-7.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-7.png index ce4238e58b837..1fa6a0275b025 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-7.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-7.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-8.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-8.png index 185fc6979857a..83cc908852cce 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-8.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-8.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-9.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-9.png index c2775947d9f39..efa05d1cef162 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure4-9.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure4-9.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure5-1.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure5-1.png index fbcf367a3500e..e1865ed7cdb19 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure5-1.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure5-1.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/Figure5-2.png b/docs/architecture/porting-existing-aspnet-apps/media/Figure5-2.png index eb5c3a12f8144..b23c767cd80e6 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/Figure5-2.png and b/docs/architecture/porting-existing-aspnet-apps/media/Figure5-2.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/media/index/porting-existing-aspnet-apps.png b/docs/architecture/porting-existing-aspnet-apps/media/index/porting-existing-aspnet-apps.png index 27be20619c573..a1358e4db046c 100644 Binary files a/docs/architecture/porting-existing-aspnet-apps/media/index/porting-existing-aspnet-apps.png and b/docs/architecture/porting-existing-aspnet-apps/media/index/porting-existing-aspnet-apps.png differ diff --git a/docs/architecture/porting-existing-aspnet-apps/middleware-modules-handlers.md b/docs/architecture/porting-existing-aspnet-apps/middleware-modules-handlers.md index b448388e6d766..e4651cecf28a2 100644 --- a/docs/architecture/porting-existing-aspnet-apps/middleware-modules-handlers.md +++ b/docs/architecture/porting-existing-aspnet-apps/middleware-modules-handlers.md @@ -1,11 +1,11 @@ --- -title: Comparing middleware to modules and handlers +title: Compare middleware to modules and handlers description: This section explores the differences in structure ASP.NET apps that leverage handlers and modules with ASP.NET Core apps that define middleware for their request handling pipelines. author: ardalis ms.date: 11/13/2020 --- -# Comparing middleware to modules and handlers +# Compare middleware to modules and handlers If your existing ASP.NET MVC or Web API app uses OWIN/Katana, you're most likely already familiar with the concept of middleware and porting it to ASP.NET Core should be fairly straightforward. However, most ASP.NET apps rely on HTTP modules and HTTP handlers instead of middleware. Migrating these to ASP.NET Core requires additional effort. @@ -13,7 +13,7 @@ If your existing ASP.NET MVC or Web API app uses OWIN/Katana, you're most likely [HTTP modules and HTTP handlers](https://docs.microsoft.com/troubleshoot/aspnet/http-modules-handlers) are an integral part of the ASP.NET architecture. While a request is being processed, each request is processed by multiple HTTP modules (for example, the authentication module and the session module) and is then processed by a single HTTP handler. After the handler has processed the request, the request flows back through the HTTP modules. -If your app is using custom HTTP modules or HTTP handlers, you will need a plan to migrate these to ASP.NET Core, most likely as middleware. +If your app is using custom HTTP modules or HTTP handlers, you'll need a plan to migrate these to ASP.NET Core, most likely as middleware. ## ASP.NET Core middleware diff --git a/docs/architecture/porting-existing-aspnet-apps/migrate-aspnet-core-2-1.md b/docs/architecture/porting-existing-aspnet-apps/migrate-aspnet-core-2-1.md index fe991cfe06fca..7b460faf12629 100644 --- a/docs/architecture/porting-existing-aspnet-apps/migrate-aspnet-core-2-1.md +++ b/docs/architecture/porting-existing-aspnet-apps/migrate-aspnet-core-2-1.md @@ -7,17 +7,17 @@ ms.date: 11/13/2020 # Migrate to ASP.NET Core 2.1 -ASP.NET Core 2.1 is an interesting release because it is the only currently supported .NET Core release to support both .NET Core and .NET Framework runtimes. As such, it may offer an easier upgrade path for some applications when compared to upgrading all parts of the app to .NET Core at once. As an LTS release, support for .NET Core 2.1 will continue through August 2021. +ASP.NET Core 2.1 is an interesting release because it is the only currently supported .NET Core release to support both .NET Core and .NET Framework runtimes. As such, it may offer an easier upgrade path for some apps when compared to upgrading all parts of the app to .NET Core at once. As an LTS release, support for .NET Core 2.1 will continue through August 2021. -## Should applications run on .NET Framework with ASP.NET Core 2.1? +## Should apps run on .NET Framework with ASP.NET Core 2.1? -ASP.NET Core 2.2 and earlier supported both .NET Core and .NET Framework runtimes. Does it make sense to migrate some or all of an application to ASP.NET Core 2.1 as a stepping stone, before porting over completely to .NET Core? Apps, or subsets of apps, could see their front-end ASP.NET logic ported to use ASP.NET Core, while still consuming .NET Framework libraries for business logic and infrastructure consumption. This approach may make sense when there is a relatively thin UI layer without much business logic, and a much larger set of functionality in class libraries. +ASP.NET Core 2.2 and earlier supported both .NET Core and .NET Framework runtimes. Does it make sense to migrate some or all of an app to ASP.NET Core 2.1 as a stepping stone, before porting over completely to .NET Core? Apps, or subsets of apps, could see their front-end ASP.NET logic ported to use ASP.NET Core, while still consuming .NET Framework libraries for business logic and infrastructure consumption. This approach may make sense when there is a relatively thin UI layer without much business logic, and a much larger set of functionality in class libraries. -The main benefit of porting just the front end web layer to ASP.NET Core 2.1 is that the existing .NET class libraries can remain as is during the initial migration. They may be in continued use by other .NET applications or simply don't need to be in scope for the first iteration of a planned full migration to .NET Core. Reducing the scope of the initial migration for large applications helps provide incremental goals that act as stepping stones toward the desired end state, which is often a complete port to .NET Core. +The main benefit of porting just the front end web layer to ASP.NET Core 2.1 is that the existing .NET class libraries can remain as is during the initial migration. They may be in continued use by other .NET apps or simply don't need to be in scope for the first iteration of a planned full migration to .NET Core. Reducing the scope of the initial migration for large apps helps provide incremental goals that act as stepping stones toward the desired end state, which is often a complete port to .NET Core. If you have an existing app that may use this strategy, some things you can do today to help prepare for the process are to move as much business logic, data access, and other non-UI logic out of the ASP.NET projects and into separate class libraries as possible. It will also help if you have automated test coverage of your system, so that you can verify that behavior remains consistent before and after the migration. -If your app is so large that you can't migrate the entire web application at once, and you need to be able to deploy the new ASP.NET Core app side by side with the existing ASP.NET app, there are deployment strategies that can be used to achieve this. These are covered in [Chapter 5: Deployment Scenarios](deployment-scenarios.md). +If your app is so large that you can't migrate the entire web app at once, and you need to be able to deploy the new ASP.NET Core app side by side with the existing ASP.NET app, there are deployment strategies that can be used to achieve this. These are covered in [Chapter 5: Deployment Scenarios](deployment-scenarios.md). Keep in mind that ASP.NET Core 2.1 is the last LTS release of .NET Core that supports running on .NET Framework and consuming .NET Framework libraries. This release will be out of support soon, but ASP.NET Core 2.1 on .NET Framework will be supported as long as the .NET Framework (even after .NET Core 2.1 support ends). See the 'ASP.NET Core 2.1 on .NET Framework' section [here](https://dotnet.microsoft.com/platform/support/policy/dotnet-core). diff --git a/docs/architecture/porting-existing-aspnet-apps/migrate-web-forms.md b/docs/architecture/porting-existing-aspnet-apps/migrate-web-forms.md index 315c46863b8a4..59a36e7de92f1 100644 --- a/docs/architecture/porting-existing-aspnet-apps/migrate-web-forms.md +++ b/docs/architecture/porting-existing-aspnet-apps/migrate-web-forms.md @@ -1,27 +1,27 @@ --- title: Strategies for migrating ASP.NET Web Forms apps -description: What strategies can teams use to migrate ASP.NET Web Forms applications to .NET Core? +description: What strategies can teams use to migrate ASP.NET Web Forms apps to .NET Core? author: ardalis ms.date: 11/13/2020 --- # Strategies for migrating ASP.NET Web Forms apps -This book is primarily aimed at offering guidance for migrating large ASP.NET MVC and Web API apps to .NET Core. However, in some cases these applications will also include some number of Web Forms (.aspx) pages which must also be taken into account. ASP.NET Web Forms is not supported in .NET Core (nor are ASP.NET Web Pages). Typically the functionality of these pages must be rewritten as part of a port to ASP.NET Core. There are, however, some strategies you can apply before or during such migration to help reduce the overall effort required. +This book is primarily aimed at offering guidance for migrating large ASP.NET MVC and Web API apps to .NET Core. However, in some cases these apps will also include some number of Web Forms (.aspx) pages which must also be taken into account. ASP.NET Web Forms is not supported in .NET Core (nor are ASP.NET Web Pages). Typically the functionality of these pages must be rewritten as part of a port to ASP.NET Core. There are, however, some strategies you can apply before or during such migration to help reduce the overall effort required. -It should also be noted that Web Forms will continue to be supported for quite some time. One option may be to retain this functionality in an ASP.NET 4.x application. +It should also be noted that Web Forms will continue to be supported for quite some time. One option may be to retain this functionality in an ASP.NET 4.x app. ## Separate business logic and other concerns -The less code you have in your ASP.NET Web Forms pages, the better. When possible, try to keep business logic and other concerns like data access in separate classes, ideally in separate class libraries. These class libraries can be ported to .NET Standard and consumed by any ASP.NET Core application. +The less code you have in your ASP.NET Web Forms pages, the better. When possible, try to keep business logic and other concerns like data access in separate classes, ideally in separate class libraries. These class libraries can be ported to .NET Standard and consumed by any ASP.NET Core app. ## Leverage client behavior and web APIs -Given the choice between implementing logic in Web Forms or in the browser with the help of API calls, favor the latter. Migrating APIs to ASP.NET Core is supported, and client-side behavior should be independent of whatever server-side stack your application is using. Leveraging this approach has the added benefit of often providing a more responsive user experience, as well. +Given the choice between implementing logic in Web Forms or in the browser with the help of API calls, favor the latter. Migrating APIs to ASP.NET Core is supported, and client-side behavior should be independent of whatever server-side stack your app is using. Leveraging this approach has the added benefit of often providing a more responsive user experience, as well. ## Consider Blazor -Blazor lets you build interactive web UIs with C# instead of JavaScript. It can run on the server or in the browser using WebAssembly. ASP.NET Web Forms applications may be ported page-by-page to Blazor applications. Microsoft has published a detailed e-book on [Blazor for ASP.NET Web Forms Developers](https://devblogs.microsoft.com/aspnet/blazor-aspnet-webforms-ebook/) which is available for free. In addition, many Web Forms controls have been ported to Blazor as part of an open source community project, [Blazor Web Forms Components](https://fritzandfriends.github.io/BlazorWebFormsComponents/). Using these components, you may be able to easily port your Web Forms pages to Blazor even if they leverage a number of built-in Web Forms controls. +Blazor lets you build interactive web UIs with C# instead of JavaScript. It can run on the server or in the browser using WebAssembly. ASP.NET Web Forms apps may be ported page-by-page to Blazor apps. Microsoft has published a detailed e-book on [Blazor for ASP.NET Web Forms Developers](https://devblogs.microsoft.com/aspnet/blazor-aspnet-webforms-ebook/) which is available for free. In addition, many Web Forms controls have been ported to Blazor as part of an open source community project, [Blazor Web Forms Components](https://fritzandfriends.github.io/BlazorWebFormsComponents/). Using these components, you may be able to easily port your Web Forms pages to Blazor even if they leverage a number of built-in Web Forms controls. ## Summary diff --git a/docs/architecture/porting-existing-aspnet-apps/migration-considerations.md b/docs/architecture/porting-existing-aspnet-apps/migration-considerations.md index 58d0011d58fe8..6cec74e4e0bde 100644 --- a/docs/architecture/porting-existing-aspnet-apps/migration-considerations.md +++ b/docs/architecture/porting-existing-aspnet-apps/migration-considerations.md @@ -23,7 +23,7 @@ Apps built with .NET Core are running on [one of the fastest tech stacks availab ### Cloud-native -For the above reasons as well as others, .NET Core apps are very well-suited to running in cloud hosting environments. Lightweight and fast, .NET Core apps can be deployed to Azure Web Apps or containers and scaled horizontally as needed to meet immediate system demand. +For the above reasons as well as others, .NET Core apps are well-suited to running in cloud hosting environments. Lightweight and fast, .NET Core apps can be deployed to Azure Web Apps or containers and scaled horizontally as needed to meet immediate system demand. ### Maintainable @@ -31,11 +31,11 @@ For many apps, while they've continued to meet customer and business needs, tech ### Modular -ASP.NET Core is very modular, leveraging NuGet packages as a first-class part of the framework. Apps built for .NET Core all support dependency injection, making it easy to compose solutions from whatever implementations are needed for a given environment. Building microservices with .NET Core is far easier than with ASP.NET MVC with its dependency on IIS, which opens up additional options to break up large applications into smaller modules. +ASP.NET Core is modular, leveraging NuGet packages as a first-class part of the framework. Apps built for .NET Core all support dependency injection, making it easy to compose solutions from whatever implementations are needed for a given environment. Building microservices with .NET Core is far easier than with ASP.NET MVC with its dependency on IIS, which opens up additional options to break up large apps into smaller modules. ### Modern -Staying on a modern, actively developed technology stack has a host of advantages. New features and C# language features will only be added to .NET Core. The .NET Framework has had its last release with version 4.8, and versions of C# beyond 8 will not target .NET Framework. While ASP.NET MVC will remain supported by Microsoft for many years, the best and brightest .NET software developers are likely looking to use the more modern .NET Core framework, with all of the advantages is has to offer (only some of which are summarized above). Finding employees and/or contractors with the skills to maintain an ASP.NET MVC application will start to become a challenge at some point, as will finding online training and troubleshooting assistance. There probably aren't that many new blog posts being written about ASP.NET MVC 5, while there are plenty being written for .NET 5, for example. +Staying on a modern, actively developed technology stack has a host of advantages. New features and C# language features will only be added to .NET Core. The .NET Framework has had its last release with version 4.8, and versions of C# beyond 8 will not target .NET Framework. While ASP.NET MVC will remain supported by Microsoft for many years, the best and brightest .NET software developers are likely looking to use the more modern .NET Core framework, with all of the advantages is has to offer (only some of which are summarized above). Finding employees and/or contractors with the skills to maintain an ASP.NET MVC app will start to become a challenge at some point, as will finding online training and troubleshooting assistance. There probably aren't that many new blog posts being written about ASP.NET MVC 5, while there are plenty being written for .NET 5.0, for example. There are certainly many compelling reasons to consider migrating to .NET Core, which presumably is why you're reading this book! But let's consider some disadvantages and reasons why it may make more sense to remain on the .NET Framework. diff --git a/docs/architecture/porting-existing-aspnet-apps/serving-static-files.md b/docs/architecture/porting-existing-aspnet-apps/serving-static-files.md index 01c6f3db7068a..df173189798fb 100644 --- a/docs/architecture/porting-existing-aspnet-apps/serving-static-files.md +++ b/docs/architecture/porting-existing-aspnet-apps/serving-static-files.md @@ -5,43 +5,43 @@ author: ardalis ms.date: 11/13/2020 --- -# Serving static files in ASP.NET MVC and ASP.NET Core +# Serve static files in ASP.NET MVC and ASP.NET Core -Most web applications involve a combination of server side logic and static files that must simply be sent to the client as-is. How should your migration from ASP.NET MVC to ASP.NET Core handle serving static files? +Most web apps involve a combination of server side logic and static files that must simply be sent to the client as-is. How should your migration from ASP.NET MVC to ASP.NET Core handle serving static files? ## Hosting static files in ASP.NET MVC -ASP.NET MVC apps, hosted by IIS, typically host static files directly from the application. ASP.NET MVC supports placing static files side by side with files that should be kept private on the server. IIS and ASP.NET require explicitly restricting certain files or file extensions from being served from the folder in which an ASP.NET application is hosted. +ASP.NET MVC apps, hosted by IIS, typically host static files directly from the app. ASP.NET MVC supports placing static files side by side with files that should be kept private on the server. IIS and ASP.NET require explicitly restricting certain files or file extensions from being served from the folder in which an ASP.NET app is hosted. -For many static files, using a content delivery network (CDN) is a good practice. [Static content hosting](https://docs.microsoft.com/azure/architecture/patterns/static-content-hosting) allows better performance while reducing load and bandwidth from application servers. +For many static files, using a content delivery network (CDN) is a good practice. [Static content hosting](https://docs.microsoft.com/azure/architecture/patterns/static-content-hosting) allows better performance while reducing load and bandwidth from app servers. ## Hosting static files in ASP.NET Core Though I admit it took me by surprise the first time I encountered it, ASP.NET Core does not have built-in support for static files. This feature that has always existed as just a part of ASP.NET, enabled by IIS, isn't intrinsic to ASP.NET Core or its Kestrel web server. In order to serve static files from an ASP.NET Core app, you must configure [static files middleware](https://docs.microsoft.com/aspnet/core/fundamentals/static-files). -With static files middleware configured, an ASP.NET Core app will serve all files located in a certain folder (typically `/wwwroot`). No other files in the application or project folder are at risk of being accidentally exposed by the server, and no special restrictions based on file names or extensions need to be configured, as is the case with IIS. Instead, developers explicitly choose to expose files publicly when they place them in the `wwwroot` folder, and otherwise files are not shared. +With static files middleware configured, an ASP.NET Core app will serve all files located in a certain folder (typically `/wwwroot`). No other files in the app or project folder are at risk of being accidentally exposed by the server, and no special restrictions based on file names or extensions need to be configured, as is the case with IIS. Instead, developers explicitly choose to expose files publicly when they place them in the `wwwroot` folder, and otherwise files are not shared. Because support for static files uses middleware, any other middleware such as authentication, caching, or compression can also be applied as part of the same request pipeline. -Of course, CDNs remain a good choice for ASP.NET Core applications for all the same reasons they're used in ASP.NET MVC apps. As part of preparing to migrate to .NET Core, if there are benefits your app could realize from using a CDN, it would be good to move static files to a CDN prior to migrating to .NET Core. This will reduce the overall scope of the migration effort where static assets are concerned. +Of course, CDNs remain a good choice for ASP.NET Core apps for all the same reasons they're used in ASP.NET MVC apps. As part of preparing to migrate to .NET Core, if there are benefits your app could realize from using a CDN, it would be good to move static files to a CDN prior to migrating to .NET Core. This will reduce the overall scope of the migration effort where static assets are concerned. -Most web applications involve a combination of server side logic and static files that must simply be sent to the client as-is. How should your migration from ASP.NET MVC to ASP.NET Core handle serving static files? +Most web apps involve a combination of server side logic and static files that must simply be sent to the client as-is. How should your migration from ASP.NET MVC to ASP.NET Core handle serving static files? ## Host static files in ASP.NET MVC -ASP.NET MVC apps, hosted by IIS, typically host static files directly from the application. ASP.NET MVC supports placing static files side by side with files that should be kept private on the server. IIS and ASP.NET require explicitly restricting certain files or file extensions from being served from the folder in which an ASP.NET application is hosted. +ASP.NET MVC apps, hosted by IIS, typically host static files directly from the app. ASP.NET MVC supports placing static files side by side with files that should be kept private on the server. IIS and ASP.NET require explicitly restricting certain files or file extensions from being served from the folder in which an ASP.NET app is hosted. -For many static files, using a content delivery network (CDN) is a good practice. [Static content hosting](https://docs.microsoft.com/azure/architecture/patterns/static-content-hosting) allows better performance while reducing load and bandwidth from application servers. +For many static files, using a content delivery network (CDN) is a good practice. [Static content hosting](https://docs.microsoft.com/azure/architecture/patterns/static-content-hosting) allows better performance while reducing load and bandwidth from app servers. ## Host static files in ASP.NET Core Though I admit it took me by surprise the first time I encountered it, ASP.NET Core does not have built-in support for static files. This feature that has always existed as just a part of ASP.NET, enabled by IIS, isn't intrinsic to ASP.NET Core or its Kestrel web server. In order to serve static files from an ASP.NET Core app, you must configure [static files middleware](https://docs.microsoft.com/aspnet/core/fundamentals/static-files). -With static files middleware configured, an ASP.NET Core app will serve all files located in a certain folder (typically `/wwwroot`). No other files in the application or project folder are at risk of being accidentally exposed by the server, and no special restrictions based on file names or extensions need to be configured, as is the case with IIS. Instead, developers explicitly choose to expose files publicly when they place them in the `wwwroot` folder, and otherwise files are not shared. +With static files middleware configured, an ASP.NET Core app will serve all files located in a certain folder (typically `/wwwroot`). No other files in the app or project folder are at risk of being accidentally exposed by the server, and no special restrictions based on file names or extensions need to be configured, as is the case with IIS. Instead, developers explicitly choose to expose files publicly when they place them in the `wwwroot` folder, and otherwise files are not shared. Because support for static files uses middleware, any other middleware such as authentication, caching, or compression can also be applied as part of the same request pipeline. -Of course, CDNs remain a good choice for ASP.NET Core applications for all the same reasons they're used in ASP.NET MVC apps. As part of preparing to migrate to .NET Core, if there are benefits your app could realize from using a CDN, it would be good to move static files to a CDN prior to migrating to .NET Core. This will reduce the overall scope of the migration effort where static assets are concerned. +Of course, CDNs remain a good choice for ASP.NET Core apps for all the same reasons they're used in ASP.NET MVC apps. As part of preparing to migrate to .NET Core, if there are benefits your app could realize from using a CDN, it would be good to move static files to a CDN prior to migrating to .NET Core. This will reduce the overall scope of the migration effort where static assets are concerned. ## References diff --git a/docs/architecture/porting-existing-aspnet-apps/testing-differences.md b/docs/architecture/porting-existing-aspnet-apps/testing-differences.md index a491e387aa4e5..2ad784e6265ad 100644 --- a/docs/architecture/porting-existing-aspnet-apps/testing-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/testing-differences.md @@ -11,7 +11,7 @@ ASP.NET MVC apps support unit testing of controllers, but this approach often om [ASP.NET Core controllers can be unit tested](https://docs.microsoft.com/aspnet/core/mvc/controllers/testing) just like ASP.NET MVC controllers, but with the same limitations. However, [ASP.NET Core supports fast, easy-to-author integration tests](https://docs.microsoft.com/aspnet/core/test/integration-tests) as well. Integration tests are hosted by a `TestHost` class and are typically configured in a custom `WebApplicationFactory` which can override or replace app dependencies. For instance, frequently during integration tests the app will target a different data source and may replace services that send emails with fake or mock implementations. -ASP.NET MVC and Web API did not support anything like the integration testing scenarios available in ASP.NET Core. As part of any migration effort you should allocate time to write some integration tests for your newly-migrated system in order to ensure it's working as expected continues to do so. Even if you weren't writing tests of your web application logic before the migration, you should strongly consider doing so as you move to ASP.NET Core. +ASP.NET MVC and Web API did not support anything like the integration testing scenarios available in ASP.NET Core. As part of any migration effort you should allocate time to write some integration tests for your newly-migrated system in order to ensure it's working as expected continues to do so. Even if you weren't writing tests of your web app logic before the migration, you should strongly consider doing so as you move to ASP.NET Core. ## References diff --git a/docs/architecture/porting-existing-aspnet-apps/understand-update-dependencies.md b/docs/architecture/porting-existing-aspnet-apps/understand-update-dependencies.md index 0c2b7b945f47d..0765467893fcf 100644 --- a/docs/architecture/porting-existing-aspnet-apps/understand-update-dependencies.md +++ b/docs/architecture/porting-existing-aspnet-apps/understand-update-dependencies.md @@ -29,7 +29,7 @@ Once you've successfully installed the tool, you can run `try-convert` in the fo ## Update NuGet package dependencies -Analyze your use of third party NuGet packages and determine if any of them do not yet support .NET Standard (or do support it but only with a new version). It can be helpful to [update NuGet packages to use `` syntax using Visual Studios converter tool](https://docs.microsoft.com/nuget/consume-packages/migrate-packages-config-to-package-reference), so that top-level dependencies are visible. Next, check whether the current or later versions of these packages support .NET Core or .NET Standard. This information can be found on [nuget.org] or within Visual Studio for each package. +Analyze your use of third-party NuGet packages and determine if any of them do not yet support .NET Standard (or do support it but only with a new version). It can be helpful to [update NuGet packages to use `` syntax using Visual Studio's converter tool](https://docs.microsoft.com/nuget/consume-packages/migrate-packages-config-to-package-reference), so that top-level dependencies are visible. Next, check whether the current or later versions of these packages support .NET Core or .NET Standard. This information can be found on [nuget.org] or within Visual Studio for each package. If support exists using the version of the package the app currently uses, great! If not, see if a more recent version of the package has the support and research what would be involved in upgrading. There may be breaking changes in the package, especially if the major version of the package changes between your currently used version and the one to which you're upgrading. @@ -41,7 +41,7 @@ The `System.Web` namespace and types don't exist in .NET Core. When you're analy In general, it's a good practice to minimize how much of an app's business logic lives in its user interface layer. It's also best to keep controllers and views small. Apps that have followed this guidance will be easier to port than those that have a significant amount of their logic in the ASP.NET web project. If you have an app you're considering porting, but haven't begun the process yet, keep this in mind as you maintain it. Any effort you put toward minimizing how much code is in the ASP.NET MVC or Web API project will likely result in less work when the time comes to port the app. -The next chapter digs into details of how to migrate from ASP.NET MVC and Web API projects to ASP.NET Core projects. The previous chapter called out the biggest differences between the apps. Once the basic project structure is in place, migrating individual controllers and views is usually pretty straightforward, especially if they're mainly focused on web responsibilities. +The next chapter digs into details of how to migrate from ASP.NET MVC and Web API projects to ASP.NET Core projects. The previous chapter called out the biggest differences between the apps. Once the basic project structure is in place, migrating individual controllers and views is usually straightforward, especially if they're mainly focused on web responsibilities. ## References diff --git a/docs/architecture/porting-existing-aspnet-apps/webapi-differences.md b/docs/architecture/porting-existing-aspnet-apps/webapi-differences.md index 608a21820fcd0..61fef20323670 100644 --- a/docs/architecture/porting-existing-aspnet-apps/webapi-differences.md +++ b/docs/architecture/porting-existing-aspnet-apps/webapi-differences.md @@ -7,11 +7,11 @@ ms.date: 11/13/2020 # Compare ASP.NET Web API 2 and ASP.NET Core -ASP.NET Core offers iterative improvements to ASP.NET Web API 2, but should feel very familiar to developers who have used Web API 2. ASP.NET Web API 2 was developed and shipped alongside ASP.NET MVC, which meant that the two approaches had similar-but-different approaches to things like attribute routing and dependency injection. In ASP.NET Core, there is no longer any distinction between MVC and Web APIs. There is only ASP.NET MVC, which includes support for view-based scenarios, API endpoints, and Razor Pages (as well as other variations like health checks and SignalR). +ASP.NET Core offers iterative improvements to ASP.NET Web API 2, but should feel very familiar to developers who have used Web API 2. ASP.NET Web API 2 was developed and shipped alongside ASP.NET MVC. This meant the two approaches had similar-but-different approaches to things like attribute routing and dependency injection. In ASP.NET Core, there's no longer any distinction between MVC and Web APIs. There's only ASP.NET MVC, which includes support for view-based scenarios, API endpoints, and Razor Pages (as well as other variations like health checks and SignalR). -In addition to being consistent and unified within ASP.NET Core, APIs built in .NET Core are much easier to test than those built on ASP.NET Web API 2. We'll cover [testing differences](testing-differences.md) in more detail in a moment. The built-in support for hosting ASP.NET Core apps, in a test host which can create an `HttpClient` that makes in-memory requests to the app, is a huge benefit when it comes to automated testing. +In addition to being consistent and unified within ASP.NET Core, APIs built in .NET Core are much easier to test than those built on ASP.NET Web API 2. We'll cover [testing differences](testing-differences.md) in more detail in a moment. The built-in support for hosting ASP.NET Core apps, in a test host that can create an `HttpClient` that makes in-memory requests to the app, is a huge benefit when it comes to automated testing. -When migrating from ASP.NET Web API 2 to ASP.NET Core, the transition should be pretty straightforward. If you have controllers that are bloated and larger then you'd like, one approach you may consider to break them up is the use of the [Ardalis.ApiEndpoints](https://www.nuget.org/packages/Ardalis.ApiEndpoints/) NuGet packages. This package breaks up each endpoint into its own specific class, with associated request and response types as appropriate. This approach yields many of [the same benefits as Razor Pages offer over view-based code organization](comparing-razor-pages-aspnet-mvc.md). +When migrating from ASP.NET Web API 2 to ASP.NET Core, the transition should be pretty straightforward. If you have large, bloated controllers, one approach you may consider to break them up is the use of the [Ardalis.ApiEndpoints](https://www.nuget.org/packages/Ardalis.ApiEndpoints/) NuGet packages. This package breaks up each endpoint into its own specific class, with associated request and response types as appropriate. This approach yields many of [the same benefits as Razor Pages offer over view-based code organization](comparing-razor-pages-aspnet-mvc.md). ## References