1.1. Создание первого проекта

В случае с созданием проекта на данный момент есть небольшая разница, потому что в Windows нужно выбрать меню File -> New -> Project, а в macOS версии нужно выбрать меню File -> New Solution. Казалось бы, есть большая разница, но в реальности, когда в Windows мы выбирает создание нового проекта, будет создан не только проект (Project), но и решение (Solution)

Та же песня и в macOS – хотя мы выбрали создание решения, будет так же создан и проект.

Проект – это код одного файла – библиотеки, исполняемого файла или сайта. Решение – это как папка для нескольких проектов. В одно решение может входить сразу несколько проектов – несколько библиотек и исполняемый файл или web сайт.

Итак, после выбора меню создания проекта/решения, вы увидите это окно в macOS. Опять же, в Windows оно будет отличаться, но идея будет та же:

Слева можно выбирать категории проектов, мы в этой книге будем говорить про .NET Core приложения. Выбрав категорию, в центральной части окна можно выбрать шаблон. Я выбрал ASP .NET Core Web App.

Если нажать далее, то в macOS версии вторым шагом мастера будет выбор версии .NET Core. В Windows вторым шагом идет выбор более конкретного шаблона. Для Web их есть несколько – пустой, MVC, Angular и так далее. Выберите пустой, чтобы не было ничего сгенерировано для нас, а только пустой проект. Сверху окна будет выпадающий список, в котором можно будет выбрать версию .NET.

В мак версии VS после выбора ASP .NET Core Web App весь второй шаг мастера посвязен выбору версии. Третий шаг – это настройки:

Здесь у нас имя проекта и имя решения. В случае с Web очень часто выбирают одно и то же – название сайта. Нужно так же указать путь, где будут сгенерированы файлы и если вы знаете, что такое git, то можно включить и его.

git – это система управления исходными кодами. Хотя у Microsoft есть своя система TFS, они везде стали поддерживать бесплатный и открытый git. О нем вы можете почитать в моей статье https://www.flenov.info/story/show/git---sovremennoe-upravlenie-kodom

В правой части окна можно увидеть, какие файлы будут созданы. Давайте нажмем кнопку Create и посмотрим на результат.

У меня вдоль левой кромки окна распложена панель Solution Explorer – это где вы будете управлять файлами. В Windows это окно по умолчанию растянуто вдоль правой кромки.

В корне нашего дерева находиться имя решения - MyWebSite. Сразу под ним идет имя проекта MyWebSite. Самое интересное находится в проекте. У него несколько подразделов:

Dependencies - зависимости. Здесь будут библиотеки, которые необходимы для работы приложения. Visual Studio и .NET Core по умолчанию используют менеджер пакетов NuGet. Сразу после создания проекта этот менеджер пакетов полезет в сеть и скачает все необходимое. У меня пустой проект, поэтому ничего пока особого нет, а по умолчанию есть только одна зависимость Microsoft.AspNetCore.App 2.1.1

Pages - страницы. Здесь для нас уже сгенерировали несколько файлов с HTML и C# кодом.

Properties - здесь находиться файл настроек launchSettings.json

wwwroot - в этой папке вы можете располагать файлы, которые должны быть доступны посетителям сайта. В основном это будет статичный контент, такой как JavaScript, CSS, картинки и другие файлы.

Так как VS уже сгенерировала для нас немного файлов, то можно запустить сайт и посмотреть на результат. Для этого в меню Run выбираем один из вариантов – Start Debugging или Start Without Debugging. Первый позволяет отлаживать код, а второй просто запускает сайт без возможности отлаживать.

Обратите внимание на строку URL - https://localhost:5001. Эта страница загружена с вашего локального хота (localhost) и использовался порт 5001.

Посмотрим, как в это время изменилось окно Visual Studio – здесь появились новые панели, которые позволяют отлаживать код (если вы запустили сайт с отладкой) и возможность в панели инструментов появились новые кнопки для отладки.

Чтобы остановить работу сайта можно нажать на панели инструментов кнопку с квадратиком (символизирует стоп) или выбрать Stop из меню Run

Снова вернемся к структуре проекта, который сгенерировала для нас среда разработки. Вы можете перейти в папку, где VS создал для нас файлы и убедиться, что все они там присутствуют. Чтобы проще было найти место, где находятся файлы, щелкните правой кнопкой по имени проекта и выберите в контекстном мену Reveal in finder (в Windows кажется это будет Open Folder in File Explorer).

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

Когда я работал на Sony, то в 2009-м году мы такое автоматическое добавление файлов в проект реализовывали самостоятельно через сторонние утилиты для сборки проектов, а теперь MS решила пойти этим же путем и это правильно.

Давайте остановим сайт и немного подчистим. Удалите все файлы из папки Page, но сделайте это не в VS, а в файловом менеджере. Мы не будем пользоваться благом мастера, а все будем начинать изучать с самого начала. Обратите внимание, что все файлы из папки Page в VS тоже исчезли. Среда разработки обновила состав проекта в соответствии с тем, что найдено в файловой системе. У меня в версии под mac Page вообще исчезла.

Теперь попробуйте скопировать в файловой системе какой-нибудь файл и он автоматически появится в составе проекта. Это нереально удобно и я рад, что MS наконец сделали это.

Посмотрим, из чего же состоит файл проекта. Это должен быть csproj файл, в моем случае это MyWebSite.csproj:

  
<Project> 
 <PropertyGroup> 
    <TargetFramework>net5.0</TargetFramework>
 </PropertyGroup> 
</Project> 

Хотя Microsoft все больше переходит на использование JSON файлов в качестве конфигурации, файл проекта все еще остался XML файлом, скорей всего для совместимости с предыдущими версиями их среды разработки.

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

