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

1: В чем разница между .NET и .NET Core?

ASP.NET — это зрелая платформа, которая существует уже более десяти лет. Он построен на .NET Framework и работает в Windows. С другой стороны, ASP.NET Core — это более новая и более модульная версия ASP.NET. Он построен на среде выполнения .NET Core и может работать в Windows, Linux и macOS.

Одно из основных различий между ними заключается в том, что ASP.NET Core легче и эффективнее, чем ASP.NET. Он также занимает меньше места и оптимизирован для облачных сред. Кроме того, ASP.NET Core поддерживает современные веб-стандарты и технологии, такие как WebSockets, HTTP/2 и последние версии C#.

Вот пример кода, демонстрирующий одно различие между двумя фреймворками:

//ASP.NET
var server = new HttpServer(new HttpConfiguration());
server.OpenAsync().Wait();
Console.WriteLine("ASP.NET Server running...");

//ASP.NET Core
var host = new WebHostBuilder()
    .UseKestrel()
    .UseStartup<Startup>()
    .Build();

host.Run();
Console.WriteLine("ASP.NET Core Server running...");

2: Для чего нужен класс Startup/Program?

Класс Startup и Program служат точкой входа для приложения ASP.NET Core. Startup — это место, где вы настраиваете службы приложения и конвейер запросов. Program — это место, где вы создаете и запускаете веб-хост для приложения.

Startup обычно содержит два метода: ConfigureServices и Configure. ConfigureServices — это место, где вы регистрируете службы приложения, такие как внедрение зависимостей, ведение журнала и службы базы данных. В Configure вы определяете конвейер промежуточного программного обеспечения, который обрабатывает входящие запросы и отправляет ответы.

Program обычно содержит Main, который создает и запускает веб-хост. Этот метод создает экземпляр WebHostBuilder , устанавливает класс запуска и запускает хост.

Вот пример простых классов Startup и Program с использованием .NET 5:

// Startup.cs
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Register services
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // Configure the request pipeline
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGet("/", async context =>
            {
                await context.Response.WriteAsync("Hello, ASP.NET Core!");
            });
        });
    }
}

// Program.cs
public class Program
{
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseStartup<Startup>()
            .Build();

        host.Run();
    }
}

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

3: Как добавить настройки (пара ключ-значение)?

Один из способов добавить параметры конфигурации (пары «ключ-значение») в приложение ASP.NET Core — использовать файл IConfiguration . Служба IConfiguration позволяет вам получать доступ к данным конфигурации из различных источников, таких как файлы JSON, переменные среды и аргументы командной строки.

Вот пример того, как вы можете добавить параметры конфигурации с помощью IConfiguration:

1-В Startup добавьте конструктор, который принимает параметр IConfiguration:

    public class Startup
    {
        private readonly IConfiguration _config;

        public Startup(IConfiguration config)
        {
            _config = config;
        }

2-В ConfigureServices зарегистрируйте IConfiguration:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddSingleton(_config);
    }

3-В Program добавьте файлы конфигурации в WebHostBuilder:

    public class Program
    {
        public static void Main(string[] args)
        {
            var host = new HostBuilder()
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                    webBuilder.UseKestrel();
                    webBuilder.ConfigureAppConfiguration((hostingContext, config) =>
                    {
                        config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
                    });
                })
                .Build();

            host.Run();
        }
    }

Конструктор Startup принимает параметр IConfiguration, который позволяет классу получить доступ к данным конфигурации. Затем IConfiguration регистрируется в ConfigureServices, чтобы его можно было внедрить в другие части приложения.

В Program WebHostBuilder настроен на добавление файла JSON с именем appsettings.json в качестве источника конфигурации, но вы также можете добавить другие источники, такие как переменные среды или аргументы командной строки.

После того, как вы настроили конфигурацию, вы можете получить доступ к значениям, используя IConfiguration, например:

    var mySetting = _config["MySetting"];

4: Как реализовать кэширование?

Этого можно добиться с помощью IMemoryCache . Он предоставляет кэш в памяти, в котором могут храниться часто используемые данные, что сокращает время, необходимое для их извлечения из более медленного источника.

Вот пример реализации кэширования в приложении ASP.NET Core:

1-В Startup добавьте IMemoryCache в ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddMemoryCache();
    }

2-В контроллере вы можете использовать их IMemoryCache для кэширования данных

    public class MyController : Controller
    {
        private readonly IMemoryCache _cache;

        public MyController(IMemoryCache cache)
        {
            _cache = cache;
        }

        [HttpGet("data")]
        public IActionResult GetData()
        {
            // Try to get the data from the cache
            if (!_cache.TryGetValue("MyData", out List<MyData> data))
            {
                // If the data is not in the cache, retrieve it from the data source
                data = GetDataFromDataSource();

                // Set the cache options
                var cacheEntryOptions = new MemoryCacheEntryOptions()
                    .SetSlidingExpiration(TimeSpan.FromSeconds(30));

                // Save the data in the cache
                _cache.Set("MyData", data, cacheEntryOptions);
            }

            return Ok(data);
        }
    }

В этом примере IMemoryCache добавляется к ConfigureServices, чтобы его можно было внедрить в контроллер. В GetData код сначала пытается получить данные из кеша, используя TryGetValue. Если данных нет в кеше, код извлекает их из источника данных и сохраняет в кеше, используя функцию Set.

Вы также можете установить скользящее время истечения срока действия для данных кеша, чтобы они автоматически удалялись из кеша по истечении определенного периода.

5: Как реализовать ведение журнала?

Этого можно добиться с помощью ILogger. встроенной службы ведения журналов, которая может регистрировать сообщения в различные места назначения, такие как консоль, файл или база данных.

Вот пример того, как вы можете реализовать ведение журнала в приложении ASP.NET Core:

1-В Startup добавьте ILogger в ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddLogging(loggingBuilder =>
        {
            loggingBuilder.AddConsole();
            loggingBuilder.AddDebug();
        });
    }

2-В контроллере вы можете использовать сообщения журнала ILoggerto:

    public class MyController : Controller
    {
        private readonly ILogger<MyController> _logger;

        public MyController(ILogger<MyController> logger)
        {
            _logger = logger;
        }

        [HttpGet("data")]
        public IActionResult GetData()
        {
            _logger.LogInformation("Retrieving data from the data source");
            var data = GetDataFromDataSource();
            _logger.LogInformation("Data retrieved successfully");
            return Ok(data);
        }
    }

В этом примере ILoggerдобавляется к ConfigureServices, чтобы его можно было внедрить в контроллер. В методе действия GetData код использует LogInformation для регистрации сообщений о получении данных из источника данных.

Вы также можете использовать другие уровни ведения журнала, такие как LogDebug, LogError, LogWarning..

  • LogDebug Используется для тех данных, которые полезны только во время разработки, например для получения подробной информации о внутренней работе приложения.
  • LogError Используется, чтобы указать, что произошла ошибка. Эти сообщения обычно используются для отслеживания и устранения проблем с приложением.
  • LogWarning Он используется для обозначения потенциальной проблемы, которую необходимо исследовать. Эти сообщения обычно используются для отслеживания и устранения проблем с приложением.
  • LogInformation Используется для сообщений, предоставляющих общую информацию о поведении приложения. Эти сообщения обычно используются для отслеживания и устранения проблем с приложением, а также для мониторинга общего состояния приложения.

6: Как реализовать подпрограммы?

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

Одним из популярных способов является использование файла IHostedService. Это служба, которая работает в фоновом режиме и может использоваться для выполнения фоновых задач.

Вот пример того, как вы можете реализовать запланированное задание с помощью IHostedService:

1-Создайте новый класс, который реализует IHostedService и переопределяет методы StartAsync и StopAsync:

    public class MyBackgroundService : IHostedService
    {
        private readonly ILogger<MyBackgroundService> _logger;
        private Timer _timer;

        public MyBackgroundService(ILogger<MyBackgroundService> logger)
        {
            _logger = logger;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("MyBackgroundService starting.");

            _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));

            return Task.CompletedTask;
        }

        private void DoWork(object state)
        {
            _logger.LogInformation("MyBackgroundService is working.");
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            _logger.LogInformation("MyBackgroundService is stopping.");

            _timer?.Change(Timeout.Infinite, 0);

            return Task.CompletedTask;
        }
    }

2-В Startup добавьте IHostedService в ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddHostedService<MyBackgroundService>();
    }

В этом примере MyBackgroundService реализует IHostedService и использует таймер для выполнения задачи каждые 5 секунд. StartAsync запускает таймер, а StopAsync останавливает таймер.

Вы также можете использовать сторонние библиотеки, такие как Hangfire или Quartz.Net, чтобы помочь с запланированными заданиями.

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

7: Как реализовать внедрение зависимостей и в чем разница между Transient, Scoped и Singleton?

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

Вот пример того, как реализовать внедрение зависимостей в приложении ASP.NET Core:

1 — Создайте интерфейс для службы, которую вы хотите внедрить:

    public interface IMyService
    {
        void DoSomething();
    }

2 — Создайте класс, реализующий интерфейс:

    public class MyService : IMyService
    {
        public void DoSomething()
        {
            // Do something here
        }
    }

