Обновление с ASP платформа .NET Framework до ASP.NET Core

Почему обновление до последней версии .NET

ASP.NET Core — это современная веб-платформа для .NET. Хотя ASP.NET Core имеет множество сходств с ASP.NET в платформа .NET Framework, это новая платформа, которая полностью перезаписана. ASP.NET приложения, обновленные до ASP.NET Core, могут воспользоваться улучшенной производительностью и доступом к новейшим функциям и возможностям веб-разработки.

Подходы к обновлению ASP платформа .NET Framework

Большинство нетривиальных приложений ASP платформа .NET Framework следует рассмотреть возможность использования подхода добавочного обновления. Дополнительные сведения см. в разделе добавочные ASP.NET обновления ядра ASP.NET.

Сведения о ASP.NET приложениях MVC и веб-API см. в статье Об обновлении с ASP.NET MVC и веб-API до ASP.NET Core MVC. Сведения о приложениях ASP платформа .NET Framework веб-формы см. в статье "Сведения об обновлении с ASP.NET веб-формы до ASP.NET Core".

Надежные шаблоны веб-приложений

См. статью "Шаблон надежных веб-приложений" for.NET видео и статьи YouTube по созданию современного, надежного, производительного, тестового, экономичного и масштабируемого приложения ASP.NET Core, будь то с нуля или рефакторинг существующего приложения.

Декодирование URI между ASP.NET в ASP.NET Core

ASP.NET Core имеет следующие различия в декодировании URI с ASP платформа .NET Framework:

ASCII Encoded ASP.NET Core ASP.NET Framework
\ %5C \ /
/ %2F %2F /

При декодировании %2F в ASP.NET Core:

  • Весь путь становится неискаченным, за исключением %2F того, что преобразование будет / изменять структуру пути. Его нельзя декодировать, пока путь не будет разделен на сегменты.

Чтобы создать значение для HttpRequest.Url, используйте new Uri(this.AspNetCoreHttpRequest.GetEncodedUrl()); для предотвращения Uri неправильного понимания значений.

Перенос секретов пользователей из ASP платформа .NET Framework в ASP.NET Core

Также см. эту проблему в GitHub.

Данная статья служит руководством по миграции приложений ASP.NET на ASP.NET Core.

Visual Studio включает инструменты для переноса приложений ASP.NET на ASP.NET Core. Дополнительные сведения см. в статье Migrating from ASP.NET to ASP.NET Core in Visual Studio (Миграция с ASP.NET на ASP.NET Core в Visual Studio).

Помощник по обновлению .NET — это инструмент командной строки для миграции с ASP.NET на ASP.NET Core. Дополнительные сведения см. в разделах Обзор помощника по обновлению .NET и Обновление приложения ASP.NET MVC до .NET 6 с помощью помощника по обновлению .NET.

Полное руководство по переносу см. в книге Перенос существующих приложений ASP.NET в .NET Core .

Необходимые компоненты

.NET Core SDK 2.2 или более поздней версии.

Целевые платформы

Проекты ASP.NET Core предлагают разработчикам гибкость работы с .NET Core и .NET Framework. Определить наиболее подходящую платформу поможет статья Выбор между .NET Core и .NET Framework для серверных приложений.

При разработке для .NET Framework проекты должны ссылаться на отдельные пакеты NuGet.

Работа с .NET Core позволяет избавиться от многочисленных явных ссылок на пакеты благодаря метапакету ASP.NET Core. Установите метапакет Microsoft.AspNetCore.App в свой проект.

<ItemGroup>
   <PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>

При использовании метапакета никакие указанные по ссылкам пакеты с приложением не развертываются. Все эти ресурсы входят в хранилище среды выполнения .NET Core и предварительно компилируются для повышения производительности. Дополнительные сведения см. в статье Метапакет Microsoft.AspNetCore.App для ASP.NET Core 2.1.

Различия в структуре пакетов

Формат .csproj файла был упрощен в ASP.NET Core. Вот некоторые основные изменения.

  • Чтобы файлы считались частью проекта, включать их явно теперь не требуется. Это уменьшает вероятность конфликтов слияния XML при работе в больших командах.

  • GUID-ссылки на другие проекты не используются, что повышает удобочитаемость файла.

  • Файл можно редактировать, не выгружая его в Visual Studio.

    Параметр изменения файла CSPROJ в контекстном меню в Visual Studio 2017]

Замена файла Global.asax

В ASP.NET Core появился новый механизм для начальной загрузки приложения. Точкой входа для приложений ASP.NET стал файл Global.asax. Такие задачи, как конфигурация маршрута, а также регистрации фильтров и областей, теперь выполняются в файле Global.asax.

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
    }
}

При этом подходе приложение сопоставляется с сервером, на котором оно развертывается, таким образом, чтобы это не мешало реализации. Чтобы отделить приложение от сервера, был введен OWIN, который обеспечивает более точный способ совместного использования нескольких платформ. OWIN предоставляет конвейер для добавления только необходимых модулей. Среда внешнего размещения принимает функцию Startup для настройки служб и конвейера обработки запросов приложения. Startup регистрирует набор ПО промежуточного слоя в приложении. Для каждого запроса приложение вызывает каждый из компонентов ПО промежуточного слоя по заглавному указателю связанного списка на существующий набор обработчиков. Каждый компонент ПО промежуточного слоя может добавлять в конвейер обработки запросов один обработчик или несколько. Это достигается путем возвращения ссылки на обработчик, который представляет собой новый заголовок списка. Каждый обработчик отвечает за запоминание и вызов следующего обработчика в списке. При работе с ASP.NET Core точкой входа в приложения становится Startup, и зависимость от файла Global.asax исчезает. Используя OWIN с .NET Framework, применяйте для конвейера код следующего вида:

using Owin;
using System.Web.Http;

namespace WebApi
{
    // Note: By default all requests go through this OWIN pipeline. Alternatively you can turn this off by adding an appSetting owin:AutomaticAppStartup with value “false”. 
    // With this turned off you can still have OWIN apps listening on specific routes by adding routes in global.asax file using MapOwinPath or MapOwinRoute extensions on RouteTable.Routes
    public class Startup
    {
        // Invoked once at startup to configure your application.
        public void Configuration(IAppBuilder builder)
        {
            HttpConfiguration config = new HttpConfiguration();
            config.Routes.MapHttpRoute("Default", "{controller}/{customerID}", new { controller = "Customer", customerID = RouteParameter.Optional });

            config.Formatters.XmlFormatter.UseXmlSerializer = true;
            config.Formatters.Remove(config.Formatters.JsonFormatter);
            // config.Formatters.JsonFormatter.UseDataContractJsonSerializer = true;

            builder.UseWebApi(config);
        }
    }
}

Он определяет ваши маршруты по умолчанию и изначально предусматривает XmlSerialization по Json. При необходимости добавьте другое ПО промежуточного слоя для этого конвейера (загрузка служб, параметры конфигурации, статические файлы и т. д.).

ASP.NET Core использует аналогичный подход, но не требует OWIN для обработки запроса. Вместо этого это делается с помощью Program.cs Main метода (аналогично консольным приложениям) и Startup загружается через него.

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace WebApplication2
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

Startup должен включать метод Configure. В Configure добавьте в конвейер необходимое ПО промежуточного слоя. В примере ниже (на основе шаблона веб-сайта по умолчанию) используются методы расширения для настройки конвейера с поддержкой следующих компонентов:

  • Страницы ошибок
  • HTTP Strict Transport Security;
  • перенаправление с HTTP на HTTPS;
  • ASP.NET Core MVC
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseHsts();
    }

    app.UseHttpsRedirection();
    app.UseMvc();
}

Сервер и приложение разделены, что позволит вам в будущем легко перейти на другую платформу.

Примечание.

Более подробный справочник по запуску ASP.NET Core и ПО промежуточного слоя см. в статье Запуск в ASP.NET Core.

Конфигурации хранения

ASP.NET поддерживает параметры хранения. Эти параметры используются, например, для поддержки среды, в которой развертываются приложения. Как правило, все пользовательские пары ключей и значений хранятся в разделе <appSettings> файла Web.config:

<appSettings>
  <add key="UserName" value="User" />
  <add key="Password" value="Password" />
</appSettings>

Приложения считывают эти параметры с помощью коллекции ConfigurationManager.AppSettings в пространстве имен System.Configuration:

string userName = System.Web.Configuration.ConfigurationManager.AppSettings["UserName"];
string password = System.Web.Configuration.ConfigurationManager.AppSettings["Password"];

ASP.NET Core может сохранять данные конфигурации для приложения из любого файла и загружать их в процессе начальной загрузки ПО промежуточного слоя. По умолчанию в шаблонах проектов используется файл appsettings.json:

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "AppConfiguration": {
    "UserName": "UserName",
    "Password": "Password"
  }
}

Загрузка этого файла в экземпляр IConfiguration внутри приложения выполняется в Startup.cs:

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

Для получения этих параметров приложение считывает данные из Configuration:

string userName = Configuration.GetSection("AppConfiguration")["UserName"];
string password = Configuration.GetSection("AppConfiguration")["Password"];

Существуют расширения, повышающие надежность этого подхода, например, внедрение зависимостей позволяет загружать эти значения в службу. Метод внедрения зависимостей предоставляет строго типизированный набор объектов конфигурации.

// Assume AppConfiguration is a class representing a strongly-typed version of AppConfiguration section
services.Configure<AppConfiguration>(Configuration.GetSection("AppConfiguration"));

Примечание.

Более подробное руководство по конфигурации ASP.NET Core см. в статье Конфигурация в ASP.NET Core.

Собственные функции внедрения зависимостей

При сборке больших, масштабируемых приложений важно обеспечить слабые взаимозависимости между компонентами и службами. Внедрение зависимостей — популярный способ решения этой задачи и собственный компонент ASP.NET Core.

В приложениях ASP.NET разработчики используют для внедрения зависимостей стороннюю библиотеку. Одна из таких библиотек, Unity, входит в шаблоны и рекомендации Майкрософт.

