Добро пожаловать в мир .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-В контроллере вы можете использовать сообщения журнала ILogger
to:
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.
К преимуществам модульного тестирования относятся:
- Улучшенное качество кода: помогает выявлять и исправлять ошибки на ранних этапах процесса разработки, прежде чем они станут более сложными и дорогостоящими для исправления. Это приводит к более качественному коду, более надежному и менее подверженному ошибкам.
- Повышенная уверенность в изменениях кода: обеспечивает систему безопасности, которая гарантирует, что изменения в коде не нарушат существующие функции. Это повышает уверенность разработчиков в необходимости внесения изменений в легенду, зная, что модульные тесты выявят любые проблемы.
- Улучшенный дизайн и удобство сопровождения. Благодаря этому код разработан так, чтобы его было легко тестировать. Это часто приводит к лучшему общему дизайну и архитектуре кода, что делает его более удобным для сопровождения в долгосрочной перспективе.
- Быстрая разработка. Помогает автоматизировать процесс тестирования и снижает потребность в ручном тестировании. Это означает, что разработчики могут работать более эффективно, зная, что код тестируется автоматически.
- Простота отладки: это упрощает выявление проблемы в случае сбоя теста, поскольку он фокусируется на определенной единице кода. Это делает отладку более быстрой и эффективной.
- Улучшение совместной работы и коммуникации. Сделайте процесс разработки более прозрачным и совместным. Когда разработчики пишут модульные тесты, они эффективно документируют предполагаемое поведение кода, что помогает улучшить общение и сотрудничество между членами команды.
- Улучшенная документация: она может служить формой документации для кода, предоставляя информацию о том, как код должен вести себя и как он предназначен для использования.
- Большая масштабируемость: это помогает выявлять и устранять проблемы на ранней стадии, прежде чем они станут более сложными и дорогостоящими. Это помогает гарантировать, что код станет более масштабируемым и сможет справиться с растущим числом пользователей или изменениями.
- Повышение производительности. Выявляйте узкие места на ранней стадии и повышайте производительность кода.
- Повышение качества продукта. Улучшите качество продукта и убедитесь, что он соответствует требованиям клиентов.
Если вы нашли эту статью полезной, похлопайте ей в ладоши.
Отказ от ответственности: часть этой статьи была написана с помощью инструмента искусственного интеллекта.
Но автор просмотрел и отредактировал содержимое.