3 — В Startup добавить услугу в ConfigureServices:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
        services.AddTransient<IMyService, MyService>();
    }

В этом примере AddTransient используется для регистрации службы, которая указывает контейнеру DI создавать новый экземпляр службы каждый раз, когда он запрашивается.

В ASP.NET Core доступны три варианта жизненного цикла:

  • Transient: каждый раз при запросе службы создается новый экземпляр.
  • Scoped: Новый экземпляр создается один раз для каждого запроса.
  • Singleton: создается один экземпляр на все время существования приложения.

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

8: Какие коды ответов HTTP и когда использовать в REST API?

В API REST коды ответов HTTP используются для указания статуса запроса. Вот некоторые из наиболее распространенных кодов ответов HTTP и когда их использовать:

  • 200 OK: указывает, что запрос выполнен успешно. Это наиболее распространенный код ответа, и его следует использовать, когда запрос возвращает успешный результат.
  • 201 Created: указывает, что новый ресурс был создан по запросу. Это следует использовать, когда запрос создает новый ресурс, например новую учетную запись пользователя.
  • 204 No Content: указывает, что запрос был выполнен успешно, но нет содержимого для возврата. Это следует использовать, когда запрос обновляет ресурс, но в ответе нет содержимого для возврата.
  • 400 Bad Request: указывает, что запрос недействителен. Это следует использовать, когда клиент отправляет запрос с недопустимыми параметрами или отсутствующим обязательным полем.
  • 401 Unauthorized: указывает, что запрос требует аутентификации. Это следует использовать, когда клиент пытается получить доступ к защищенному ресурсу без предоставления действительных учетных данных для аутентификации.
  • 403 Forbidden: указывает, что у клиента нет необходимых разрешений для доступа к ресурсу. Это следует использовать, когда клиенты пытаются получить доступ к ресурсу, к которому у них нет прав доступа.
  • 404 Not Found: указывает, что запрошенный ресурс не найден. Это следует использовать, когда клиент запрашивает несуществующий ресурс.
  • 500 Internal Server Error: Это указывает на то, что на сервере произошла ошибка. Это следует использовать, когда на сервере возникает непредвиденная ошибка, например, ошибка подключения к базе данных.

Очень важно использовать соответствующие коды ответа HTTP в API REST, чтобы предоставить клиенту четкую и содержательную обратную связь.

9: Как реализовать проверку?

ASP.NET Core предоставляет встроенную поддержку проверки модели, что упрощает ее реализацию в вашем приложении. Вот пример того, как реализовать проверку в контроллере ASP.NET Core:

1. Создайте класс POCO (обычный старый объект CLR), который представляет данные запроса, и определите правила проверки с помощью аннотаций данных:

    public class CreateProductRequest
    {
        [Required]
        [StringLength(50, MinimumLength = 3)]
        public string Name { get; set; }

        [Range(1, 100)]
        public decimal Price { get; set; }
    }

2-В действии контроллера используйте ModelState, чтобы проверить правильность запрошенных данных:

    [HttpPost]
    public IActionResult CreateProduct([FromBody] CreateProductRequest request)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        // Create the product
        var product = new Product
        {
            Name = request.Name,
            Price = request.Price
        };

        return CreatedAtAction(nameof(GetProduct), new { id = product.Id }, product);
    }

В этом примере мы используем атрибут Required, чтобы указать, что Name требуется, и StringLength, чтобы указать, что Name должен иметь минимальную длину 3 и максимальную длину 50. Точно так же мы используем Range, чтобы указать, что Price должно быть от 1 до 100.

В случае неверных данных ModelState.IsValid будет ложным, и контроллер вернет BadRequest с ModelState, содержащим сообщения об ошибках.

Важно отметить, что проверка также может быть реализована на стороне клиента. Тем не менее, также важно проверить его на стороне сервера, чтобы защитить API и избежать вредоносных запросов.

Другой способ создать валидацию — использовать HTTP Filter.

Вот как выполнить дополнительную логику до или после выполнения действия контроллера в ASP.NET Core. Например, одним из вариантов повседневного использования фильтров является реализация логики проверки, применяемой к нескольким контроллерам или действиям.

Вот пример того, как создать фильтр HTTP для проверки того, что запрос содержит действительный ключ API:

1-Создайте новый класс, наследуемый от ActionFilterAttribute:

    public class ValidateApiKeyAttribute : ActionFilterAttribute
    {
        private readonly string _apiKey;

        public ValidateApiKeyAttribute(string apiKey)
        {
            _apiKey = apiKey;
        }
    }