Пример внедрения зависимостей с использованием библиотеки Unity — это реализация IDependencyResolver как оболочки для UnityContainer:

using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;

public class UnityResolver : IDependencyResolver
{
    protected IUnityContainer container;

    public UnityResolver(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return container.ResolveAll(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return new List<object>();
        }
    }

    public IDependencyScope BeginScope()
    {
        var child = container.CreateChildContainer();
        return new UnityResolver(child);
    }

    public void Dispose()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        container.Dispose();
    }
}

Создайте экземпляр UnityContainer, зарегистрируйте свою службу и установите средство разрешения зависимостей HttpConfiguration в новый экземпляр UnityResolver для вашего контейнера:

public static void Register(HttpConfiguration config)
{
    var container = new UnityContainer();
    container.RegisterType<IProductRepository, ProductRepository>(new HierarchicalLifetimeManager());
    config.DependencyResolver = new UnityResolver(container);

    // Other Web API configuration not shown.
}

Там, где необходимо, вставьте IProductRepository:

public class ProductsController : ApiController
{
    private IProductRepository _repository;

    public ProductsController(IProductRepository repository)  
    {
        _repository = repository;
    }

    // Other controller methods not shown.
}

Так как внедрение зависимостей является частью ASP.NET Core, вы можете добавить службу в ConfigureServices метод Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    // Add application services.
    services.AddTransient<IProductRepository, ProductRepository>();
}

Репозиторий, как и в Unity, можно внедрять где угодно.

Примечание.

Дополнительные сведения о внедрении зависимостей см. здесь.

Обслуживание статических файлов

Важной частью разработки веб-приложений является возможность обслуживания статических ресурсов на стороне клиента. Наиболее распространенные примеры статических файлов — это HTML, каскадные таблицы стилей, Javascript и изображения. Эти файлы необходимо сохранять в место публикации приложения (или CDN) и указывать по ссылкам, чтобы они могли загружаться по запросу. В ASP.NET Core ситуация изменилась.

В ASP.NET статические файлы хранятся в разных папках со ссылками в представлениях.

В ASP.NET Core, если не заданы другие настройки, статические файлы хранятся на корневом веб-узле (<содержимое корневой папки>/wwwroot). Файлы загружаются в конвейер запросов путем вызова метода расширения UseStaticFiles из Startup.Configure:

Примечание.

Для работы с .NET Framework установите пакет NuGet Microsoft.AspNetCore.StaticFiles.

Например, ресурс изображения в папке wwwroot/images доступен для браузера в расположении http://<app>/images/<imageFileName>.

Примечание.

Более подробное руководство по обработке статических файлов в ASP.NET Core см. в статье Статические файлы.

Файлы cookie с несколькими значениями

Файлы cookie с несколькими значениями не поддерживаются в ASP.NET Core. Создайте один файл cookie для каждого значения.

Файлы cookie проверки подлинности не сжимаются в ASP.NET Core

По соображениям безопасности файлы cookie проверки подлинности не сжимаются в ASP.NET Core. При использовании файлов cookie проверки подлинности разработчики должны свести к минимуму количество сведений о утверждениях, включенных только в то, что необходимо для их потребностей.

Частичная миграция приложений

Один из способов выполнить частичную миграцию приложений предусматривает создание вспомогательного приложения IIS и перенос из ASP.NET 4.x в ASP.NET Core только некоторых маршрутов с сохранением структуры URL-адресов приложения. Рассмотрим структуру URL-адресов приложения из файла applicationHost.config:

<sites>
    <site name="Default Web Site" id="1" serverAutoStart="true">
        <application path="/">
            <virtualDirectory path="/" physicalPath="D:\sites\MainSite\" />
        </application>
        <application path="/api" applicationPool="DefaultAppPool">
            <virtualDirectory path="/" physicalPath="D:\sites\netcoreapi" />
        </application>
        <bindings>
            <binding protocol="http" bindingInformation="*:80:" />
            <binding protocol="https" bindingInformation="*:443:" sslFlags="0" />
        </bindings>
    </site>
	...
</sites>

Структура каталогов:

.
├── MainSite
│   ├── ...
│   └── Web.config
└── NetCoreApi
    ├── ...
    └── web.config

[BIND] и форматировщики входных данных

В предыдущих версиях ASP.NET использовался атрибут [Bind] для защиты от атак чрезмерной передачи данных. Форматировщики входных данных работают по-разному в ASP.NET Core. Атрибут [Bind] больше не предназначен для предотвращения чрезмерной передачи данных при использовании с форматировщиками входных данных для анализа JSON или XML. Эти атрибуты влияют на привязку модели, когда источником данных являются данные формы, опубликованные с типом содержимого x-www-form-urlencoded.

Для приложений, которые передают данные JSON в контроллеры и используют форматировщики входных данных JSON для анализа данных, рекомендуется заменить атрибут [Bind] моделью представления, которая соответствует свойствам, определенным атрибутом [Bind].

Дополнительные ресурсы