Здесь у нас всего лишь указывается, какой должен использоваться SDK (Microsoft.NET.Sdk.Web), для какой версии Framework нужно компилировать код (netcoreapp2.1) и ссылки на пакеты, которые будут предоставлять дополнительные возможности.

Ссылки на пакеты это тэги PackageReference. В моем файле есть только одна ссылка на Microsoft.AspNetCore.App и именно этот файл мы видим в VS в папке Dependencies. Новые пакеты можно добавлять как с помощью среды разработки, так и добавлением ручками прямо в файл csproj. Среда разработки отслеживает изменения файла проекта и если вы что-то меняете, она тут же реагирует и обновляется в соответствии с изменениями.

В файле проекта может быть так же подключение директорий, например вот так:

   < ItemGroup>
    < Folder Include="Model/"/>
  < /ItemGroup>

Здесь явно подключается директория Model. Теперь любые файлы, которые вы будете копировать в эту папку, будут автоматически становиться частью проекта.

Теперь переходим к рассмотрению cs файлов, которые остались в корне проекта. Первый из них это Program.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

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

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

Я надеюсь у вас уже есть опыт работы с C#, иначе книга может быть немного сложной для восприятия, хотя я и пытаюсь все раскладывать по полочкам. И если опыт есть, то вы подобную структуру файла должны были видеть в консольных приложениях. Здесь у нас статичный метод Main, который выполняется при запуске консольных приложений и Web сайт тоже можно запустить с помощью специального движка из консоли, поэтому схожая архитектура имеет смысл.

Сделаем паузу и посмотрим, как запустить сайт из командной строки даже без использования IIS. Запускаю терминал и нужно убедится, что я нахожусь в папке проекта. Если нет, то нужно в нее перейти:

Mikhails-MacBook-Pro:MyWebSite mikhailflenov$ pwd
/Users/mikhailflenov/Projects/MyWebSite/MyWebSite

Теперь выполняем команду dotnet run:

Mikhails-MacBook-Pro:MyWebSite mikhailflenov$ dotnet run
Using launch settings from /Users/mikhailflenov/Projects/MyWebSite/MyWebSite/Properties/launchSettings.json...
: Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager[0]
      User profile is available. Using '/Users/mikhailflenov/.aspnet/DataProtection-Keys' as key repository; keys will not be encrypted at rest.
Hosting environment: Development
Content root path: /Users/mikhailflenov/Projects/MyWebSite/MyWebSite
Now listening on: https://localhost:5001
Now listening on: http://localhost:5000
Application started. Press Ctrl+C to shut down.
 

Как видите, все работает как в привычной консоли и поэтому схожая структура основного файла Program оправдана.

В методе Main вызывается один метод - CreateWebHostBuilder, который создает WebHost (вызов WebHost.CreateDefaultBuilder из состава Microsoft.AspNetCore.Hosting) и запускает его на выполнение.

Теперь у нас есть Web Host, который начал ожидать HTTP и HTTPS соединения.

Теперь посмотрим на Startup.cs. Даже если вы создавали пустой мастер, у вас скорей всего в этом файле уже есть немного дополнительных фишек, которые нам не нужны. Я начну сначала и в своем файле я убрал совершенно все, что пока не нужно и оставил минимум:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace MyWebSite
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
            });
        }
    }
}

Итак, у меня остался конструктор, который получает в качестве параметра IServiceCollection, через который мы можем работать с конфигурацией. Если вы знаете паттерн Dependency Injection – это как раз он. В .NET Core используют паттерны очень даже хорошо, особенно в MS полюбили Инъекцию, которая поддерживается из коробки и используется оттуда же.

Метод ConfigureServices я оставил, но не использую пока, о нем мы поговорим позже.

Единственное, что я реально использую – это метод Configure в котором и происходит вся логика сайта. Сначала проверяем, если мы работаем в режиме разработки, то любые ошибки будут показываться в подробном виде.

if (env.IsDevelopment())
{
  app.UseDeveloperExceptionPage();
}

Ну и запуск метода, который будет выполняться в ответ на любой входящий запрос:

app.UseEndpoints(endpoints =>
{
   endpoints.MapGet("/", async context =>
   {
      await context.Response.WriteAsync("Hello World!");
   });
});

До пятой пятой версии этот код выглядел так:

app.Run(async (context) =>
{
 await context.Response.WriteAsync("Hello from .NET Core");
});

Так что если вы увидите где-то этот код, то не пугайтесь, это просто старый подход. Раньше мы запускали приложение app.Run, а сейчас настраиваем точки входа для приложения app.UseEndpoints. И в принципе это имеет смысл, ведь Web сайт - это не просто приложение, это множество различных URL, которые выполняют различные действия. И вот каждый URL может быть отдельной точкой входа и с помощью UseEndpoints мы можем сразу же настраивать все в более удобном виде.

Этот код говорит, что нужно записать в результат Response строку. Контекст context – это специальная переменная, типа HttpContext, через которую мы можем получить информацию о запросе, который направил пользователь и через свойство Response мы можем записать ответ, который будет отправлен пользователю.

Теперь если запустить приложение, то оно будет писать на с странице указаную строку. Какой бы запрос вы не отправили серверу, он будет всегда отвечать одно и то же.

Это наверно самый минимальный код, который можно использовать для запуска собственного сайта. Можно уще правда убрать конфигурирование ошибки... Ну ладно, не самый минимальный, можно его еще немного ужать. Но главное, что он минимально прост и мы создали с помощью .NET Core первое Hello World приложение.

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне