Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Aanbeveling
Deze inhoud is een fragment uit het eBook, Blazor voor ASP NET-webformulierontwikkelaars voor Azure, beschikbaar op .NET Docs of als een gratis downloadbare PDF die offline kan worden gelezen.
Het migreren van een codebasis van ASP.NET Web Forms naar Blazor is een tijdrovende taak waarvoor planning is vereist. In dit hoofdstuk wordt het proces beschreven. Iets wat de overgang kan vereenvoudigen, is ervoor te zorgen dat de app voldoet aan een N-laag-architectuur , waarbij het app-model (in dit geval Web Forms) losstaat van de bedrijfslogica. Deze logische scheiding van lagen maakt duidelijk wat er moet worden verplaatst naar .NET Core en Blazor.
In dit voorbeeld wordt de eShop-app die beschikbaar is op GitHub gebruikt. eShop is een catalogusservice die CRUD-mogelijkheden biedt via formulierinvoer en validatie.
Waarom moet een werkende app worden gemigreerd naar Blazor? Vaak is het niet nodig. ASP.NET webformulieren worden nog vele jaren ondersteund. Veel van de functies die Blazor u biedt, worden echter alleen ondersteund voor een gemigreerde app. Dergelijke functies zijn onder andere:
- Prestatieverbeteringen in het framework, zoals
Span<T> - Mogelijkheid om uit te voeren als WebAssembly
- Platformoverschrijdende ondersteuning voor Linux en macOS
- App-lokale implementatie of gedeelde frameworkimplementatie zonder dat dit van invloed is op andere apps
Als deze of andere nieuwe functies overtuigend genoeg zijn, is het mogelijk dat de app wordt gemigreerd. De migratie kan verschillende vormen aannemen; dit kan de hele app zijn of alleen bepaalde eindpunten waarvoor de wijzigingen zijn vereist. De beslissing om te migreren is uiteindelijk gebaseerd op de zakelijke problemen die door de ontwikkelaar moeten worden opgelost.
Serverzijde versus hosting aan clientzijde
Zoals beschreven in het hoofdstuk hostingmodellen , kan een Blazor app op twee verschillende manieren worden gehost: serverzijde en clientzijde. Het model aan de serverzijde maakt gebruik van ASP.NET Core SignalR-verbindingen om de DOM-updates te beheren tijdens het uitvoeren van werkelijke code op de server. Het model aan de clientzijde wordt uitgevoerd in WebAssembly een browser en vereist geen serververbindingen. Er zijn een aantal verschillen die van invloed kunnen zijn op wat het beste is voor een specifieke app:
- Uitvoeren als WebAssembly biedt geen ondersteuning voor alle functies (zoals threading) op het huidige moment
- Chatty communication between the client and server may cause latency issues in server side mode
- Toegang tot databases en interne of beveiligde services vereisen een afzonderlijke service met hosting aan clientzijde
Op het moment van schrijven lijkt het model aan de serverzijde beter op webformulieren. Het grootste deel van dit hoofdstuk is gericht op het hostingmodel aan de serverzijde, omdat het klaar is voor productie.
Een nieuw project maken
Deze eerste migratiestap is het maken van een nieuw project. Dit projecttype is gebaseerd op de SDK-stijlprojecten van .NET en vereenvoudigt veel van de standaard die in eerdere projectindelingen is gebruikt. Zie het hoofdstuk over projectstructuur voor meer informatie.
Nadat het project is gemaakt, installeert u de bibliotheken die in het vorige project zijn gebruikt. In oudere Web Forms-projecten hebt u mogelijk het bestand packages.config gebruikt om de vereiste NuGet-pakketten weer te geven. In het nieuwe SDK-project is packages.config vervangen door <PackageReference> elementen in het projectbestand. Een voordeel van deze benadering is dat alle afhankelijkheden transitief worden geïnstalleerd. U vermeldt alleen de afhankelijkheden op het hoogste niveau die u belangrijk vindt.
Veel van de afhankelijkheden die u gebruikt, zijn beschikbaar voor .NET, waaronder Entity Framework 6 en log4net. Als er geen .NET- of .NET Standard-versie beschikbaar is, kan de .NET Framework-versie vaak worden gebruikt. Uw kilometerstand kan variëren. Elke API die niet beschikbaar is in .NET, veroorzaakt een runtimefout. Visual Studio meldt u van dergelijke pakketten. Er wordt een geel pictogram weergegeven op het knooppunt Verwijzingen van het project in Solution Explorer.
In het BlazoreShop-project op basis van eShop ziet u de pakketten die zijn geïnstalleerd. Voorheen vermeldde het bestand packages.config elk pakket dat in het project wordt gebruikt, wat resulteert in een bestand van bijna 50 regels. Een fragment van packages.config is:
<?xml version="1.0" encoding="utf-8"?>
<packages>
...
<package id="Microsoft.ApplicationInsights.Agent.Intercept" version="2.4.0" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.DependencyCollector" version="2.9.1" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.PerfCounterCollector" version="2.9.1" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.Web" version="2.9.1" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.WindowsServer" version="2.9.1" targetFramework="net472" />
<package id="Microsoft.ApplicationInsights.WindowsServer.TelemetryChannel" version="2.9.1" targetFramework="net472" />
<package id="Microsoft.AspNet.FriendlyUrls" version="1.0.2" targetFramework="net472" />
<package id="Microsoft.AspNet.FriendlyUrls.Core" version="1.0.2" targetFramework="net472" />
<package id="Microsoft.AspNet.ScriptManager.MSAjax" version="5.0.0" targetFramework="net472" />
<package id="Microsoft.AspNet.ScriptManager.WebForms" version="5.0.0" targetFramework="net472" />
...
<package id="System.Memory" version="4.5.1" targetFramework="net472" />
<package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net472" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.0" targetFramework="net472" />
<package id="System.Threading.Channels" version="4.5.0" targetFramework="net472" />
<package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net472" />
<package id="WebGrease" version="1.6.0" targetFramework="net472" />
</packages>
Het <packages> element bevat alle benodigde afhankelijkheden. Het is moeilijk om te bepalen welke van deze pakketten zijn opgenomen omdat u ze nodig hebt. Sommige <package> elementen worden weergegeven om te voldoen aan de behoeften van afhankelijkheden die u nodig hebt.
Het Blazor project bevat de afhankelijkheden die u nodig hebt binnen een <ItemGroup> element in het projectbestand:
<ItemGroup>
<PackageReference Include="Autofac" Version="4.9.3" />
<PackageReference Include="EntityFramework" Version="6.4.4" />
<PackageReference Include="log4net" Version="2.0.12" />
<PackageReference Include="Microsoft.Extensions.Logging.Log4Net.AspNetCore" Version="2.2.12" />
</ItemGroup>
Eén NuGet-pakket dat het leven van webformulierontwikkelaars vereenvoudigt, is het Windows-compatibiliteitspakket. Hoewel .NET platformoverschrijdend is, zijn sommige functies alleen beschikbaar in Windows. Windows-specifieke functies worden beschikbaar gesteld door het compatibiliteitspakket te installeren. Voorbeelden van dergelijke functies zijn het register, WMI en Directory Services. Het pakket voegt ongeveer 20.000 API's toe en activeert veel services waarmee u mogelijk al bekend bent. Voor het eShop-project is het compatibiliteitspakket niet vereist; maar als uw projecten gebruikmaken van Windows-specifieke functies, vereenvoudigt het pakket de migratie-inspanningen.
Opstartproces inschakelen
Het opstartproces voor Blazor webformulieren is gewijzigd en volgt een vergelijkbare installatie voor andere ASP.NET Core-services. Bij gehoste serverzijde worden Razor-onderdelen uitgevoerd als onderdeel van een normale ASP.NET Core-app. Wanneer razor-onderdelen worden gehost in de browser met WebAssembly, gebruiken Razor-onderdelen een vergelijkbaar hostingmodel. Het verschil is dat de onderdelen worden uitgevoerd als een afzonderlijke service van een van de back-endprocessen. Hoe dan ook, het opstarten is vergelijkbaar.
Het Global.asax.cs-bestand is de standaardstartpagina voor Web Forms-projecten. In het eShop-project configureert dit bestand de IoC-container (Inversion of Control) en verwerkt deze de verschillende levenscyclus-gebeurtenissen van de app of aanvraag. Sommige van deze gebeurtenissen worden verwerkt met middleware (zoals Application_BeginRequest). Voor andere gebeurtenissen is het overschrijven van specifieke services via afhankelijkheidsinjectie (DI) vereist.
Het bestand Global.asax.cs voor eShop bevat bijvoorbeeld de volgende code:
public class Global : HttpApplication, IContainerProviderAccessor
{
private static readonly ILog _log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
static IContainerProvider _containerProvider;
IContainer container;
public IContainerProvider ContainerProvider
{
get { return _containerProvider; }
}
protected void Application_Start(object sender, EventArgs e)
{
// Code that runs on app startup
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ConfigureContainer();
ConfigDataBase();
}
/// <summary>
/// Track the machine name and the start time for the session inside the current session
/// </summary>
protected void Session_Start(Object sender, EventArgs e)
{
HttpContext.Current.Session["MachineName"] = Environment.MachineName;
HttpContext.Current.Session["SessionStartTime"] = DateTime.Now;
}
/// <summary>
/// https://autofaccn.readthedocs.io/en/latest/integration/webforms.html
/// </summary>
private void ConfigureContainer()
{
var builder = new ContainerBuilder();
var mockData = bool.Parse(ConfigurationManager.AppSettings["UseMockData"]);
builder.RegisterModule(new ApplicationModule(mockData));
container = builder.Build();
_containerProvider = new ContainerProvider(container);
}
private void ConfigDataBase()
{
var mockData = bool.Parse(ConfigurationManager.AppSettings["UseMockData"]);
if (!mockData)
{
Database.SetInitializer<CatalogDBContext>(container.Resolve<CatalogDBInitializer>());
}
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
//set the property to our new object
LogicalThreadContext.Properties["activityid"] = new ActivityIdHelper();
LogicalThreadContext.Properties["requestinfo"] = new WebRequestInfo();
_log.Debug("Application_BeginRequest");
}
}
Het voorgaande bestand wordt het Program.cs bestand aan de serverzijde Blazor:
using eShopOnBlazor.Models;
using eShopOnBlazor.Models.Infrastructure;
using eShopOnBlazor.Services;
using log4net;
using System.Data.Entity;
using eShopOnBlazor;
var builder = WebApplication.CreateBuilder(args);
// add services
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
if (builder.Configuration.GetValue<bool>("UseMockData"))
{
builder.Services.AddSingleton<ICatalogService, CatalogServiceMock>();
}
else
{
builder.Services.AddScoped<ICatalogService, CatalogService>();
builder.Services.AddScoped<IDatabaseInitializer<CatalogDBContext>, CatalogDBInitializer>();
builder.Services.AddSingleton<CatalogItemHiLoGenerator>();
builder.Services.AddScoped(_ => new CatalogDBContext(builder.Configuration.GetConnectionString("CatalogDBContext")));
}
var app = builder.Build();
new LoggerFactory().AddLog4Net("log4Net.xml");
if (app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
// Middleware for Application_BeginRequest
app.Use((ctx, next) =>
{
LogicalThreadContext.Properties["activityid"] = new ActivityIdHelper(ctx);
LogicalThreadContext.Properties["requestinfo"] = new WebRequestInfo(ctx);
return next();
});
app.UseStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
ConfigDataBase(app);
void ConfigDataBase(IApplicationBuilder app)
{
using (var scope = app.ApplicationServices.CreateScope())
{
var initializer = scope.ServiceProvider.GetService<IDatabaseInitializer<CatalogDBContext>>();
if (initializer != null)
{
Database.SetInitializer(initializer);
}
}
}
app.Run();
Een belangrijke wijziging die u van Web Forms kunt merken, is het belang van afhankelijkheidsinjectie (DI). DI is een leidraad in het ASP.NET Core-ontwerp. Het ondersteunt het aanpassen van bijna alle aspecten van het ASP.NET Core-framework. Er is zelfs een ingebouwde serviceprovider die voor veel scenario's kan worden gebruikt. Als er meer aanpassingen nodig zijn, kan dit worden ondersteund door veel communityprojecten. U kunt bijvoorbeeld uw investering in di-bibliotheken van derden doorsturen.
In de oorspronkelijke eShop-app is er een configuratie voor sessiebeheer. Omdat aan de serverzijde Blazor ASP.NET Core SignalR wordt gebruikt voor communicatie, wordt de sessiestatus niet ondersteund omdat de verbindingen onafhankelijk van een HTTP-context kunnen optreden. Voor een app die gebruikmaakt van de sessiestatus moet u opnieuw ontwerpen voordat deze als app Blazor wordt uitgevoerd.
Zie App opstarten voor meer informatie over het opstarten van apps.
HTTP-modules en handlers migreren naar middleware
HTTP-modules en handlers zijn veelvoorkomende patronen in Web Forms om de HTTP-aanvraagpijplijn te beheren. Klassen die binnenkomende aanvragen implementeren IHttpModule of IHttpHandler kunnen worden geregistreerd en verwerkt. Web Forms configureert modules en handlers in het bestand web.config . Web Forms is ook sterk gebaseerd op het verwerken van gebeurtenissen in de levenscyclus van apps. ASP.NET Core maakt in plaats daarvan gebruik van middleware. Middleware wordt geregistreerd in de Configure methode van de Startup klasse. De uitvoeringsorder van Middleware wordt bepaald door de registratieorder.
In de sectie Opstartproces inschakelen is een levenscyclusgebeurtenis gegenereerd door Web Forms als methode Application_BeginRequest . Deze gebeurtenis is niet beschikbaar in ASP.NET Core. Een manier om dit gedrag te bereiken, is door middleware te implementeren, zoals te zien is in het voorbeeld van het Startup.cs bestand. Deze middleware voert dezelfde logica uit en draagt vervolgens het besturingselement over naar de volgende handler in de middleware-pijplijn.
Zie HTTP-handlers en modules migreren naar ASP.NET Core middleware voor meer informatie over het migreren van modules en handlers.
Statische bestanden migreren
Als u statische bestanden wilt leveren (bijvoorbeeld HTML, CSS, afbeeldingen en JavaScript), moeten de bestanden worden weergegeven door middleware. Als u de UseStaticFiles methode aanroept, wordt het leveren van statische bestanden vanaf het hoofdpad van het web mogelijk. De standaardmap van de webhoofdmap is wwwroot, maar kan worden aangepast. Zoals opgenomen in het Program.cs-bestand :
...
app.UseStaticFiles();
...
Het eShop-project maakt eenvoudige statische bestandstoegang mogelijk. Er zijn veel aanpassingen beschikbaar voor statische bestandstoegang. Zie Statische bestanden in ASP.NET Core voor informatie over het inschakelen van standaardbestanden of een bestandsbrowser.
Runtime-bundeling en minificatie-installatie migreren
Bundeling en minificatie zijn technieken voor het optimaliseren van prestaties voor het verminderen van het aantal en de grootte van serveraanvragen om bepaalde bestandstypen op te halen. JavaScript en CSS ondergaan vaak een vorm van bundeling of minificatie voordat ze naar de client worden verzonden. In ASP.NET Web Forms worden deze optimalisaties tijdens runtime verwerkt. De optimalisatieconventies worden gedefinieerd als een App_Start/BundleConfig.cs-bestand . In ASP.NET Core wordt een meer declaratieve benadering aangenomen. Een bestand bevat de bestanden die moeten worden geminimificeerd, samen met specifieke minificatie-instellingen.
Zie Bundel en minificatie van statische assets in ASP.NET Core voor meer informatie over bundeling en minificatie.
ASPX-pagina's migreren
Een pagina in een Web Forms-app is een bestand met de extensie .aspx . Een webpagina met webformulieren kan vaak worden toegewezen aan een onderdeel in Blazor. Een Razor-onderdeel is geschreven in een bestand met de extensie .razor . Voor het eShop-project worden vijf pagina's geconverteerd naar een Razor-pagina.
De detailweergave bestaat bijvoorbeeld uit drie bestanden in het webformulierproject: Details.aspx, Details.aspx.cs en Details.aspx.designer.cs. Bij het converteren naar Blazor, worden de code-behind en markeringen gecombineerd in Details.razor. Razor-compilatie (gelijk aan wat zich in .designer.cs bestanden bevindt) wordt opgeslagen in de obj-map en is standaard niet zichtbaar in Solution Explorer. De pagina Webformulieren bestaat uit de volgende markeringen:
<%@ Page Title="Details" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Details.aspx.cs" Inherits="eShopLegacyWebForms.Catalog.Details" %>
<asp:Content ID="Details" ContentPlaceHolderID="MainContent" runat="server">
<h2 class="esh-body-title">Details</h2>
<div class="container">
<div class="row">
<asp:Image runat="server" CssClass="col-md-6 esh-picture" ImageUrl='<%#"/Pics/" + product.PictureFileName%>' />
<dl class="col-md-6 dl-horizontal">
<dt>Name
</dt>
<dd>
<asp:Label runat="server" Text='<%#product.Name%>' />
</dd>
<dt>Description
</dt>
<dd>
<asp:Label runat="server" Text='<%#product.Description%>' />
</dd>
<dt>Brand
</dt>
<dd>
<asp:Label runat="server" Text='<%#product.CatalogBrand.Brand%>' />
</dd>
<dt>Type
</dt>
<dd>
<asp:Label runat="server" Text='<%#product.CatalogType.Type%>' />
</dd>
<dt>Price
</dt>
<dd>
<asp:Label CssClass="esh-price" runat="server" Text='<%#product.Price%>' />
</dd>
<dt>Picture name
</dt>
<dd>
<asp:Label runat="server" Text='<%#product.PictureFileName%>' />
</dd>
<dt>Stock
</dt>
<dd>
<asp:Label runat="server" Text='<%#product.AvailableStock%>' />
</dd>
<dt>Restock
</dt>
<dd>
<asp:Label runat="server" Text='<%#product.RestockThreshold%>' />
</dd>
<dt>Max stock
</dt>
<dd>
<asp:Label runat="server" Text='<%#product.MaxStockThreshold%>' />
</dd>
</dl>
</div>
<div class="form-actions no-color esh-link-list">
<a runat="server" href='<%# GetRouteUrl("EditProductRoute", new {id =product.Id}) %>' class="esh-link-item">Edit
</a>
|
<a runat="server" href="~" class="esh-link-item">Back to list
</a>
</div>
</div>
</asp:Content>
De code-behind van de voorgaande markering bevat de volgende code:
using eShopLegacyWebForms.Models;
using eShopLegacyWebForms.Services;
using log4net;
using System;
using System.Web.UI;
namespace eShopLegacyWebForms.Catalog
{
public partial class Details : System.Web.UI.Page
{
private static readonly ILog _log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected CatalogItem product;
public ICatalogService CatalogService { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
var productId = Convert.ToInt32(Page.RouteData.Values["id"]);
_log.Info($"Now loading... /Catalog/Details.aspx?id={productId}");
product = CatalogService.FindCatalogItem(productId);
this.DataBind();
}
}
}
Wanneer deze wordt geconverteerd naar Blazor, wordt de pagina Web Forms omgezet in de volgende code:
@page "/Catalog/Details/{id:int}"
@inject ICatalogService CatalogService
@inject ILogger<Details> Logger
<h2 class="esh-body-title">Details</h2>
<div class="container">
<div class="row">
<img class="col-md-6 esh-picture" src="@($"/Pics/{_item.PictureFileName}")">
<dl class="col-md-6 dl-horizontal">
<dt>
Name
</dt>
<dd>
@_item.Name
</dd>
<dt>
Description
</dt>
<dd>
@_item.Description
</dd>
<dt>
Brand
</dt>
<dd>
@_item.CatalogBrand.Brand
</dd>
<dt>
Type
</dt>
<dd>
@_item.CatalogType.Type
</dd>
<dt>
Price
</dt>
<dd>
@_item.Price
</dd>
<dt>
Picture name
</dt>
<dd>
@_item.PictureFileName
</dd>
<dt>
Stock
</dt>
<dd>
@_item.AvailableStock
</dd>
<dt>
Restock
</dt>
<dd>
@_item.RestockThreshold
</dd>
<dt>
Max stock
</dt>
<dd>
@_item.MaxStockThreshold
</dd>
</dl>
</div>
<div class="form-actions no-color esh-link-list">
<a href="@($"/Catalog/Edit/{_item.Id}")" class="esh-link-item">
Edit
</a>
|
<a href="/" class="esh-link-item">
Back to list
</a>
</div>
</div>
@code {
private CatalogItem _item;
[Parameter]
public int Id { get; set; }
protected override void OnInitialized()
{
Logger.LogInformation("Now loading... /Catalog/Details/{Id}", Id);
_item = CatalogService.FindCatalogItem(Id);
}
}
U ziet dat de code en markeringen zich in hetzelfde bestand bevinden. Alle vereiste services worden toegankelijk gemaakt met het @inject kenmerk. Volgens de @page richtlijn is deze pagina toegankelijk op de Catalog/Details/{id} route. De waarde van de tijdelijke aanduiding voor de route {id} is beperkt tot een geheel getal. Zoals beschreven in de routeringssectie , in tegenstelling tot Web Forms, geeft een Razor-onderdeel expliciet de route en eventuele parameters op die zijn opgenomen. Veel webformulierbesturingselementen hebben mogelijk geen exacte tegenhangers in Blazor. Er is vaak een equivalent HTML-fragment dat hetzelfde doel biedt. Het besturingselement kan bijvoorbeeld <asp:Label /> worden vervangen door een HTML-element <label> .
Modelvalidatie in Blazor
Als uw webformuliercode validatie bevat, kunt u veel van wat u hebt met weinig tot geen wijzigingen overdragen. Een voordeel om in Blazor te voeren is dat dezelfde validatielogica kan worden uitgevoerd zonder aangepaste JavaScript nodig te hebben. Gegevensaantekeningen maken eenvoudige modelvalidatie mogelijk.
De pagina Create.aspx heeft bijvoorbeeld een gegevensinvoerformulier met validatie. Een voorbeeldfragment ziet er als volgt uit:
<div class="form-group">
<label class="control-label col-md-2">Name</label>
<div class="col-md-3">
<asp:TextBox ID="Name" runat="server" CssClass="form-control"></asp:TextBox>
<asp:RequiredFieldValidator runat="server" ControlToValidate="Name" Display="Dynamic"
CssClass="field-validation-valid text-danger" ErrorMessage="The Name field is required." />
</div>
</div>
In Blazorwordt de equivalente opmaak opgegeven in een Create.razor-bestand :
<EditForm Model="_item" OnValidSubmit="@...">
<DataAnnotationsValidator />
<div class="form-group">
<label class="control-label col-md-2">Name</label>
<div class="col-md-3">
<InputText class="form-control" @bind-Value="_item.Name" />
<ValidationMessage For="(() => _item.Name)" />
</div>
</div>
...
</EditForm>
De EditForm context bevat validatieondersteuning en kan worden verpakt rond een invoer. Gegevensaantekeningen zijn een veelgebruikte manier om validatie toe te voegen. Dergelijke validatieondersteuning kan worden toegevoegd via het DataAnnotationsValidator onderdeel. Zie ASP.NET Core-formulieren Blazor en -validatie voor meer informatie over dit mechanisme.
Configuratie migreren
In een Web Forms-project worden configuratiegegevens meestal opgeslagen in het web.config-bestand . De configuratiegegevens worden geopend met ConfigurationManager. Services waren vaak vereist om objecten te parseren. Met .NET Framework 4.7.2 is de composabiliteit toegevoegd aan de configuratie via ConfigurationBuilders. Deze bouwers hebben ontwikkelaars toegestaan verschillende bronnen toe te voegen voor de configuratie die vervolgens tijdens runtime is samengesteld om de benodigde waarden op te halen.
ASP.NET Core heeft een flexibel configuratiesysteem geïntroduceerd waarmee u de configuratiebron of bronnen kunt definiëren die door uw app en implementatie worden gebruikt. De ConfigurationBuilder infrastructuur die u mogelijk in uw Web Forms-app gebruikt, is gemodelleerd naar de concepten die worden gebruikt in het ASP.NET Core-configuratiesysteem.
In het volgende codefragment ziet u hoe het project Web Forms eShop web.config gebruikt om configuratiewaarden op te slaan:
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="CatalogDBContext" connectionString="Data Source=(localdb)\MSSQLLocalDB; Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb; Integrated Security=True; MultipleActiveResultSets=True;" providerName="System.Data.SqlClient" />
</connectionStrings>
<appSettings>
<add key="UseMockData" value="true" />
<add key="UseCustomizationData" value="false" />
</appSettings>
</configuration>
Het is gebruikelijk dat geheimen, zoals database-verbindingsreeks s, worden opgeslagen in de web.config. De geheimen worden onvermijdelijk bewaard op onbeveiligde locaties, zoals broncodebeheer. In Blazor ASP.NET Core wordt de voorgaande op XML gebaseerde configuratie vervangen door de volgende JSON:
{
"ConnectionStrings": {
"CatalogDBContext": "Data Source=(localdb)\\MSSQLLocalDB; Initial Catalog=Microsoft.eShopOnContainers.Services.CatalogDb; Integrated Security=True; MultipleActiveResultSets=True;"
},
"UseMockData": true,
"UseCustomizationData": false
}
JSON is de standaardconfiguratie-indeling; ASP.NET Core ondersteunt echter veel andere indelingen, waaronder XML. Er zijn ook verschillende indelingen die door de community worden ondersteund.
U kunt in Program.cs toegang krijgen tot configuratiewaarden van de opbouwfunctie:
if (builder.Configuration.GetValue<bool>("UseMockData"))
{
builder.Services.AddSingleton<ICatalogService, CatalogServiceMock>();
}
else
{
builder.Services.AddScoped<ICatalogService, CatalogService>();
builder.Services.AddScoped<IDatabaseInitializer<CatalogDBContext>, CatalogDBInitializer>();
builder.Services.AddSingleton<CatalogItemHiLoGenerator>();
builder.Services.AddScoped(_ => new CatalogDBContext(builder.Configuration.GetConnectionString("CatalogDBContext")));
}
Standaard zijn omgevingsvariabelen, JSON-bestanden (appsettings.json en appsettings.{ Omgeving}.json) en opdrachtregelopties worden geregistreerd als geldige configuratiebronnen in het configuratieobject. De configuratiebronnen zijn toegankelijk via Configuration[key]. Een geavanceerdere techniek is het binden van de configuratiegegevens aan objecten met behulp van het optiespatroon. Zie Configuratie in ASP.NET core - en optiespatroon in respectievelijk ASP.NET Core voor meer informatie over configuratie en het optiespatroon.
Gegevenstoegang migreren
Gegevenstoegang is een belangrijk aspect van elke app. Het eShop-project slaat catalogusgegevens op in een database en haalt de gegevens op met Entity Framework (EF) 6. Omdat EF 6 wordt ondersteund in .NET 5, kan het project het blijven gebruiken.
De volgende EF-gerelateerde wijzigingen waren nodig voor eShop:
- In .NET Framework accepteert het
DbContextobject een tekenreeks van de formuliernaam=ConnectionString en wordt de verbindingsreeks gebruikt omConfigurationManager.AppSettings[ConnectionString]verbinding te maken. In .NET Core wordt dit niet ondersteund. De verbindingsreeks moet worden opgegeven. - De database is synchroon geopend. Hoewel dit werkt, kan schaalbaarheid lijden. Deze logica moet worden verplaatst naar een asynchroon patroon.
Hoewel er niet dezelfde systeemeigen ondersteuning is voor gegevenssetbinding, Blazor biedt u flexibiliteit en kracht met de C#-ondersteuning op een Razor-pagina. U kunt bijvoorbeeld berekeningen uitvoeren en het resultaat weergeven. Zie het Blazor voor meer informatie over gegevenspatronen in.
Architectuur
Ten slotte zijn er enkele belangrijke architecturale verschillen waarmee u rekening moet houden bij het migreren naar Blazor. Veel van deze wijzigingen zijn van toepassing op alles op basis van .NET Core of ASP.NET Core.
Omdat Blazor deze is gebouwd op .NET Core, zijn er overwegingen bij het waarborgen van ondersteuning voor .NET Core. Enkele van de belangrijkste wijzigingen zijn het verwijderen van de volgende functies:
- Meerdere AppDomains
- Externe toegang
- Code Access Security (CAS) - Beveiliging van code toegang
- Transparantie van beveiliging
Zie Uw code van .NET Framework overzetten naar .NET Core voor meer informatie over technieken voor het identificeren van de benodigde wijzigingen ter ondersteuning van .NET Core.
ASP.NET Core is een opnieuw ontworpen versie van ASP.NET en heeft enkele wijzigingen die in eerste instantie niet duidelijk lijken. De belangrijkste wijzigingen zijn:
- Geen synchronisatiecontext, wat betekent dat er geen
HttpContext.Current,Thread.CurrentPrincipalof andere statische accessors zijn - Geen schaduwkopie
- Geen aanvraagwachtrij
Veel bewerkingen in ASP.NET Core zijn asynchroon, waardoor I/O-gebonden taken eenvoudiger kunnen worden geladen. Het is belangrijk om nooit te blokkeren met behulp van Task.Wait() of Task.GetResult(), waardoor resources voor threadgroepen snel kunnen worden uitgeput.
Migratieconcluse
Op dit moment hebt u veel voorbeelden gezien van wat nodig is om een Web Forms-project naar te Blazorverplaatsen. Zie het eShopOnBlazor-project voor een volledig voorbeeld.