2-Переопределите метод OnActionExecuting для выполнения проверки:

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        if (!context.HttpContext.Request.Headers.TryGetValue("ApiKey", out var apiKey) ||
            apiKey != _apiKey)
        {
            context.Result = new UnauthorizedResult();
        }
    }

3-Примените фильтр к контроллерам или действиям, которые вы хотите защитить:

    [ValidateApiKey("secret-key")]
    public class ProductsController : Controller
    {
        // ...
    }

В этом примере мы создали ValidateApiKeyAttribute, который наследуется от ActionFilterAttribute. Класс принимает ключ API в качестве параметра конструктора и проверяет, соответствует ли ему заголовок ApiKey в запросе. Если он не подходит, фильтр устанавливает Result из ActionExecutingContext на UnauthorizedResult, который возвращает 401 Unauthorized клиенту.

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

10: Как реализовать модульные тесты и в чем преимущества?

Модульное тестирование — это метод тестирования программного обеспечения, при котором отдельные модули или компоненты программного приложения тестируются изолированно. В ASP.NET Core модульные тесты могут быть написаны с использованием различных платформ тестирования, таких как MSTest, xUnit и NUnit.

Чтобы реализовать модульные тесты в приложении ASP.NET Core, используйте встроенный шаблон тестового проекта в Visual Studio или средство запуска тестов .NET, например dotnet test.

Вот пример написания модульного теста с использованием xUnit для простого класса калькулятора:

1-Создайте новый тестовый проект и укажите ссылку на проект, который хотите протестировать. Вам также потребуется установить пакет xUnit NuGet.

2-Создайте новый тестовый класс и добавьте атрибут [Fact] к методу, который хотите протестировать.

    public class CalculatorTests
    {
        [Fact]
        public void Add_ShouldReturnSumOfTwoNumbers()
        {
            // Arrange
            var calculator = new Calculator();

            // Act
            var result = calculator.Add(1, 2);

            // Assert
            Assert.Equal(3, result);
        }
    }

В этом примере мы создали тестовый класс с именем CalculatorTests и тестовый метод с именем Add_ShouldReturnSumOfTwoNumbers. Внутри этого метода мы устраиваем проверку, создавая новый экземпляр калькулятора, а затем действуем, вызывая метод Add и передавая 1 и 2 в качестве аргументов. Наконец, мы утверждаем, что результат Add равен 3.

К преимуществам модульного тестирования относятся:

  1. Улучшенное качество кода: помогает выявлять и исправлять ошибки на ранних этапах процесса разработки, прежде чем они станут более сложными и дорогостоящими для исправления. Это приводит к более качественному коду, более надежному и менее подверженному ошибкам.
  2. Повышенная уверенность в изменениях кода: обеспечивает систему безопасности, которая гарантирует, что изменения в коде не нарушат существующие функции. Это повышает уверенность разработчиков в необходимости внесения изменений в легенду, зная, что модульные тесты выявят любые проблемы.
  3. Улучшенный дизайн и удобство сопровождения. Благодаря этому код разработан так, чтобы его было легко тестировать. Это часто приводит к лучшему общему дизайну и архитектуре кода, что делает его более удобным для сопровождения в долгосрочной перспективе.
  4. Быстрая разработка. Помогает автоматизировать процесс тестирования и снижает потребность в ручном тестировании. Это означает, что разработчики могут работать более эффективно, зная, что код тестируется автоматически.
  5. Простота отладки: это упрощает выявление проблемы в случае сбоя теста, поскольку он фокусируется на определенной единице кода. Это делает отладку более быстрой и эффективной.
  6. Улучшение совместной работы и коммуникации. Сделайте процесс разработки более прозрачным и совместным. Когда разработчики пишут модульные тесты, они эффективно документируют предполагаемое поведение кода, что помогает улучшить общение и сотрудничество между членами команды.
  7. Улучшенная документация: она может служить формой документации для кода, предоставляя информацию о том, как код должен вести себя и как он предназначен для использования.
  8. Большая масштабируемость: это помогает выявлять и устранять проблемы на ранней стадии, прежде чем они станут более сложными и дорогостоящими. Это помогает гарантировать, что код станет более масштабируемым и сможет справиться с растущим числом пользователей или изменениями.
  9. Повышение производительности. Выявляйте узкие места на ранней стадии и повышайте производительность кода.
  10. Повышение качества продукта. Улучшите качество продукта и убедитесь, что он соответствует требованиям клиентов.

Если вы нашли эту статью полезной, похлопайте ей в ладоши.

Отказ от ответственности: часть этой статьи была написана с помощью инструмента искусственного интеллекта.
Но автор просмотрел и отредактировал содержимое.