Search test library by skills or roles
⌘ K
.NET Core interview questions for freshers
1. What is .NET Core, and why should we use it instead of older .NET Framework?
2. Can you explain the difference between .NET Core and .NET Standard?
3. What are the key benefits of using .NET Core for building applications?
4. What's the role of the .NET CLI (Command Line Interface), and what are some common commands you'd use?
5. Explain what a 'cross-platform' application is, and how .NET Core enables it.
6. What is a NuGet package, and why are they important in .NET Core development?
7. How do you create a new .NET Core project using the command line?
8. What is the purpose of the 'Program.cs' file in a .NET Core console application?
9. What's the difference between 'build' and 'run' commands in .NET Core?
10. How can you add a NuGet package to your .NET Core project?
11. What is the purpose of the 'csproj' file in a .NET Core project?
12. Explain what environment variables are and how they are used in .NET Core applications.
13. How do you handle configuration settings in a .NET Core application (e.g., connection strings)?
14. What is dependency injection (DI), and why is it used in .NET Core?
15. How do you register services for dependency injection in .NET Core?
16. Can you explain the concept of middleware in .NET Core, especially within ASP.NET Core?
17. What are some common middleware components used in ASP.NET Core applications?
18. How do you create a simple API endpoint in ASP.NET Core?
19. What are HTTP request methods (like GET, POST, PUT, DELETE), and how are they used in APIs?
20. How do you handle different HTTP status codes in your API responses?
21. What is JSON, and why is it commonly used in APIs?
22. How do you serialize and deserialize JSON data in .NET Core?
23. What is exception handling, and how do you implement it in .NET Core?
24. How do you write unit tests for your .NET Core code?
25. What are some common unit testing frameworks used with .NET Core (e.g., xUnit, NUnit)?
26. What is source control, and why is it important when working on .NET Core projects?
27. Explain the basic Git commands like 'clone', 'commit', 'push', and 'pull'.
28. How would you debug a .NET Core application running in a Docker container?
29. What are some of the key differences between .NET Core and .NET 5/6/7/8?
.NET Core interview questions for juniors
1. What is .NET Core, and why is it special compared to the older .NET Framework?
2. Can you explain what a 'namespace' is in C# and why we use them?
3. What's the difference between 'int' and 'string' in C#, and when would you use each?
4. Imagine you're explaining 'variables' to a friend. How would you describe what they are and what they do?
5. What is an 'if' statement, and how does it help your program make decisions?
6. What is a 'loop', and why is it useful when you want to do something many times?
7. Can you explain what an 'array' is and how it helps you store multiple things?
8. What is a 'method' in C#, and why do we use them to organize our code?
9. What does 'debugging' mean, and what's one simple way you can try to find mistakes in your code?
10. What is 'source control' (like Git), and why is it important for working on projects with others?
11. What is the difference between `Console.WriteLine()` and `Console.ReadLine()`?
12. Explain the difference between a class and an object in C#?
13. What is the purpose of using comments in code, and how can they help you and others?
14. What are some basic data types you know in C# other than `int` and `string`?
15. How do you create a simple 'Hello, World!' program in .NET Core?
16. Describe the difference between `public` and `private` access modifiers.
17. Can you describe what you understand about API's and how they can be used in .NET Core?
18. What is NuGet, and why is it important in .NET Core development?
19. How would you handle a simple error in a .NET Core application?
20. Explain what you know about testing in .NET Core (e.g., unit testing).
21. What are some benefits of using .NET Core for web development?
22. Describe what you understand about dependency injection in .NET Core.
23. What are environment variables and how might you use them in a .NET Core application?
24. If you had a list of numbers, how could you find the largest number using C#?
25. Explain what you know about LINQ and how it is useful.
26. What is JSON, and why is it used in .NET Core applications?
27. How does .NET Core handle different operating systems (like Windows, macOS, and Linux)?
28. What are some tools or IDEs (like Visual Studio Code) that you can use for .NET Core development?
29. Imagine your program isn't working as expected. Walk me through your process of fixing it.
.NET Core intermediate interview questions
1. How does .NET Core's dependency injection work, and why is it useful?
2. Explain the difference between `Task.Run` and `Task.Factory.StartNew` in .NET Core.
3. What are middleware components in ASP.NET Core, and how are they used in the request pipeline?
4. How does .NET Core handle configuration, and what are some common configuration sources?
5. Describe the purpose of Kestrel in ASP.NET Core.
6. How can you implement logging in a .NET Core application, and what are some best practices?
7. What is the role of the `dotnet` CLI, and what are some common commands?
8. Explain the difference between `ProjectReference`, `PackageReference`, and `ProjectReference` in a .NET Core project file.
9. How does .NET Core support cross-platform development, and what are some considerations?
10. What is the purpose of the `IConfiguration` interface, and how is it used?
11. Explain how you would implement exception handling in an ASP.NET Core application.
12. How can you secure a .NET Core web API?
13. What are Razor Pages in ASP.NET Core, and how do they differ from traditional MVC?
14. How does .NET Core handle memory management, and what are some common memory leaks?
15. Explain the concept of 'options pattern' in .NET Core.
16. How would you implement unit testing in a .NET Core project, and what are some common testing frameworks?
17. What is the purpose of the `IHttpClientFactory` interface in .NET Core?
18. How can you publish a .NET Core application to different platforms?
19. Describe the role of environment variables in a .NET Core application.
20. How do you implement caching in .NET Core to improve performance?
.NET Core interview questions for experienced
1. How does .NET Core's garbage collector handle large object heaps, and what strategies can you employ to minimize fragmentation in these heaps?
2. Describe the differences between `Task.Run` and `Task.Factory.StartNew` in .NET Core, focusing on their thread pool usage and potential performance implications.
3. Explain the concept of middleware in ASP.NET Core and how you would implement custom middleware to handle authentication or request logging.
4. How can you implement efficient caching strategies in .NET Core applications, considering both in-memory and distributed caching options?
5. Discuss the role of dependency injection in .NET Core and how it promotes loose coupling and testability in your applications.
6. Explain how to use health checks in ASP.NET Core to monitor the status of your application and its dependencies.
7. What are the benefits of using Kestrel as a web server in .NET Core, and when might you choose to use a reverse proxy like Nginx or IIS in front of it?
8. Describe how you would handle errors and exceptions in a .NET Core application, including global exception handling and logging strategies.
9. How can you secure a .NET Core API using JWT (JSON Web Tokens), and what are some best practices for storing and managing tokens?
10. Explain the concept of asynchronous programming in .NET Core using `async` and `await`, and how it improves the responsiveness of your applications.
11. Discuss the advantages of using gRPC over REST APIs in .NET Core, considering factors like performance, efficiency, and code generation.
12. How would you implement a message queue using .NET Core, and what are some popular message queue technologies you might consider (e.g., RabbitMQ, Kafka)?
13. Explain how to use the .NET Core CLI for building, testing, and deploying your applications, and what are some common CLI commands you use?
14. Describe the different hosting models available in ASP.NET Core (e.g., InProcess, OutOfProcess) and their implications on performance and deployment.
15. How do you optimize performance in .NET Core applications, specifically regarding memory allocation and CPU usage?
16. What are the various ways to configure a .NET Core application, and how do you manage environment-specific configurations?
17. How does the .NET Core runtime handle cross-platform compatibility, and what are some potential challenges when deploying to different operating systems?
18. What are Span<T> and Memory<T> in .NET Core, and what problems do they solve when dealing with memory management and data processing?
19. Describe the role of logging frameworks (e.g., Serilog, NLog) in .NET Core, and how you would configure structured logging in your applications.
20. How do you implement unit testing and integration testing in .NET Core, and what testing frameworks do you prefer (e.g., xUnit, NUnit)?
21. Explain the concept of minimal APIs in .NET 6+ and how they differ from traditional controller-based APIs.
22. Describe how you would implement background tasks in a .NET Core application, considering options like `IHostedService` and Hangfire.
23. How can you use reflection in .NET Core to dynamically inspect and manipulate types and members at runtime?
24. Discuss the various options for deploying .NET Core applications to cloud platforms like Azure and AWS.
25. How would you implement a CQRS (Command Query Responsibility Segregation) pattern in a .NET Core application?
26. Explain the purpose of the `ConfigureAwait(false)` method in asynchronous .NET Core code.
27. Describe the differences between authorization and authentication in ASP.NET Core and how to implement custom authorization policies.
28. How do you handle data migrations in .NET Core using Entity Framework Core?
29. What are the benefits of using source generators in .NET Core, and how can they improve performance and reduce boilerplate code?
30. Explain how to use OpenTelemetry in .NET Core for distributed tracing and monitoring.

108 .NET Core interview questions to hire top developers


Siddhartha Gunti Siddhartha Gunti

September 09, 2024


Hiring .NET Core developers can be challenging without the right questions to ask. Recruiters often struggle to gauge a candidate's proficiency in .NET Core, leading to mismatches and wasted resources, and a quick look at the skills required for .NET developer can quickly overwhelm you.

This blog post provides a curated list of .NET Core interview questions tailored for various experience levels, from freshers to experienced professionals. Additionally, you'll find a set of multiple-choice questions (MCQs) to further assess their understanding.

By using these questions, you'll be able to identify candidates with the right expertise and fit for your team; before the interview, you can further evaluate their knowledge using our C# .NET online test.

Table of contents

.NET Core interview questions for freshers
.NET Core interview questions for juniors
.NET Core intermediate interview questions
.NET Core interview questions for experienced
.NET Core MCQ
Which .NET Core skills should you evaluate during the interview phase?
3 Tips for Using .NET Core Interview Questions
Evaluate .NET Candidates with Precision: Skills Tests & Targeted Interview Questions
Download .NET Core interview questions template in multiple formats

.NET Core interview questions for freshers

1. What is .NET Core, and why should we use it instead of older .NET Framework?

.NET Core is a cross-platform, open-source, and modular framework for building modern applications. Unlike the older .NET Framework, which was primarily Windows-centric, .NET Core can run on Windows, macOS, and Linux.

Reasons to use .NET Core instead of .NET Framework include:

  • Cross-platform compatibility: Build applications that run on different operating systems without code changes.
  • Improved performance: .NET Core is generally faster and more efficient than .NET Framework.
  • Modularity: You only include the necessary components, reducing application size and dependencies.
  • Open-source: Benefit from community contributions and transparency. It is available on GitHub.
  • Modern architecture: Designed for modern development practices like microservices and containerization. For example, use this to define a controller:
    [ApiController]
    [Route("[controller]")]
    public class MyController : ControllerBase
    {
     [HttpGet]
     public ActionResult<string> Get()
      {
         return "Hello World!";
      }
    }
    

2. Can you explain the difference between .NET Core and .NET Standard?

.NET Standard is a specification of APIs that .NET implementations must provide. Think of it as a contract. .NET Standard allows you to write code that can run on different .NET platforms (e.g., .NET Framework, .NET Core, .NET 5+). It defines a common set of APIs that all compliant .NET implementations must support.

.NET Core (and later .NET 5, 6, 7, etc.) is a specific implementation of the .NET Standard. It's a runtime, libraries, and compiler. .NET Core (and newer .NET versions) can target a specific .NET Standard version, indicating which APIs it supports. Essentially, .NET Standard defines what APIs exist, while .NET Core/5+/etc. is how those APIs are implemented and executed.

3. What are the key benefits of using .NET Core for building applications?

The key benefits of using .NET Core (now .NET 6, 7, 8, etc.) include cross-platform compatibility, high performance, and a modular design. Cross-platform capabilities enable applications to run on Windows, macOS, and Linux, significantly broadening the deployment options.

Performance improvements are substantial due to optimizations in the CoreCLR runtime and ASP.NET Core framework. The modular design allows developers to include only the necessary components, resulting in smaller application sizes and improved security. It also offers features like built-in dependency injection, a modern configuration system and support for microservices architectures. Tools like dotnet publish -r <RID> allows for framework dependent deployments.

4. What's the role of the .NET CLI (Command Line Interface), and what are some common commands you'd use?

The .NET CLI (Command Line Interface) is a cross-platform toolchain for developing, building, running, and publishing .NET applications. It allows developers to perform these tasks from the command line, providing a consistent and automated way to manage .NET projects. It is particularly useful for scripting, automation, and continuous integration/continuous deployment (CI/CD) pipelines.

Some common .NET CLI commands include:

  • dotnet new: Creates a new .NET project or solution.
  • dotnet build: Builds a .NET project.
  • dotnet run: Runs a .NET application.
  • dotnet test: Executes unit tests.
  • dotnet publish: Publishes a .NET application for deployment.
  • dotnet add package: Adds a NuGet package to a project.
  • dotnet restore: Restores dependencies specified in the project file.
  • dotnet ef: Executes Entity Framework Core commands (e.g., migrations).
  • dotnet tool install: Installs a .NET tool.
  • dotnet --version: Displays the installed .NET SDK version.

5. Explain what a 'cross-platform' application is, and how .NET Core enables it.

A cross-platform application is software that can run on multiple operating systems (like Windows, macOS, and Linux) without requiring significant code changes. This contrasts with platform-specific applications, which are designed to run only on a single operating system.

.NET Core (now .NET) enables cross-platform development through its design and runtime environment. It is a modular and open-source framework that runs on different operating systems. The .NET runtime, along with platform-specific implementations, handles the execution of the application's intermediate language (IL) code. Key features enabling this include:

  • .NET Runtime: Provides a consistent execution environment across platforms.
  • Cross-Platform Libraries: Offers a set of libraries and APIs that work uniformly across different OS.
  • Framework Abstraction: Abstracts away platform-specific details, allowing developers to write code that interacts with the underlying OS through a common interface. This allows building and deploying the same code base on different operating systems. For example, you can write C# code using .NET libraries that interact with the file system, network, or UI elements, and this code will function on Windows, macOS, and Linux.

6. What is a NuGet package, and why are they important in .NET Core development?

A NuGet package is a single ZIP file with the .nupkg extension that contains compiled code (DLLs), related files like images and configuration, and a manifest file (a .nuspec file) that describes the package, its dependencies, and version information.

NuGet packages are crucial in .NET Core development because they provide a standardized way to distribute and consume reusable code. They simplify dependency management by allowing developers to easily add, update, and remove libraries from their projects, resolving dependencies automatically. This promotes code reuse, reduces development time, and ensures consistency across projects.

7. How do you create a new .NET Core project using the command line?

To create a new .NET Core project using the command line, you use the dotnet new command. This command requires you to specify a template for the type of project you want to create. Common templates include console, webapi, mvc, classlib, and razorclasslib. For example, to create a new console application named 'MyNewApp', you would run the following command:

dotnet new console -n MyNewApp

After executing this command, a new directory named MyNewApp will be created, containing the necessary files for a basic console application. You can then navigate into that directory (cd MyNewApp) and build/run the application using dotnet build and dotnet run respectively.

8. What is the purpose of the 'Program.cs' file in a .NET Core console application?

In a .NET Core console application, Program.cs serves as the entry point of the application. It contains the Main method, which is the first method that is executed when the application starts.

The Main method typically handles tasks such as:

  • Initializing resources.
  • Parsing command-line arguments.
  • Creating objects.
  • Calling other methods to perform the core logic of the application. Essentially, it's the starting point from where your application's code begins to execute.

9. What's the difference between 'build' and 'run' commands in .NET Core?

In .NET Core, build and run are distinct commands with different purposes.

dotnet build compiles your source code into intermediate language (IL) code and produces the necessary assemblies (DLLs and EXEs). It checks for syntax errors and ensures all dependencies are available. It essentially prepares your application for execution but doesn't actually execute it. dotnet run, on the other hand, combines the build process (if necessary or if changes have been made since the last build) with execution. It first builds the application and then immediately runs it. dotnet run is typically used for quick testing and development cycles. If you need to deploy, you need to build it and then copy the DLL files accordingly.

10. How can you add a NuGet package to your .NET Core project?

You can add a NuGet package to your .NET Core project using several methods:

  • NuGet Package Manager Console: Use the Install-Package command in the Package Manager Console within Visual Studio. For example, Install-Package Newtonsoft.Json.

  • NuGet Package Manager UI: Right-click on your project in Solution Explorer, select "Manage NuGet Packages...", and browse or search for the desired package. Then, click "Install".

  • .csproj file: Manually add a <PackageReference> element to your project's .csproj file within the <ItemGroup> element, and then restore the NuGet packages. For example:

    <ItemGroup>
        <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
    </ItemGroup>
    
  • dotnet CLI: Use the dotnet add package command in the command line. For instance, dotnet add package Newtonsoft.Json.

11. What is the purpose of the 'csproj' file in a .NET Core project?

The .csproj file in a .NET project (including .NET Core, .NET 5+, and .NET Framework) serves as the project file, defining the project's structure, dependencies, build configuration, and metadata. It essentially tells the .NET SDK how to build, package, and run the application or library. It uses an XML format, which has evolved over time to be more streamlined and readable, especially with the introduction of SDK-style projects.

Specifically, the .csproj file manages things like:

  • Dependencies: References to NuGet packages and other projects.
  • Source files: Lists of source code files to include in the project.
  • Target framework(s): Specifies the .NET runtime version(s) the project is targeting (e.g., net6.0, net7.0).
  • Build configuration: Defines build properties such as output type (console application, library), compiler options, and pre/post-build events.
  • Project metadata: Includes project name, version, description, and other information. For example, you can include this in the PropertyGroup tags:
<PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net7.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
</PropertyGroup>

12. Explain what environment variables are and how they are used in .NET Core applications.

Environment variables are name-value pairs that hold configuration information accessible to applications and processes running on a system. They define the environment in which these processes operate, allowing for customization without modifying the application's code directly. In .NET Core applications, environment variables are commonly used to store settings such as database connection strings, API keys, and application-specific configurations that might differ between development, testing, and production environments.

.NET Core applications access environment variables via the System.Environment class. For example, Environment.GetEnvironmentVariable("MY_VARIABLE") retrieves the value of the environment variable named 'MY_VARIABLE'. ASP.NET Core applications also leverage environment variables extensively, often using them in configuration files (appsettings.json) through configuration providers. These providers load settings from environment variables, command-line arguments, and other sources, allowing developers to easily manage application configurations across different environments. For instance, one can set an environment variable named ASPNETCORE_ENVIRONMENT to specify the environment (Development, Staging, Production) for ASP.NET Core to use.

13. How do you handle configuration settings in a .NET Core application (e.g., connection strings)?

In .NET Core, configuration settings are typically handled using the Microsoft.Extensions.Configuration package. We can use appsettings.json to store settings like connection strings and application-specific configurations. This file is loaded at startup using ConfigurationBuilder. Then we access the settings via the IConfiguration interface.

For example, to read a connection string:

var connectionString = Configuration.GetConnectionString("DefaultConnection");

We can also use environment variables to override settings in appsettings.json for different environments (Development, Staging, Production). We can then bind the configuration to strongly-typed classes using options pattern. Secrets like API keys can be stored in user secrets during development, or Azure Key Vault in production to avoid storing them directly in the code or configuration files.

14. What is dependency injection (DI), and why is it used in .NET Core?

Dependency Injection (DI) is a design pattern in which a class receives its dependencies from external sources rather than creating them itself. This promotes loose coupling and makes code more testable and maintainable. Essentially, dependencies are "injected" into a class.

In .NET Core, DI is a first-class citizen, built into the framework. It's used for several reasons:

  • Loose Coupling: Reduces dependencies between classes, allowing them to be changed independently.
  • Testability: Easier to mock or stub dependencies during unit testing.
  • Maintainability: Easier to change implementations without affecting dependent classes.
  • Reusability: Dependencies can be easily swapped with different implementations.
  • Configuration: Simplifies configuration of application components.

15. How do you register services for dependency injection in .NET Core?

In .NET Core, services are registered for dependency injection within the ConfigureServices method of the Startup.cs file (or in the Program.cs file for .NET 6+ minimal hosting model). This method takes an IServiceCollection as a parameter, which provides extension methods for registering services with different lifetimes. You can register services using methods like:

  • AddSingleton: Creates a single instance of the service for the lifetime of the application.
  • AddScoped: Creates a new instance of the service for each scope (typically an HTTP request).
  • AddTransient: Creates a new instance of the service every time it is requested.

For example:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IMyService, MyService>();
    services.AddScoped<IMyRepository, MyRepository>();
    services.AddSingleton<IConfiguration>(Configuration);
}

16. Can you explain the concept of middleware in .NET Core, especially within ASP.NET Core?

Middleware in ASP.NET Core forms a pipeline to handle HTTP requests. Each middleware component in the pipeline has the opportunity to process the request and response. Think of it like a series of filters that act on the HTTP request before it reaches your application's endpoint and then act on the response before it's sent back to the client.

Each middleware component can perform actions such as logging, authentication, authorization, routing, or modifying request/response headers. Middleware is configured in the Configure method of the Startup.cs file, and the order in which they are added to the pipeline is significant as it determines the order in which they are executed. For example:

app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllers();
});

17. What are some common middleware components used in ASP.NET Core applications?

ASP.NET Core middleware components form a pipeline to handle requests and responses. Some common middleware components include:

  • Authentication Middleware: Handles user authentication (e.g., using cookies, JWT). It verifies user credentials.
  • Routing Middleware: Matches incoming requests to specific endpoints (controllers and actions).
  • Static File Middleware: Serves static files like HTML, CSS, JavaScript, and images directly to the client. You configure the location of the static files.
  • Exception Handling Middleware: Catches and handles exceptions that occur during request processing. Provides a global error handling mechanism.
  • CORS Middleware: Enables Cross-Origin Resource Sharing, allowing requests from different domains.
  • Session Middleware: Manages user sessions by storing data on the server and associating it with a user's browser.
  • Response Compression Middleware: Compresses the HTTP response to reduce its size, improving performance.
  • Endpoint Routing Middleware: Configures endpoints (e.g., MVC controllers, Razor Pages, minimal APIs) for the application.

18. How do you create a simple API endpoint in ASP.NET Core?

To create a simple API endpoint in ASP.NET Core, you typically start by creating a new ASP.NET Core Web API project. Define a controller class (e.g., MyController) that inherits from ControllerBase. Within this controller, define action methods (e.g., Get) decorated with attributes like [HttpGet] and [Route("api/[controller]")] to specify the HTTP method and route. The action method returns data, often as JSON, using Ok(), BadRequest(), etc.

Here's a minimal example:

[ApiController]
[Route("api/[controller]")]
public class MyController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok(new { message = "Hello from API" });
    }
}

19. What are HTTP request methods (like GET, POST, PUT, DELETE), and how are they used in APIs?

HTTP request methods, also known as HTTP verbs, indicate the desired action to be performed on a resource. Common methods include:

  • GET: Retrieves data from a specified resource. It's read-only and should not have side effects.
  • POST: Submits data to be processed to a specified resource, often used to create new resources.
  • PUT: Replaces the current resource with the uploaded content. Requires knowing the full resource URL.
  • PATCH: Applies partial modifications to a resource. Useful for updating only specific fields.
  • DELETE: Deletes the specified resource.

In APIs, these methods define how clients interact with server-side resources. For example, a GET /users request might retrieve a list of users, while a POST /users request could create a new user. Using the correct method is crucial for building RESTful APIs, ensuring predictable and well-defined interactions. PUT and PATCH are often confused; PUT replaces the entire resource, while PATCH modifies parts of it.

20. How do you handle different HTTP status codes in your API responses?

I handle HTTP status codes by mapping them to appropriate actions in my application. Successful responses (2xx) trigger UI updates or data processing. Redirects (3xx) are handled automatically by the client or may prompt user interaction if needed. Client errors (4xx) trigger user-friendly error messages in the UI, along with logging for debugging. Server errors (5xx) display generic error messages to the user and trigger extensive logging and monitoring to identify and resolve the underlying issue.

Specifically:

  • 200 OK: Success, process data as expected.
  • 201 Created: Resource created, redirect or update UI.
  • 400 Bad Request: Display error message to the user, log details.
  • 401 Unauthorized: Redirect to login page or prompt for credentials.
  • 403 Forbidden: Display "access denied" message.
  • 404 Not Found: Display a user-friendly "resource not found" message.
  • 500 Internal Server Error: Display a generic error message, log error details to the server and monitoring system, and trigger alerts.

21. What is JSON, and why is it commonly used in APIs?

JSON (JavaScript Object Notation) is a lightweight, human-readable data-interchange format. It's used for transmitting data objects consisting of attribute-value pairs and array data types (or any other serializable value).

JSON is commonly used in APIs because it is:

  • Easy to parse: Most programming languages have built-in libraries to easily parse and generate JSON.
  • Lightweight: Compared to other formats like XML, JSON has less overhead, resulting in faster data transmission.
  • Human-readable: Its simple structure makes it easy to understand and debug.
  • Widely supported: JSON is supported by almost all modern platforms and technologies. For example, in JavaScript, converting a JavaScript object to JSON can be done using JSON.stringify(object) and converting JSON to a JavaScript object can be done using JSON.parse(jsonString).

22. How do you serialize and deserialize JSON data in .NET Core?

In .NET Core, you typically use the System.Text.Json namespace (or Newtonsoft.Json package) for JSON serialization and deserialization.

To serialize an object to JSON, use JsonSerializer.Serialize(). For example:

using System.Text.Json;

string jsonString = JsonSerializer.Serialize(myObject);

To deserialize JSON to an object, use JsonSerializer.Deserialize(). For example:

using System.Text.Json;

MyClass myObject = JsonSerializer.Deserialize<MyClass>(jsonString);

Newtonsoft.Json uses similar methods (JsonConvert.SerializeObject() and JsonConvert.DeserializeObject<T>()).

23. What is exception handling, and how do you implement it in .NET Core?

Exception handling is a mechanism to deal with runtime errors that may occur during the execution of a program. It allows you to gracefully handle unexpected situations, prevent program crashes, and potentially recover from errors.

In .NET Core, you implement exception handling using try-catch-finally blocks. The code that might throw an exception is placed inside the try block. If an exception occurs, the corresponding catch block is executed. You can have multiple catch blocks to handle different types of exceptions. The finally block is always executed, regardless of whether an exception was thrown or not, and is typically used to release resources. Here's an example:

try
{
    // Code that might throw an exception
    int result = 10 / 0;
}
catch (DivideByZeroException ex)
{
    // Handle the specific exception
    Console.WriteLine("Error: " + ex.Message);
}
catch (Exception ex)
{
    // Handle any other exceptions
    Console.WriteLine("An error occurred: " + ex.Message);
}
finally
{
    // Code to be executed regardless of exceptions
    Console.WriteLine("Finally block executed.");
}

24. How do you write unit tests for your .NET Core code?

I write unit tests for .NET Core code using frameworks like xUnit, NUnit, or MSTest, often alongside a mocking library like Moq or NSubstitute. The general process involves:

  • Creating a separate test project within the solution.
  • Referencing the project to be tested.
  • Writing test methods to exercise different aspects of the code, focusing on individual units (classes, methods).
  • Using Assert methods provided by the testing framework to verify expected outcomes. Mocking dependencies allows me to isolate the unit under test and control its inputs and outputs during testing. For example, using xUnit I would typically write a test method that calls a method under test. Then I use Assert.Equal() or other Assert methods to check if the result is the expected value. Often times, I will utilize arrange, act, assert phases within the test methods.

25. What are some common unit testing frameworks used with .NET Core (e.g., xUnit, NUnit)?

Several popular unit testing frameworks are commonly used with .NET Core. Two of the most prevalent are xUnit.net and NUnit. xUnit.net is known for its focus on extensibility and its attribute-driven approach. NUnit, on the other hand, is a more traditional framework with a rich set of assertions.

Other notable options include MSTest, which is the testing framework developed by Microsoft, and Shouldly, which is an assertion library that enhances readability. Using any of these frameworks involves installing the appropriate NuGet package and writing test methods marked with specific attributes (e.g., [Fact] in xUnit, [Test] in NUnit). For example, here's a basic xUnit example:

using Xunit;

public class MyTests
{
    [Fact]
    public void MyFirstTest()
    {
        Assert.Equal(4, 2 + 2);
    }
}

26. What is source control, and why is it important when working on .NET Core projects?

Source control (also known as version control) is a system that tracks changes to files over time. It's crucial for managing .NET Core projects, especially when working in teams, because it provides a central repository for the code, allowing multiple developers to work simultaneously without overwriting each other's changes. It also enables easy reverting to previous versions, branching for new features, and merging changes back into the main codebase.

Why is source control important? Consider these points:

  • Collaboration: Facilitates seamless teamwork.
  • Version History: Tracks all changes, allowing you to revert to any previous state.
  • Branching and Merging: Enables parallel development of features.
  • Backup and Recovery: Acts as a backup for your codebase.
  • Code Review: Supports code review processes before merging changes.

Tools like Git are commonly used with .NET Core projects, often integrated with platforms like GitHub, Azure DevOps, or GitLab.

27. Explain the basic Git commands like 'clone', 'commit', 'push', and 'pull'.

Git commands are fundamental for version control. git clone creates a local copy of a remote repository. For example, git clone https://github.com/user/repo.git downloads the repository to your machine.

git commit saves changes to your local repository. First, you'd stage changes with git add . or git add <file>. Then, git commit -m "Your commit message" creates a new commit with a descriptive message. git push uploads your local commits to a remote repository. For instance, git push origin main pushes the 'main' branch to the 'origin' remote. Finally, git pull downloads changes from a remote repository and merges them into your current branch. git pull origin main updates your local 'main' branch with the latest changes from the 'origin' remote.

28. How would you debug a .NET Core application running in a Docker container?

Debugging a .NET Core application running in a Docker container can be achieved in a few ways. One common method is to use Visual Studio's container tools. You can attach the Visual Studio debugger to the running container process. This requires ensuring the application is built with debug symbols and that the debugger is configured correctly within Visual Studio to connect to the container.

Another approach involves using the dotnet attach command-line tool. First, you'll need to find the process ID (PID) of the .NET application within the container. You can use docker exec to run ps -ef inside the container and identify the PID. Then, use dotnet attach <PID> from your host machine, targeting the container. Remember that your .NET runtime needs to be able to discover this newly attached debugger.

29. What are some of the key differences between .NET Core and .NET 5/6/7/8?

.NET Core was the initial cross-platform, open-source reimplementation of .NET Framework. .NET 5 (and subsequent versions like 6, 7, and 8) are continuations of .NET Core, but they represent the unified .NET platform. .NET 5 and later versions effectively replaced both .NET Framework and .NET Core.

The key differences are:

  • .NET Core is end-of-life (EOL). .NET 5+ is the supported version.
  • .NET 5+ unifies the platform. It aims to have a single base class library (BCL) and runtime for all workloads (desktop, web, mobile, cloud, etc.). .NET Core had some differences in supported workloads.
  • .NET 5+ includes performance improvements and new language features (from C# versions).
  • .NET 5+ uses a new versioning scheme. The jump from .NET Core 3.1 to .NET 5 signified this major change and the move away from the "Core" branding.

.NET Core interview questions for juniors

1. What is .NET Core, and why is it special compared to the older .NET Framework?

.NET Core (now just .NET) is a free, open-source, cross-platform framework for building various applications, including web, mobile, desktop, and cloud applications. Its cross-platform nature is a major distinction from the older .NET Framework, which was primarily Windows-centric. This allows .NET applications to run on Windows, macOS, and Linux.

Compared to the .NET Framework, .NET offers several key advantages:

  • Cross-platform: Runs on Windows, macOS, and Linux.
  • Modular: Enables you to include only the necessary packages for your application, reducing its size and improving performance.
  • Open-source: Benefits from community contributions and transparency.
  • Performance: Generally offers better performance than .NET Framework.
  • Modern: Embraces modern development practices and tooling.

2. Can you explain what a 'namespace' is in C# and why we use them?

In C#, a namespace is a way to organize code into logical groups and prevent naming conflicts. Think of it as a container for classes, interfaces, structs, enums, and other namespaces. Namespaces help you avoid situations where two different pieces of code define the same name, which would lead to compilation errors.

We use namespaces for several reasons:

  • Organization: Namespaces make it easier to find and understand related code.
  • Avoiding Naming Collisions: They allow you to use the same name for different types, as long as they are in different namespaces. For example, System.IO.File and MyProject.File can coexist without conflict.
  • Code Reusability: Namespaces allow you to package code into reusable components.
  • Controlling Scope: Namespaces control the scope of names.

3. What's the difference between 'int' and 'string' in C#, and when would you use each?

In C#, int and string represent different data types. int is a value type that stores integer numbers (e.g., -1, 0, 100). It's used for representing countable whole numbers. string is a reference type that represents a sequence of characters (e.g., "Hello", "World").

You would use int when you need to perform arithmetic operations, represent quantities, or use as indices. You'd use string when you need to store textual data, such as names, descriptions, or user input.

Examples:

  • int: int age = 30;, int count = 10;
  • string: string name = "Alice";, string message = "Hello, world!";

4. Imagine you're explaining 'variables' to a friend. How would you describe what they are and what they do?

Imagine a variable like a labeled container or a box. You can put information inside it, like a number, a word, or even a list of things. The label on the box (the variable's name) lets you easily find and use that information later.

Variables are used to store values that might change or be needed multiple times in a program. For example, in x = 5, x is the variable, and 5 is the value stored in it. Later, if you want to use that value, you just refer to the variable x.

5. What is an 'if' statement, and how does it help your program make decisions?

An if statement is a fundamental control flow statement in programming that allows a program to execute different blocks of code based on whether a specified condition is true or false. It's the cornerstone of decision-making within a program. The basic syntax looks like this in many languages:

if (condition) {
  // Code to execute if the condition is true
} else {
  // Code to execute if the condition is false
}

if statements enable programs to respond dynamically to different inputs or situations. For example, an if statement could check if a user is logged in before allowing them to access sensitive data, or if a number is positive before calculating its square root. This allows programs to handle various scenarios and execute the appropriate actions accordingly, making them more versatile and robust.

6. What is a 'loop', and why is it useful when you want to do something many times?

A 'loop' is a programming construct that allows you to repeatedly execute a block of code. It's useful because instead of writing the same code multiple times, you can write it once inside a loop, and the loop will handle the repetition for you.

For example, if you wanted to print "Hello" 10 times, instead of writing print("Hello") ten times, you could use a loop like this (in Python):

for i in range(10):
    print("Hello")

This makes your code much more concise, readable, and maintainable. Loops are essential for tasks like processing lists of data, iterating through files, and performing repetitive calculations.

7. Can you explain what an 'array' is and how it helps you store multiple things?

An array is a data structure that stores a collection of elements of the same data type in contiguous memory locations. Think of it like a numbered list where each item has a specific position (index). This arrangement allows you to access any element quickly using its index. For example, in many languages, the first element has index 0, the second has index 1, and so on.

Arrays are helpful because they allow you to organize and manage multiple related values under a single variable name. Instead of creating separate variables for each item (e.g., item1, item2, item3), you can store them all in an array like items = [item1, item2, item3]. This makes your code more organized, readable, and easier to manipulate data when dealing with a group of similar items. For example, consider processing a series of temperature readings or storing a list of student names.

8. What is a 'method' in C#, and why do we use them to organize our code?

In C#, a method is a block of code that performs a specific task. It's essentially a function that's associated with a class or struct. Methods define the behavior of objects.

We use methods to organize our code for several reasons:

  • Modularity: Methods break down large, complex problems into smaller, more manageable pieces.
  • Reusability: A method can be called multiple times from different parts of the code, avoiding duplication. Example:
    public int Add(int a, int b)
    {
    return a + b;
    }
    
  • Readability: Well-named methods make code easier to understand.
  • Maintainability: Changes to a specific functionality can be isolated to a single method, reducing the risk of introducing bugs elsewhere.

9. What does 'debugging' mean, and what's one simple way you can try to find mistakes in your code?

Debugging is the process of finding and fixing errors (bugs) in computer code or software. A bug is an error, flaw, or fault in a computer program or system that causes it to produce an incorrect or unexpected result, or to behave in unintended ways.

One simple way to find mistakes is to use print statements or a debugger to step through your code line by line. By inserting print statements (e.g., print(variable_name)) at various points, you can inspect the values of variables and the flow of execution to identify where the code deviates from the expected behavior. Alternatively, using a debugger allows you to pause execution, examine variables, and step through the code one line at a time, providing a more controlled way to understand what's happening.

10. What is 'source control' (like Git), and why is it important for working on projects with others?

Source control, like Git, is a system that tracks changes to files over time. It's essentially a version history for your project's code and other assets. This allows you to revert to previous versions, compare changes, and see who made specific modifications.

It's crucial for collaborative projects because it enables multiple people to work on the same files simultaneously without overwriting each other's work. Git provides mechanisms for merging changes, resolving conflicts, and maintaining a central repository of the project's history. Without source control, coordinating changes and managing different versions becomes extremely difficult and error-prone, leading to lost work and integration problems. For example, you might use commands like git pull, git push, and git merge to manage the changes within a team.

11. What is the difference between `Console.WriteLine()` and `Console.ReadLine()`?

Console.WriteLine() is used to output information to the console. It takes a value (or a string) as input and displays it in the console window. It then moves the cursor to the next line. Think of it as 'writing a line' to the console.

Console.ReadLine() is used to read input from the console. It waits for the user to type something and press Enter. The method then returns the entered text as a string. If the user doesn't enter anything and just presses enter, it returns "" (an empty string).

12. Explain the difference between a class and an object in C#?

A class is a blueprint or a template for creating objects. It defines the properties (data) and methods (behavior) that an object of that class will have. Think of it like a cookie cutter; the cookie cutter is the class, and the cookies are the objects.

An object, on the other hand, is an instance of a class. It's a concrete realization of the blueprint. Each object has its own unique set of data values for the properties defined in the class. Multiple objects can be created from the same class, each with its own state. For example, if Dog is a class, myDog and yourDog are objects of the Dog class. They are both dogs but have different names, breeds, and ages.

13. What is the purpose of using comments in code, and how can they help you and others?

The primary purpose of comments in code is to explain what the code does, how it works, and why certain decisions were made. They serve as documentation within the code itself, making it easier to understand and maintain.

Comments help developers (including yourself in the future) by:

  • Improving Readability: They break down complex logic into simpler terms.
  • Facilitating Collaboration: They allow other developers to quickly grasp the code's purpose.
  • Aiding Debugging: They can highlight potential problem areas or explain the reasoning behind specific implementations.
  • Generating Documentation: Tools can automatically extract comments to generate external documentation.

Example:

# Calculate the area of a rectangle
def calculate_area(length, width):
    # Ensure inputs are positive
    if length <= 0 or width <= 0:
        return 0 # Return 0 if dimensions are invalid
    return length * width

14. What are some basic data types you know in C# other than `int` and `string`?

Besides int and string, C# offers several other fundamental data types. Some common ones include:

  • bool: Represents a boolean value, either true or false.
  • float: Represents a single-precision floating-point number (32-bit).
  • double: Represents a double-precision floating-point number (64-bit).
  • char: Represents a single Unicode character.
  • decimal: Represents a precise decimal value, suitable for financial calculations (128-bit).
  • byte: Represents an 8-bit unsigned integer.
  • short: Represents a 16-bit integer.
  • long: Represents a 64-bit integer.

15. How do you create a simple 'Hello, World!' program in .NET Core?

To create a 'Hello, World!' program in .NET Core, you can use the following steps:

First, create a new console application project using the .NET CLI: dotnet new console -o HelloWorld. This creates a basic project structure. Next, navigate into the project directory using the command line: cd HelloWorld. Now, modify the Program.cs file to output 'Hello, World!'. The relevant code inside Program.cs would look like this:

using System;

namespace HelloWorld
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello, World!");
        }
    }
}

Finally, run the program using the command: dotnet run. This will compile and execute the code, displaying 'Hello, World!' in the console.

16. Describe the difference between `public` and `private` access modifiers.

The public and private access modifiers control the visibility and accessibility of class members (variables, methods) in object-oriented programming languages. public members are accessible from anywhere, both inside and outside the class. This means any part of the code can directly access or modify public variables or call public methods.

In contrast, private members are only accessible from within the same class. Other classes, even subclasses, cannot directly access private members. This enforces encapsulation and data hiding, preventing unintended modifications and protecting the internal state of the object. Languages like Java, C++, and C# support these access modifiers. For example:

class MyClass {
 public int publicVar; // Accessible everywhere
 private int privateVar; // Only accessible within MyClass
}

17. Can you describe what you understand about API's and how they can be used in .NET Core?

APIs (Application Programming Interfaces) are essentially contracts that allow different software systems to communicate and exchange data. They define the methods and data formats that applications can use to request services from each other. In .NET Core, APIs can be created using ASP.NET Core Web API to expose functionalities over HTTP. These APIs can then be consumed by various clients like web applications, mobile apps, or other services.

In .NET Core, we can create RESTful APIs using controllers and actions that handle HTTP requests (GET, POST, PUT, DELETE). Data is typically serialized into JSON or XML format for transmission. Clients can then use HTTP clients (like HttpClient) to interact with these APIs by sending requests and processing the responses. For example, a simple API might expose an endpoint to retrieve user data:

[HttpGet("users/{id}")]
public IActionResult GetUser(int id)
{
    // Logic to retrieve user from database
    var user = GetUserFromDatabase(id);
    if (user == null)
    {
        return NotFound();
    }
    return Ok(user);
}

18. What is NuGet, and why is it important in .NET Core development?

NuGet is a package manager for .NET, providing a centralized way to discover, install, and manage reusable software components (libraries/packages) within your .NET projects. It simplifies the process of including external dependencies, such as third-party libraries or frameworks, into your application.

In .NET Core development, NuGet is crucial because it streamlines dependency management. Instead of manually downloading and referencing DLLs, you can easily add packages from the NuGet Gallery (a central repository) using the NuGet Package Manager in Visual Studio or the dotnet add package command. This ensures consistent versions of dependencies across projects and simplifies updating and removing packages. NuGet packages can contain precompiled code, scripts, or other assets necessary for the package to function.

19. How would you handle a simple error in a .NET Core application?

In a .NET Core application, a simple error can be handled using a try-catch block. The code that might throw an exception is placed within the try block. If an exception occurs, the control is immediately transferred to the catch block, where you can log the error, display a user-friendly message, or take other appropriate actions.

For example:

try
{
    // Code that might throw an exception
    int result = 10 / 0;
}
catch (DivideByZeroException ex)
{
    // Handle the exception
    Console.WriteLine("Error: Division by zero.");
    // Optionally log the exception details using a logging framework
    //_logger.LogError(ex, "Division by zero error occurred.");
}

20. Explain what you know about testing in .NET Core (e.g., unit testing).

In .NET Core, testing is a crucial part of software development. Unit testing, in particular, focuses on verifying individual components or methods in isolation. Key frameworks include:

  • xUnit.net: A popular and extensible testing framework.
  • MSTest: Microsoft's own testing framework.
  • NUnit: Another widely used framework, similar to xUnit.

These frameworks enable writing test methods to assert expected outcomes. For example:

[Fact]
public void Add_TwoNumbers_ReturnsSum()
{
    // Arrange
    int a = 10;
    int b = 20;
    // Act
    int sum = a + b;
    // Assert
    Assert.Equal(30, sum);
}

Besides unit testing, other types of tests like integration and end-to-end are also pertinent, and .NET Core provides support for them. For instance, TestServer helps test ASP.NET Core applications by hosting them in-memory during integration tests.

21. What are some benefits of using .NET Core for web development?

Using .NET Core for web development offers several advantages. It's cross-platform, meaning you can develop and deploy applications on Windows, macOS, and Linux. This provides greater flexibility and potentially reduces infrastructure costs. Also, .NET Core has been designed with performance in mind and is much faster compared to the .NET Framework. It also features a modular design, allowing developers to include only the necessary dependencies, thus reducing the application's footprint.

Furthermore, .NET Core embraces dependency injection making the system loosely coupled and making unit testing much simpler. Package management is streamlined with NuGet, and the command-line interface (CLI) offers a powerful tool for project creation, building, and publishing. Finally, continuous updates and a vibrant community ensure that .NET Core stays current with the latest technologies and best practices. dotnet new webapi is a popular command to quickly create a Web API project.

22. Describe what you understand about dependency injection in .NET Core.

Dependency Injection (DI) is a design pattern used to achieve Inversion of Control (IoC) in .NET Core. It allows you to develop loosely coupled, testable, and maintainable code. Instead of a class creating its dependencies, these dependencies are 'injected' into the class, usually through its constructor.

.NET Core has built-in support for DI. You register your services (dependencies) in the ConfigureServices method of the Startup.cs file. These services can be registered with different lifetimes, such as: Transient, Scoped, or Singleton. The framework then takes care of resolving and injecting these dependencies when your application needs them. Here's a simple example:

public interface IMyService { }
public class MyService : IMyService { }

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

23. What are environment variables and how might you use them in a .NET Core application?

Environment variables are key-value pairs that exist outside the scope of an application's code. They store configuration settings that can vary depending on the environment the application is running in (e.g., development, testing, production). They allow you to configure application behavior without modifying the code itself.

In a .NET Core application, you can access environment variables using the System.Environment.GetEnvironmentVariable() method. For example:

string apiKey = Environment.GetEnvironmentVariable("API_KEY");
string connectionString = Environment.GetEnvironmentVariable("CONNECTION_STRING");

They are commonly used for:

  • Database connection strings: Storing sensitive database credentials.
  • API keys: Managing API access tokens.
  • Application settings: Configuring application-specific behaviors (e.g., logging levels).
  • Deployment-specific configurations: Adapting the application to different deployment environments (e.g., setting the application port).

Configuration files, such as appsettings.json, can also utilize environment variables to override default settings, using the ${VARIABLE_NAME} syntax inside the configuration file or through configuration providers that specifically load environment variables.

24. If you had a list of numbers, how could you find the largest number using C#?

You can find the largest number in a list of numbers in C# using several approaches. A straightforward method involves iterating through the list and keeping track of the largest number found so far:

using System.Linq;

public class Example
{
    public static int FindLargest(List<int> numbers)
    {
        if (numbers == null || numbers.Count == 0)
        {
            throw new ArgumentException("List cannot be null or empty.");
        }

        int largest = numbers[0];
        for (int i = 1; i < numbers.Count; i++)
        {
            if (numbers[i] > largest)
            {
                largest = numbers[i];
            }
        }
        return largest;
    }

    // Alternatively, using LINQ:
    public static int FindLargestLinq(List<int> numbers)
    {
         if (numbers == null || numbers.Count == 0)
        {
            throw new ArgumentException("List cannot be null or empty.");
        }
        return numbers.Max();
    }
}

Alternatively, you could use the LINQ library's Max() method for a more concise solution. However, consider the performance implications of each method based on the size of your list. The iterative approach avoids the overhead of LINQ, which can be beneficial for very large lists where performance is critical. Error handling for null or empty lists is crucial.

25. Explain what you know about LINQ and how it is useful.

LINQ (Language Integrated Query) is a powerful feature in .NET that provides a unified way to query data from various sources, such as databases, collections, XML, and more, directly within C# (or VB.NET) code. It uses a consistent syntax for querying different data sources, eliminating the need to learn different query languages for each type of data. LINQ enables you to write queries that are type-safe and can be checked at compile time, reducing runtime errors.

LINQ is useful because it simplifies data access, improves code readability, and reduces the amount of code needed to perform data operations. Some of its benefits include:

  • Simplified data access: Provides a consistent way to query different data sources.
  • Improved readability: Queries are written in a declarative style, making them easier to understand.
  • Type safety: Catches errors at compile time rather than runtime.
  • Reduced code: Less code is needed to perform data operations, such as filtering, sorting, and grouping.
  • Example: var results = from p in products where p.Price > 10 select p;

26. What is JSON, and why is it used in .NET Core applications?

JSON (JavaScript Object Notation) is a lightweight, human-readable data-interchange format. It's used for transmitting data between a server and a web application (or other applications) because it's easy to parse and generate.

In .NET Core applications, JSON is widely used for:

  • API communication: APIs often use JSON to send and receive data.
  • Configuration: appsettings.json is a common way to store configuration data.
  • Data serialization/deserialization: Converting .NET objects to JSON and vice versa using libraries like System.Text.Json or Newtonsoft.Json (although System.Text.Json is preferred in modern .NET Core).
  • Storing data: Simple data persistence scenarios.

27. How does .NET Core handle different operating systems (like Windows, macOS, and Linux)?

.NET Core (and later .NET 5+) achieves cross-platform compatibility through its architecture and runtime. It relies on a platform abstraction layer that provides a consistent API for interacting with the underlying operating system. This layer handles the specific nuances of each OS, such as file system differences, memory management, and system calls, allowing .NET code to run without modification on Windows, macOS, and Linux.

Specifically, .NET Core uses CoreCLR (the runtime) and CoreFX (the class libraries). The CoreCLR is responsible for compiling and executing the managed code, while CoreFX provides a set of APIs that are implemented differently for each operating system. For instance, accessing a file involves different system calls on Windows vs. Linux, but the .NET API provides a unified interface that abstracts those differences. This abstraction is key for portability. Developers build applications against the .NET standard libraries, and the .NET runtime handles the OS-specific implementations.

28. What are some tools or IDEs (like Visual Studio Code) that you can use for .NET Core development?

Several tools and IDEs support .NET Core development. Visual Studio is a comprehensive IDE with extensive features for .NET development, including debugging, profiling, and project management.

Visual Studio Code is a lightweight but powerful code editor that, with the C# extension, provides excellent support for .NET Core, including IntelliSense, debugging, and build tasks. Other options include JetBrains Rider, a cross-platform .NET IDE known for its code analysis and refactoring capabilities, and command-line tools like the .NET CLI which is essential for building, running, and publishing .NET Core applications from any terminal.

29. Imagine your program isn't working as expected. Walk me through your process of fixing it.

When a program isn't working as expected, I usually start by trying to reproduce the issue reliably. This helps ensure that I'm tackling a real problem and not just a fluke. Next, I examine the error messages, logs, and any available stack traces for clues about the source of the problem. I'll then often use a debugger to step through the code, inspect variables, and trace the program's execution flow to pinpoint the exact location where things go wrong.

Once I've identified the source of the bug, I'll formulate a fix. This might involve modifying code, changing configurations, or even adjusting the environment. After applying the fix, I'll thoroughly test the program, including the original scenario that triggered the issue and related areas, to ensure that the problem is resolved and that no new issues have been introduced. I'd also use version control, creating a new branch to test a fix. If I am unsure of the fix, or require assistance I will use a technique like rubber duck debugging, or ask a more experienced colleague for help.

.NET Core intermediate interview questions

1. How does .NET Core's dependency injection work, and why is it useful?

.NET Core's dependency injection (DI) is a design pattern and a technique used to achieve loose coupling between classes and their dependencies. Instead of a class creating its own dependencies, those dependencies are 'injected' into the class, typically through its constructor, properties, or methods. .NET Core has a built-in DI container that manages the creation and lifetime of these dependencies. You register your services (dependencies) with the container, specifying their lifetime scope (e.g., singleton, scoped, transient). When a class needs a dependency, the container provides it.

DI promotes testability, reusability, and maintainability. By decoupling components, you can easily swap implementations, mock dependencies for testing, and reduce the impact of changes. The built-in container simplifies dependency management and provides a standardized way to configure and resolve dependencies across your application. For example:

public class MyService {
 private readonly IMyDependency _dependency;

 public MyService(IMyDependency dependency) {
 _dependency = dependency;
 }
}

2. Explain the difference between `Task.Run` and `Task.Factory.StartNew` in .NET Core.

Task.Run and Task.Factory.StartNew are both used for creating and starting tasks in .NET, but they have some subtle differences. Task.Run is the preferred and simpler method in most cases. It's designed to directly queue work to the thread pool. It implicitly uses the default task scheduler and offers overload options to pass in cancellation tokens and TaskCreationOptions defaults to TaskCreationOptions.None.

Task.Factory.StartNew, on the other hand, offers more control and flexibility. It allows you to specify a custom task scheduler, configure TaskCreationOptions, and control the task's execution behavior more precisely. For example, it allows you to use TaskCreationOptions.LongRunning to hint to the scheduler that a task is long-running and should be given its own dedicated thread. The default for TaskCreationOptions is TaskCreationOptions.None unless a TaskScheduler is specified at which point it becomes TaskCreationOptions.AttachedToParent | TaskCreationOptions.DenyChildAttach.

3. What are middleware components in ASP.NET Core, and how are they used in the request pipeline?

Middleware components in ASP.NET Core are software components that are assembled into an application pipeline to handle requests and responses. Each middleware component performs a specific function, such as authentication, authorization, logging, or serving static files. They form a chain, where each middleware can process the request before passing it on to the next, and similarly process the response on the way back.

They are used in the request pipeline by being added to the Configure method in the Startup.cs file. The order in which middleware components are added to the pipeline is crucial, as it determines the order in which they are executed. For example:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

4. How does .NET Core handle configuration, and what are some common configuration sources?

.NET Core uses a flexible configuration system based on key-value pairs. It leverages the Microsoft.Extensions.Configuration NuGet package. The configuration is built from one or more configuration providers, allowing for layered and overridden settings.

Common configuration sources include:

  • appsettings.json: The most common way, typically for environment-agnostic settings.
  • appsettings.{Environment}.json: Environment-specific settings (e.g., appsettings.Development.json).
  • Environment variables: Useful for production secrets and settings that vary between environments.
  • Command-line arguments: For specifying settings when running the application.
  • User secrets: A secure store for development-time secrets (prevents accidental commits of secrets to source control). Accessed via dotnet user-secrets.
  • Azure Key Vault: For securely storing and managing secrets in Azure.
  • In-memory providers: Useful for testing or scenarios where settings are generated programmatically.

The order in which configuration sources are added determines their precedence. Later sources override earlier ones. For example, environment variables often override appsettings.json.

5. Describe the purpose of Kestrel in ASP.NET Core.

Kestrel is a cross-platform web server for ASP.NET Core. It is the default web server included in ASP.NET Core project templates and is designed to be performant and efficient.

Kestrel can be used as a direct, internet-facing web server or as a reverse proxy server, sitting behind another web server like IIS, Nginx, or Apache. When used as a reverse proxy, Kestrel handles requests passed to it by the proxy server, which can provide additional features like load balancing, security, and caching.

6. How can you implement logging in a .NET Core application, and what are some best practices?

In .NET Core, logging is typically implemented using the Microsoft.Extensions.Logging library. First, add the NuGet package Microsoft.Extensions.Logging and a specific provider like Microsoft.Extensions.Logging.Console or Serilog.AspNetCore. Then, inject ILogger<T> into your classes. Log messages using methods like LogInformation(), LogError(), LogWarning(), etc. Example:

public class MyClass
{
    private readonly ILogger<MyClass> _logger;

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

    public void DoSomething()
    {
        _logger.LogInformation("Doing something...");
        // ...
    }
}

Best practices include: using structured logging to enable easier querying and analysis; configuring different log levels (e.g., Debug, Information, Warning, Error, Critical) based on environment; logging exceptions with relevant context; avoiding logging sensitive data; using a centralized logging solution like Serilog or NLog for more advanced features such as log aggregation and filtering. Also, leverage dependency injection for easy access to the logger and configure logging in Program.cs.

7. What is the role of the `dotnet` CLI, and what are some common commands?

The dotnet CLI (Command Line Interface) is a cross-platform toolchain for developing, building, running, and publishing .NET applications. It provides a set of commands that allow developers to perform various tasks from the command line, replacing the need for an IDE in many scenarios. It is the primary way to interact with the .NET SDK.

Some common dotnet CLI commands include:

  • dotnet new: Creates a new .NET project, solution or configuration file based on a template. Example: dotnet new console
  • dotnet build: Builds a .NET project and its dependencies.
  • dotnet run: Builds and executes a .NET project.
  • dotnet publish: Packages a .NET application for deployment.
  • dotnet add package: Adds a NuGet package to a project. Example: dotnet add package Newtonsoft.Json
  • dotnet restore: Restores the dependencies specified in a project file.
  • dotnet test: Runs unit tests in a project.
  • dotnet ef: Commands for Entity Framework Core tools. Example: dotnet ef migrations add InitialCreate

8. Explain the difference between `ProjectReference`, `PackageReference`, and `ProjectReference` in a .NET Core project file.

ProjectReference, PackageReference, and Analyzer are different ways to manage dependencies in a .NET project file (typically a .csproj file). ProjectReference is used when your project depends on another project within the same solution. It essentially tells the build system to build the referenced project first and then use its output as a dependency. This is common for multi-project solutions where you have libraries or modules that your main application depends on.

PackageReference is used to include NuGet packages as dependencies. NuGet packages are pre-built libraries or components that you can easily add to your project. When you add a PackageReference, the build system will download the package from the NuGet feed and include it in your project's dependencies. Analyzer elements, distinct from regular PackageReference, specify code analyzers and source generators to incorporate into the project's build process. These can include Roslyn analyzers or custom analyzers that enforce coding standards, identify potential issues, or automatically generate code during compilation. They are incorporated as NuGet packages, identified similarly to standard packages via the PackageReference mechanism, but their purpose is strictly confined to analysis and code generation rather than providing runtime dependencies.

9. How does .NET Core support cross-platform development, and what are some considerations?

.NET Core (and later .NET 5+) achieves cross-platform development primarily through its runtime environment, which is available for Windows, macOS, and Linux. It relies on a shared set of libraries and APIs abstracted from the underlying operating system. This allows developers to write code once and, with minimal modifications (if any), deploy it across these different platforms. CoreCLR (the .NET runtime) is responsible for JIT compiling the IL code generated by the C# compiler to native machine code for the target operating system.

Some considerations include: platform-specific APIs (you might need to use #if directives for platform-specific code), differences in file system paths, and ensuring all dependencies are available for each targeted OS. Testing on each platform is crucial. Deployment strategies can also vary significantly across Windows, macOS, and Linux.

10. What is the purpose of the `IConfiguration` interface, and how is it used?

The IConfiguration interface in .NET provides a way to access application configuration settings from various sources, such as appsettings.json, environment variables, command-line arguments, and user secrets. Its primary purpose is to abstract away the details of where the configuration data comes from, allowing your application code to access settings in a consistent manner. It promotes loose coupling and makes it easy to change configuration sources without modifying application code.

It is used by injecting it into classes or methods. The IConfiguration interface provides methods like GetValue<T>() and GetSection() to retrieve configuration values. For example, _configuration.GetValue<string>("Logging:LogLevel:Default") retrieves the default log level from the configuration. Dependency Injection (DI) is the typical way to supply an IConfiguration instance to components that need it.

11. Explain how you would implement exception handling in an ASP.NET Core application.

In ASP.NET Core, exception handling can be implemented using several approaches. One common approach is using middleware. You can create a custom middleware that catches exceptions and handles them, such as logging the error and returning a user-friendly error message. This ensures a centralized location for exception handling across your application. For example:

public class ExceptionHandlingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<ExceptionHandlingMiddleware> _logger;

    public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An unhandled exception occurred.");
            context.Response.StatusCode = 500;
            await context.Response.WriteAsync("An unexpected error occurred.");
        }
    }
}

Another approach is using exception filters in your controllers. These filters allow you to handle exceptions that occur within specific controller actions or across all actions in a controller. You can also combine both middleware and exception filters for comprehensive exception handling. app.UseExceptionHandler() in Program.cs also provides global exception handling.

12. How can you secure a .NET Core web API?

Securing a .NET Core web API involves several layers. Authentication verifies the user's identity, often using techniques like:

  • API Keys: Simple but less secure.
  • JWT (JSON Web Tokens): Industry standard, using bearer tokens in the Authorization header. Needs proper secret key management and validation.
  • OAuth 2.0 / OpenID Connect: Delegates authentication to a trusted provider (like Google, Azure AD).

Authorization determines what resources the authenticated user can access. Implement role-based or claim-based authorization using the [Authorize] attribute or custom policies. Other measures include: input validation to prevent injection attacks, HTTPS for encrypted communication, rate limiting to prevent abuse, CORS configuration, and regular security audits.

13. What are Razor Pages in ASP.NET Core, and how do they differ from traditional MVC?

Razor Pages are a page-centric approach to building web UI in ASP.NET Core, making it easier and more productive to create web pages. They are organized around individual pages in a directory structure (e.g., Pages/Index.cshtml and Pages/Index.cshtml.cs), with each page typically handling a single request.

The key difference from traditional MVC is how request handling is structured. In MVC, requests go through a controller which then selects a view. In Razor Pages, each page has its own code-behind file (.cshtml.cs) that directly handles requests, simplifying the structure. This eliminates the need for separate controllers and often reduces boilerplate code, especially for simple applications. Code is co-located, with the UI (.cshtml) and its logic (.cshtml.cs) residing in the same directory. Razor Pages promote separation of concerns by encapsulating UI logic within the page model and the UI rendering logic in the Razor view.

14. How does .NET Core handle memory management, and what are some common memory leaks?

.NET Core uses a garbage collector (GC) to automatically manage memory. The GC periodically scans the heap, identifies objects that are no longer reachable by the application, and reclaims the memory they occupy. However, even with a GC, memory leaks can still occur. These leaks usually happen when objects are unintentionally kept alive longer than necessary, preventing the GC from collecting them.

Common .NET Core memory leaks include: holding onto event handlers without unregistering, storing objects in static variables or long-lived caches, not disposing of IDisposable objects (like streams or database connections) within a using statement or try-finally block, and using closure which unintentionally capture outer scope variables and prevent them to be garbage collected. For example:

using(var connection = new SqlConnection(connectionString))
{
  //use the connection
} //connection.Dispose() is automatically called

15. Explain the concept of 'options pattern' in .NET Core.

The Options Pattern in .NET Core provides a way to access configuration values in a strongly-typed manner. Instead of directly accessing Configuration objects, you define classes representing sections of your configuration file (e.g., appsettings.json), and bind the configuration values to the properties of these classes. This promotes code maintainability, testability, and type safety.

To use the Options Pattern:

  1. Define an options class (a simple POCO) with properties matching the configuration keys.
  2. Register the options class with the dependency injection container using services.Configure<YourOptionsClass>(Configuration.GetSection("YourSectionName")).
  3. Inject IOptions<YourOptionsClass> into your classes to access the configuration values through the Value property (e.g., _options.Value.YourSetting).
  4. IOptionsSnapshot<YourOptionsClass> can be used if you need to get the updated values of the options class after configuration changes. It is scoped.
  5. IOptionsMonitor<YourOptionsClass> can be used if you need to get the updated values of the options class after configuration changes. It is singleton and it can notify you of changes.

16. How would you implement unit testing in a .NET Core project, and what are some common testing frameworks?

To implement unit testing in a .NET Core project, I would typically use a testing framework like xUnit, NUnit, or MSTest. First, add the necessary NuGet packages for the chosen framework and a mocking library like Moq. Then, create a separate test project mirroring the structure of the main project. Within the test project, write test methods to exercise individual units of code (e.g., classes, methods). Use Arrange-Act-Assert pattern within each test method.

Common testing frameworks include:

  • xUnit: A popular, extensible framework.
  • NUnit: Another widely used framework with a rich feature set.
  • MSTest: Microsoft's own testing framework.

Example:

[Fact]
public void Add_ValidInput_ReturnsSum()
{
    // Arrange
    var calculator = new Calculator();
    int a = 5;
    int b = 10;

    // Act
    int result = calculator.Add(a, b);

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

17. What is the purpose of the `IHttpClientFactory` interface in .NET Core?

The IHttpClientFactory interface in .NET Core provides a central location for creating and configuring HttpClient instances. It addresses common issues related to managing HttpClient lifecycles, such as socket exhaustion due to improper disposal. Instead of creating a new HttpClient instance each time you need to make an HTTP request, IHttpClientFactory manages a pool of HttpClient instances, reusing connections when possible.

Key benefits include:

  • Centralized Configuration: Allows you to configure HttpClient instances with specific headers, timeouts, and other settings in a single location.
  • Lifecycle Management: Handles the creation and disposal of HttpClient instances, preventing socket exhaustion.
  • Integration with Polly: Supports the use of Polly, a resilience and transient-fault-handling library, to add retry policies, circuit breakers, and other resilience patterns to HTTP requests.
  • Improved Testability: Simplifies unit testing by allowing you to mock or substitute the IHttpClientFactory implementation.

18. How can you publish a .NET Core application to different platforms?

You can publish a .NET Core application to different platforms using the dotnet publish command. This command creates a self-contained deployment or a framework-dependent deployment.

To publish for a specific platform, you specify the Runtime Identifier (RID) using the -r or --runtime option. For example, dotnet publish -c Release -r linux-x64 publishes for 64-bit Linux. Common RIDs include win-x64, linux-x64, osx-x64, etc. You can find a full list in the .NET documentation. For self-contained deployments (SCD), the runtime is included, making it larger but independent. Framework-dependent deployments (FDD) rely on the .NET runtime being installed on the target system. The target framework is specified in the .csproj file.

Example of modifying the .csproj file for targeting multiple frameworks:

<TargetFrameworks>net6.0;net7.0</TargetFrameworks>

19. Describe the role of environment variables in a .NET Core application.

Environment variables in .NET Core applications provide a way to configure the application's behavior without modifying the code itself. They act as external configuration parameters that can be set at the operating system level or within the application's hosting environment (e.g., Docker, Azure App Service). This separation of configuration from code promotes portability and allows you to easily adapt the application to different environments (development, testing, production) without recompilation.

They are commonly used to store sensitive information like database connection strings, API keys, or feature flag configurations. In .NET Core, you can access environment variables using System.Environment.GetEnvironmentVariable("VARIABLE_NAME"). The IConfiguration interface also integrates with environment variables, so they can be accessed in a strongly-typed manner.

20. How do you implement caching in .NET Core to improve performance?

In .NET Core, caching can be implemented using IMemoryCache interface. First, inject IMemoryCache into your class via dependency injection. Then, use the TryGetValue, Set, and Remove methods to interact with the cache. For example:

private readonly IMemoryCache _cache;

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

public string GetData(string key)
{
    if (!_cache.TryGetValue(key, out string data))
    {
        // Data not in cache, retrieve it
        data = RetrieveDataFromSource(key);

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

        // Save data in cache
        _cache.Set(key, data, cacheEntryOptions);
    }
    return data;
}

Alternatively, you could use distributed caching using Redis or SQL Server. This requires adding the appropriate NuGet package (e.g., Microsoft.Extensions.Caching.StackExchangeRedis) and configuring the cache provider in Startup.cs using services.AddStackExchangeRedisCache() or services.AddDistributedSqlServerCache(). Then inject IDistributedCache instead of IMemoryCache.

.NET Core interview questions for experienced

1. How does .NET Core's garbage collector handle large object heaps, and what strategies can you employ to minimize fragmentation in these heaps?

.NET Core's garbage collector (GC) handles large object heaps (LOH) differently than smaller heaps. Objects larger than approximately 85,000 bytes are placed on the LOH. The LOH is not compacted as frequently as the smaller heaps due to the performance cost of moving large objects. This can lead to fragmentation, where free space is scattered across the heap, making it difficult to allocate contiguous blocks for new large objects.

To minimize LOH fragmentation, you can employ several strategies:

  • Reduce Large Object Allocations: Whenever possible, try to avoid allocating extremely large objects in the first place. Consider using smaller objects or streams.
  • Object Pooling: Implement object pooling for frequently used large objects. This reuses existing objects instead of allocating new ones.
  • Explicit Disposal: Ensure that large objects are explicitly disposed of when no longer needed, allowing the GC to reclaim the memory sooner. Use IDisposable for resources and using statements or try...finally blocks for deterministic disposal.
  • Avoid Pinning: Minimize object pinning as pinned objects cannot be moved by the GC, contributing to fragmentation. If you must pin, try to keep the pinned duration as short as possible using GC.AllocHandle and GCHandleType.Pinned.
  • Use Structs (Value Types): If appropriate, consider using structs instead of classes for collections of data if the data size permits and if copying performance is acceptable. Structs are allocated on the stack or in-line within other objects and therefore avoid the LOH.
  • Pre-allocate Buffers: If you know the size of a large object beforehand, pre-allocate a buffer to avoid reallocations and fragmentation that might occur with resizing arrays.
  • Consider Different Data Structures: Explore alternative data structures or algorithms that might reduce the need for large contiguous memory blocks.

2. Describe the differences between `Task.Run` and `Task.Factory.StartNew` in .NET Core, focusing on their thread pool usage and potential performance implications.

Task.Run and Task.Factory.StartNew are both used for asynchronous operations in .NET, but they differ in their default scheduler and thread pool behavior. Task.Run is generally preferred as it's a higher-level abstraction specifically designed to queue work directly to the thread pool. It uses the default TaskScheduler.Default, which is backed by the thread pool. Task.Factory.StartNew, on the other hand, offers more control. By default, it also uses the thread pool, but it allows you to specify a custom task scheduler and configure options like TaskCreationOptions (e.g., LongRunning).

The key difference with Task.Factory.StartNew is its flexibility. You can, for instance, use TaskCreationOptions.LongRunning to hint to the scheduler that the task might take a while, potentially leading to a new thread being created outside the thread pool. Using Task.Run is simpler and usually sufficient for most thread pool-based asynchronous operations, promoting better thread pool management and performance. If you need finer-grained control or need to execute truly long running tasks outside of the thread pool to prevent starvation, Task.Factory.StartNew can be used with caution.

3. Explain the concept of middleware in ASP.NET Core and how you would implement custom middleware to handle authentication or request logging.

In ASP.NET Core, middleware are components that form a pipeline to handle HTTP requests. Each middleware component in the pipeline can inspect and modify the request and response. They are executed in the order they are added to the pipeline in the Configure method of the Startup.cs file.

To implement custom middleware, you create a class with an InvokeAsync method. This method receives the HttpContext and a RequestDelegate representing the next middleware in the pipeline. Inside InvokeAsync, you can perform operations before and after calling await _next(context);. For example, for logging, you'd log request details before _next and response details after. For authentication, you'd check for authentication tokens and set the HttpContext.User accordingly. Here is the example code:

public class RequestLoggingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public RequestLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
    {
        _next = next;
        _logger = loggerFactory.CreateLogger<RequestLoggingMiddleware>();
    }

    public async Task InvokeAsync(HttpContext context)
    {
        _logger.LogInformation($"Request: {context.Request.Method} {context.Request.Path}");
        await _next(context);
        _logger.LogInformation($"Response: {context.Response.StatusCode}");
    }
}

public static class RequestLoggingMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestLoggingMiddleware>();
    }
}

//In Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRequestLogging();

    // Other middleware

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
}

4. How can you implement efficient caching strategies in .NET Core applications, considering both in-memory and distributed caching options?

Efficient caching in .NET Core involves leveraging both in-memory and distributed caching. For in-memory caching, use IMemoryCache. You can set expiration policies (absolute, sliding) and priorities. Dependency injection makes it easy to use. Distributed caching, ideal for multi-server environments, can be implemented using Redis or SQL Server. Use IDistributedCache interface. Serialization (e.g., JSON) is often necessary when using IDistributedCache because data needs to be transferred across the network.

To choose between them: If the application is running on a single server or if caching small, frequently accessed data is enough, in-memory caching is a good choice. If the application is running on multiple servers or if caching large data sets is needed, distributed caching is a better choice. You can use both in conjunction. For example, implementing a Cache-Aside pattern, where you check in-memory first, then distributed, and finally the origin.

5. Discuss the role of dependency injection in .NET Core and how it promotes loose coupling and testability in your applications.

Dependency Injection (DI) in .NET Core is a design pattern that allows you to develop loosely coupled and testable applications. Instead of classes creating their dependencies, these dependencies are 'injected' into the class, usually through constructor injection. .NET Core has built-in support for DI through its service container (IServiceCollection).

DI promotes loose coupling because classes don't have direct dependencies on concrete implementations; they depend on abstractions (interfaces). This makes it easier to swap implementations without modifying the dependent class. For testability, DI enables you to inject mock objects or test doubles into classes under test, isolating the unit being tested and making it easier to verify its behavior in isolation. For example, if a class depends on an IUserRepository, you can inject a mock IUserRepository during testing to control the data returned and verify interactions with the repository without hitting a real database.

public class MyService
{
 private readonly IRepository _repository;

 public MyService(IRepository repository) //Constructor Injection
 {
 _repository = repository;
 }
}

6. Explain how to use health checks in ASP.NET Core to monitor the status of your application and its dependencies.

ASP.NET Core health checks provide a way to monitor the health of your application and its dependencies (like databases, external services, etc.). To use them, you first add the Microsoft.AspNetCore.HealthChecks package. Then, in Startup.cs, you configure health checks in ConfigureServices using services.AddHealthChecks(). You register individual health checks for dependencies (e.g., builder.AddSqlServer(...) for a SQL Server database). Finally, in Configure, you expose the health check endpoint using app.UseEndpoints(endpoints => { endpoints.MapHealthChecks("/health"); });. This creates an endpoint (e.g., /health) that returns a JSON response indicating the health status of each configured check. The response will indicate Healthy, Degraded, or Unhealthy status.

You can customize health checks by implementing the IHealthCheck interface. This allows you to perform custom logic to determine the health of a specific dependency. The health check endpoint can also be customized with options, like specifying allowed status codes or using a custom response writer to change the response format. Here's an example of adding a basic health check:

services.AddHealthChecks()
    .AddCheck("Example", () => HealthCheckResult.Healthy("The check is healthy!"));

7. What are the benefits of using Kestrel as a web server in .NET Core, and when might you choose to use a reverse proxy like Nginx or IIS in front of it?

Kestrel is a cross-platform web server for ASP.NET Core. It's lightweight and designed for performance. Key benefits include: being cross-platform, its inherent speed, and its ability to be used as an edge server exposed directly to the internet in some scenarios.

While Kestrel can serve requests directly, it's often beneficial to use a reverse proxy like Nginx or IIS in front of it. Reasons for this include: Load Balancing: Distributing traffic across multiple Kestrel instances, Security: Providing a layer of defense against attacks (DDoS, etc.), SSL Termination: Handling SSL encryption/decryption to offload Kestrel, Static File Serving: Reverse proxies are generally better at serving static files, and Centralized Management: Managing routing, caching, and other web server features in a single place. You'd typically choose a reverse proxy in production environments to leverage these features.

8. Describe how you would handle errors and exceptions in a .NET Core application, including global exception handling and logging strategies.

In .NET Core, I handle errors and exceptions using a combination of try-catch blocks, global exception handling middleware, and logging. For specific operations that might fail, I wrap the code in try-catch blocks to handle exceptions gracefully, like database connection errors or file access issues. I then log the exception details using a logging framework such as Serilog or NLog. For global exception handling, I would use middleware in the ASP.NET Core pipeline, this middleware catches any unhandled exceptions and logs them. This prevents the application from crashing and presents a user-friendly error message. The implementation would look like this:

public class ExceptionHandlingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<ExceptionHandlingMiddleware> _logger;

    public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext httpContext)
    {
        try
        {
            await _next(httpContext);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "An unhandled exception occurred.");
            // Handle the exception and return an appropriate response.
            httpContext.Response.StatusCode = 500; // Or other appropriate status code
            await httpContext.Response.WriteAsync("An error occurred. Please try again later.");
        }
    }
}

I register this middleware in Startup.cs like this: app.UseMiddleware<ExceptionHandlingMiddleware>(); This ensures all exceptions are caught and handled effectively, and the application continues running.

9. How can you secure a .NET Core API using JWT (JSON Web Tokens), and what are some best practices for storing and managing tokens?

To secure a .NET Core API with JWT, you typically use middleware like Microsoft.AspNetCore.Authentication.JwtBearer. First, configure authentication in Startup.cs to use JWT Bearer authentication, specifying the issuer, audience, and signing key. Then, protect your API endpoints by adding the [Authorize] attribute to controllers or actions. The client authenticates with username/password and if valid the API returns a JWT. The client then includes this JWT in the Authorization header of subsequent requests using the Bearer scheme. The API validates this token for each request. Here is an example of how authorization would be used.

[Authorize]
[ApiController]
[Route("[controller]")]
public class MyController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok("Authorized!");
    }
}

Best practices for storing JWTs include:

  • Never store JWTs in local storage or cookies. These are vulnerable to XSS attacks.
  • Use HTTP-only cookies: Store JWTs in HTTP-only cookies with a short expiration time. This mitigates XSS risks.
  • Refresh tokens: Implement refresh tokens to obtain new access tokens without requiring the user to re-authenticate frequently. Store refresh tokens securely in the database and rotate them regularly.
  • Token revocation: Provide a mechanism to revoke tokens, such as invalidating the token upon logout or password reset.
  • Consider the BFF (Backend For Frontend) pattern: Use a secure backend service as a proxy to handle authentication and authorization on behalf of the frontend.

10. Explain the concept of asynchronous programming in .NET Core using `async` and `await`, and how it improves the responsiveness of your applications.

Asynchronous programming in .NET Core with async and await allows you to perform operations without blocking the main thread. The async keyword marks a method as asynchronous, enabling the use of the await keyword inside it. When await is encountered, the method's execution is suspended until the awaited task completes, returning control to the caller. Crucially, the thread is not blocked; it's free to handle other tasks.

This approach significantly improves application responsiveness. In UI applications, it prevents the UI from freezing during long-running operations (like network requests or file I/O). In server-side applications, it allows the server to handle more concurrent requests, as threads are not tied up waiting for I/O operations to complete. Instead, they're released to service other requests. Example: public async Task<string> DownloadDataAsync(string url) { using (HttpClient client = new HttpClient()) { return await client.GetStringAsync(url); } }

11. Discuss the advantages of using gRPC over REST APIs in .NET Core, considering factors like performance, efficiency, and code generation.

gRPC offers several advantages over REST APIs in .NET Core, primarily in performance and efficiency. gRPC uses Protocol Buffers as its interface definition language and message format. This results in smaller message sizes and faster serialization/deserialization compared to JSON used by REST. gRPC leverages HTTP/2, enabling features like bidirectional streaming, header compression, and multiplexing over a single TCP connection, which further improves performance.

Another significant advantage is code generation. gRPC uses Protocol Buffers to define the service contract, and tools automatically generate client and server stubs in various languages, including C# for .NET Core. This reduces boilerplate code, improves type safety, and simplifies development. In contrast, REST APIs often require manual creation of client libraries or reliance on reflection-based serialization, which can be less efficient and error-prone. Here's a simple example demonstrating a proto definition:

syntax = "proto3";

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

12. How would you implement a message queue using .NET Core, and what are some popular message queue technologies you might consider (e.g., RabbitMQ, Kafka)?

To implement a message queue in .NET Core, you could use an in-memory queue (useful for simpler scenarios) or integrate with a dedicated message broker. For the in-memory approach, you'd typically use a ConcurrentQueue<T> to handle message storage and implement producer/consumer patterns using threads or tasks to enqueue and dequeue messages asynchronously.

For more robust solutions, popular message queue technologies include:

  • RabbitMQ: A widely used, open-source message broker supporting various messaging protocols like AMQP.
  • Kafka: A distributed streaming platform suitable for high-throughput data pipelines and event streaming.
  • Azure Service Bus: A cloud-based messaging service offered by Microsoft Azure.
  • Amazon SQS (Simple Queue Service): A fully managed message queuing service from AWS.

The choice depends on factors like scalability needs, message volume, required features (e.g., message routing, persistence), and existing infrastructure. Libraries like RabbitMQ.Client for RabbitMQ or Confluent.Kafka for Kafka simplify integration within a .NET Core application. Example using RabbitMQ:

//Publishing a message
using RabbitMQ.Client;
using System.Text;

var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
    channel.QueueDeclare(queue: "hello",
                         durable: false,
                         exclusive: false,
                         autoDelete: false,
                         arguments: null);

    string message = "Hello World!";
    var body = Encoding.UTF8.GetBytes(message);

    channel.BasicPublish(exchange: "",
                         routingKey: "hello",
                         basicProperties: null,
                         body: body);
    Console.WriteLine(" [x] Sent {0}", message);
}

13. Explain how to use the .NET Core CLI for building, testing, and deploying your applications, and what are some common CLI commands you use?

The .NET Core CLI is a powerful tool for building, testing, and deploying .NET applications. To build, you use dotnet build, which compiles the code and produces the output assemblies. For testing, dotnet test discovers and runs tests defined in your project. Deployment involves creating a self-contained or framework-dependent deployment using dotnet publish. This command packages the application and its dependencies for distribution.

Some common CLI commands I frequently use include:

  • dotnet new: Creates a new .NET project or solution.
  • dotnet restore: Restores dependencies specified in the project file.
  • dotnet run: Runs the application directly from the source code.
  • dotnet add package: Adds a NuGet package to the project.
  • dotnet ef migrations add: Adds a new migration for Entity Framework Core.
  • dotnet ef database update: Updates the database to the latest migration.

Using the CLI offers flexibility and enables automation through scripting, making it ideal for CI/CD pipelines.

14. Describe the different hosting models available in ASP.NET Core (e.g., InProcess, OutOfProcess) and their implications on performance and deployment.

ASP.NET Core offers two primary hosting models: InProcess and OutOfProcess.

  • InProcess (IIS): The ASP.NET Core application runs within the same process as the IIS worker process (w3wp.exe or iisexpress.exe). This offers significant performance benefits because requests don't need to be proxied to a separate process. Deployment is simpler as IIS directly manages the application.
  • OutOfProcess (Kestrel): The ASP.NET Core application runs in a separate process, typically using the Kestrel server. IIS (or another reverse proxy like Nginx or Apache) acts as a reverse proxy, forwarding requests to Kestrel. This model provides greater isolation and flexibility, allowing you to update or restart the application without affecting IIS. Performance is generally slightly lower due to the reverse proxy overhead. This also includes self-hosting where Kestrel acts as the edge/public facing web server.

15. How do you optimize performance in .NET Core applications, specifically regarding memory allocation and CPU usage?

To optimize .NET Core applications, especially regarding memory allocation and CPU usage, consider several strategies. For memory allocation, minimize object creation, especially in frequently executed code paths. Use object pooling for reusable objects, leverage structs for small, value-type data structures to avoid heap allocations, and consider using Span<T> and Memory<T> to work with memory regions directly, minimizing copies. Profile your application with tools like the .NET Performance Monitor to identify memory leaks and excessive allocations.

For CPU usage, optimize algorithms and data structures for efficiency. Use asynchronous programming (async/await) to prevent blocking the main thread, improve concurrency with Parallel class or ThreadPool. Reduce lock contention by using finer-grained locking or lock-free data structures. Employ caching strategies to avoid redundant computations. Profile your application with tools like PerfView or dotnet-trace to identify CPU bottlenecks and hotspots. Ensure efficient LINQ usage; avoid unnecessary iterations and allocations. For example, prefer .ToArray() or .ToList() to immediately execute queries when using the results multiple times.

16. What are the various ways to configure a .NET Core application, and how do you manage environment-specific configurations?

Configuration in .NET Core is flexible and can be achieved through several providers. Common methods include:

  • appsettings.json: The primary configuration file for storing general settings.
  • appsettings.{Environment}.json: Environment-specific settings, like appsettings.Development.json or appsettings.Production.json, that override the base appsettings.json in the respective environment. The ASPNETCORE_ENVIRONMENT environment variable determines which environment-specific file is loaded.
  • Environment Variables: Can override settings from appsettings.json and are often used for sensitive information or settings that vary greatly between deployments.
  • Command-line arguments: Can override settings, useful for one-time configurations or passing specific values during application startup.
  • User Secrets: Used only in development to store sensitive information, preventing it from being committed to source control.
  • Azure Key Vault: Can retrieve configuration directly from Azure Key Vault in Azure environments, including secrets.

Environment-specific configurations are managed by naming convention (appsettings.{Environment}.json) and leveraging the ASPNETCORE_ENVIRONMENT environment variable. The .NET runtime automatically loads the appropriate configuration file based on this variable. We can access configuration values using the IConfiguration interface. For example, Configuration["SettingName"] or through strongly-typed options classes configured via services.Configure<MyOptions>(Configuration.GetSection("MyOptions")).

17. How does the .NET Core runtime handle cross-platform compatibility, and what are some potential challenges when deploying to different operating systems?

.NET Core achieves cross-platform compatibility primarily through .NET Runtime implementing the .NET Standard Library and building platform-specific implementations. The .NET Standard defines a consistent set of APIs that can be used across different .NET implementations (like .NET Framework, .NET Core, and Xamarin). When you build a .NET Core application, it targets a specific .NET Standard version or a specific platform (like net6.0-windows). The .NET Runtime contains the components for garbage collection, JIT compilation and base class libraries and provides the services required to execute the application.

Potential challenges when deploying to different operating systems include: platform-specific dependencies (e.g., Windows-only libraries), differences in file system paths (e.g., / vs \), varying system calls, and the need to install the appropriate .NET Runtime on the target machine. You might also need to consider different architectures (x86, x64, ARM). Resolving native dependencies often involves conditional compilation or platform-specific NuGet packages. Utilizing containerization (like Docker) can alleviate deployment inconsistencies.

18. What are Span<T> and Memory<T> in .NET Core, and what problems do they solve when dealing with memory management and data processing?

Spanand Memoryare value-type structures introduced in .NET Core to provide a safe and efficient way to work with contiguous regions of memory. Spanis a ref-like struct representing a contiguous region of arbitrary memory, while Memoryis a struct that can wrap both managed and unmanaged memory. They help avoid unnecessary memory allocations and copies when working with arrays, strings, and other data structures.

These types address problems such as:

  • Performance: They allow direct access to memory without the overhead of creating new arrays or strings.
  • Memory Allocation: They reduce the need for frequent memory allocations and garbage collections, leading to better performance.
  • Safety: They enforce bounds checking and prevent memory corruption through the use of ref semantics and restrictions on how they can be used.
  • Flexibility: They can represent different memory sources, including arrays, strings, and unmanaged memory, enabling a unified approach to memory manipulation. For example:
ReadOnlySpan<byte> bytes = new byte[] { 1, 2, 3, 4, 5 };
ReadOnlySpan<byte> slice = bytes.Slice(1, 3); // slice now represents {2, 3, 4} without copying the underlying data

19. Describe the role of logging frameworks (e.g., Serilog, NLog) in .NET Core, and how you would configure structured logging in your applications.

Logging frameworks like Serilog and NLog provide a standardized and configurable way to record events and diagnostic information in .NET Core applications. They offer features such as:

  • Structured logging: Logging data as key-value pairs instead of plain text, making it easier to query and analyze logs.
  • Multiple sinks: Writing logs to various destinations (console, file, database, cloud services).
  • Log levels: Assigning severity levels (e.g., Debug, Information, Warning, Error, Fatal) to control which events are logged.
  • Extensibility: Allowing custom formatters, filters, and sinks.

To configure structured logging, you would typically install the relevant NuGet packages (e.g., Serilog.AspNetCore, Serilog.Sinks.Console). Then, in Program.cs or Startup.cs, you'd configure the logger, specifying sinks, minimum log level, and output templates. For example, with Serilog:

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Information()
    .WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
    .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day)
    .CreateLogger();

builder.Host.UseSerilog();

This sets up Serilog to log to the console and a file, using a specified output template for structured logging and daily rolling files.

20. How do you implement unit testing and integration testing in .NET Core, and what testing frameworks do you prefer (e.g., xUnit, NUnit)?

In .NET Core, unit testing typically involves using a testing framework like xUnit or NUnit alongside a mocking library such as Moq. You'd write tests to verify individual methods or classes in isolation. For example, using xUnit, you'd install the xunit and xunit.runner.visualstudio NuGet packages. A test would look something like:

[Fact]
public void MyMethod_ShouldReturnTrue()
{
    // Arrange
    var myObject = new MyClass();

    // Act
    bool result = myObject.MyMethod();

    // Assert
    Assert.True(result);
}

Integration testing verifies the interaction between different parts of the application or external systems. It can also use xUnit or NUnit. However, instead of mocking external dependencies, you'd usually work with the real components or a test database. I generally prefer xUnit for its simplicity and focus on facts over theories, but NUnit is also a viable option offering more features out of the box. Both are well-supported in the .NET Core ecosystem.

21. Explain the concept of minimal APIs in .NET 6+ and how they differ from traditional controller-based APIs.

Minimal APIs in .NET 6+ offer a streamlined approach to building HTTP APIs with less boilerplate code compared to traditional controller-based APIs. Instead of defining controllers and actions, you directly map routes to handler functions within the Program.cs file (or a similar setup). This results in a more concise and focused code structure, especially suitable for smaller APIs or microservices.

The key differences lie in:

  • Code Volume: Minimal APIs significantly reduce the amount of code required.

  • Structure: They eliminate the need for separate controller classes, integrating route handling directly into the application's startup.

  • Flexibility: Both approaches offer flexibility, but minimal APIs can be faster for simple scenarios while controllers provide better structure for larger, more complex projects. Here is an example of a minimal API route:

    app.MapGet("/hello", () => "Hello World!");
    

22. Describe how you would implement background tasks in a .NET Core application, considering options like `IHostedService` and Hangfire.

To implement background tasks in a .NET Core application, I'd consider a few options. IHostedService is a lightweight approach suitable for simple, in-process tasks. I'd create a class implementing IHostedService and register it in the ConfigureServices method of Startup.cs. The StartAsync method would contain the logic to start the background process (e.g., using a Task.Run or a Timer), and StopAsync would handle graceful shutdown. For more complex scenarios or tasks that require persistence and reliability, I'd opt for Hangfire. It provides features like job scheduling, retry mechanisms, and a dashboard for monitoring. Implementing it involves installing the Hangfire NuGet package, configuring the storage (e.g., SQL Server), and then scheduling jobs using BackgroundJob.Enqueue or RecurringJob.AddOrUpdate. Hangfire handles the execution and persistence of these jobs out of process.

23. How can you use reflection in .NET Core to dynamically inspect and manipulate types and members at runtime?

Reflection in .NET Core allows you to examine and modify types, properties, methods, events, and other members at runtime. You can use the System.Reflection namespace to load assemblies, discover types within them, and then create instances of those types. For example, Assembly.LoadFrom("MyAssembly.dll") loads an assembly. Then assembly.GetType("MyNamespace.MyClass") retrieves a specific type. Activator.CreateInstance(type) creates an instance of the class. You can then use type.GetMethod("MyMethod") to get a method, and method.Invoke(instance, null) to invoke it.

Reflection is useful for scenarios like plugin architectures, object-relational mappers (ORMs), dependency injection containers, and dynamic code generation. It should be used judiciously as it can impact performance due to the overhead of runtime type resolution and also reduces compile-time type safety. Use the appropriate BindingFlags in the Get methods (e.g., GetMethods, GetProperties, GetFields) to filter based on accessibility (public, private, etc.) and instance vs. static members. For example:

Type myType = typeof(MyClass);
PropertyInfo myProperty = myType.GetProperty("MyProperty", BindingFlags.Public | BindingFlags.Instance);

24. Discuss the various options for deploying .NET Core applications to cloud platforms like Azure and AWS.

For deploying .NET Core applications to cloud platforms like Azure and AWS, several options exist. Azure offers options like Azure App Service (Platform-as-a-Service, PaaS), Azure Kubernetes Service (AKS) for container orchestration, Azure Virtual Machines (Infrastructure-as-a-Service, IaaS), and Azure Functions (serverless). Each option provides a different level of control and management responsibility. Similarly, AWS provides Elastic Beanstalk (PaaS), Elastic Container Service (ECS) and Elastic Kubernetes Service (EKS) for containerization, EC2 instances (IaaS), and AWS Lambda (serverless).

The choice depends on factors such as application complexity, scalability needs, desired level of control, and cost considerations. PaaS solutions like App Service and Elastic Beanstalk are easier to manage but offer less control, while IaaS solutions like VMs and EC2 provide full control but require more management overhead. Containerization through ECS, EKS or AKS allows for portability and scalability. Serverless functions (Azure Functions or AWS Lambda) are suitable for event-driven applications. Consider also factors like CI/CD integration with services like Azure DevOps or AWS CodePipeline for automated deployments.

25. How would you implement a CQRS (Command Query Responsibility Segregation) pattern in a .NET Core application?

Implementing CQRS in a .NET Core application involves separating the read (query) and write (command) operations into distinct models. First, define separate interfaces and classes for commands (e.g., CreateProductCommand, UpdateProductCommand) and queries (e.g., GetProductByIdQuery, GetAllProductsQuery). These commands and queries should encapsulate the data required for their respective operations. Then, implement command handlers to execute commands and query handlers to retrieve data. Dependency injection is crucial to register these handlers. For example: services.AddScoped<ICommandHandler<CreateProductCommand>, CreateProductCommandHandler>(); and services.AddScoped<IQueryHandler<GetProductByIdQuery, Product>, GetProductByIdQueryHandler>();. Finally, use a mediator pattern (e.g., using MediatR library) to route commands and queries to their corresponding handlers. This allows decoupling the application's layers. Data access for reads can be optimized for querying, potentially using a read-only database replica or a denormalized data structure. Writes should focus on maintaining data integrity and consistency in the primary data store. This separation allows for independent scaling and optimization of read and write operations.

Example using MediatR:

public class CreateProductCommand : IRequest<Guid>
{
 public string Name { get; set; }
 public decimal Price { get; set; }
}

public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, Guid>
{
 private readonly IProductRepository _productRepository;

 public CreateProductCommandHandler(IProductRepository productRepository)
 {
 _productRepository = productRepository;
 }

 public async Task<Guid> Handle(CreateProductCommand request, CancellationToken cancellationToken)
 {
 var product = new Product { Id = Guid.NewGuid(), Name = request.Name, Price = request.Price };
 await _productRepository.AddAsync(product);
 return product.Id;
 }
}

26. Explain the purpose of the `ConfigureAwait(false)` method in asynchronous .NET Core code.

ConfigureAwait(false) instructs the await operator to avoid attempting to marshal the continuation back to the original synchronization context or task scheduler. This is crucial in libraries or non-UI applications to prevent deadlocks or performance bottlenecks. By using ConfigureAwait(false), the code after the await will execute on a thread pool thread, rather than trying to resume on the original context (like a UI thread). This avoids potential deadlocks where the UI thread is waiting for the async operation to complete, while the async operation is trying to post back to the UI thread.

In essence, ConfigureAwait(false) enhances performance and prevents deadlocks by decoupling the continuation from the captured context. For example:

await DoSomethingAsync().ConfigureAwait(false);
// Code here will run on a thread pool thread.

27. Describe the differences between authorization and authentication in ASP.NET Core and how to implement custom authorization policies.

Authentication verifies who a user is, while authorization determines what they are allowed to do. Authentication confirms the user's identity (e.g., through username/password or OAuth), and authorization then uses that identity to decide if the user has permission to access a specific resource or perform a certain action.

Custom authorization policies in ASP.NET Core can be implemented using AuthorizationPolicyBuilder. You define requirements (e.g., a specific claim, a role) and handlers that evaluate if the user meets those requirements. Policies can then be applied globally or to specific controllers/actions using the [Authorize] attribute. For example:

services.AddAuthorization(options =>
{
 options.AddPolicy("AdminOnly", policy =>
  policy.RequireRole("Admin"));
});

And then, [Authorize(Policy = "AdminOnly")].

28. How do you handle data migrations in .NET Core using Entity Framework Core?

Data migrations in .NET Core with Entity Framework Core are typically handled using the dotnet ef migrations command-line tools. First, ensure you have the Entity Framework Core tools installed: dotnet tool install --global dotnet-ef. Then, you create a migration with dotnet ef migrations add MigrationName. This scaffolds a new migration containing the changes to your data model. The migration includes Up() and Down() methods to apply and revert the changes, respectively.

To apply the migration to your database, you use the command dotnet ef database update. This command executes any pending migrations. You can also specify a target migration to apply up to a specific point. In production, migrations are often applied during deployment, ensuring the database schema is synchronized with the application's data model. You might consider using idempotent scripts for critical schema changes to avoid issues if a migration is interrupted.

29. What are the benefits of using source generators in .NET Core, and how can they improve performance and reduce boilerplate code?

Source generators in .NET Core offer several benefits. They allow you to generate code at compile time, which can improve performance by moving certain computations from runtime to compile time. This reduces the runtime overhead, leading to faster application startup and execution. Source generators also enable you to analyze code and generate additional code based on the analysis.

They reduce boilerplate code by automatically creating repetitive code segments. For example, you can generate code for implementing INotifyPropertyChanged or creating DTOs based on database schemas. This reduces the amount of code you need to write manually, improving developer productivity and reducing the risk of errors. This also promotes more maintainable and cleaner codebases. Using source generators is better than reflection at runtime because the code is generated at compile time. Also, source generators can utilize code analysis and Syntax Trees to get information about code, that might not be available at runtime.

30. Explain how to use OpenTelemetry in .NET Core for distributed tracing and monitoring.

To use OpenTelemetry in .NET Core for distributed tracing and monitoring, you'll typically install the necessary NuGet packages such as OpenTelemetry.Exporter.Jaeger, OpenTelemetry.Extensions.Hosting, OpenTelemetry.Instrumentation.AspNetCore, and OpenTelemetry.Instrumentation.SqlClient. Then, in your Program.cs file, configure the OpenTelemetry services. This involves adding OpenTelemetry to the service collection, configuring a trace provider, and setting up exporters like Jaeger or Zipkin to send the telemetry data. Instrumentation libraries automatically collect data from libraries like ASP.NET Core and SqlClient.

For example:

builder.Services.AddOpenTelemetryTracing(tracerProviderBuilder =>
{
    tracerProviderBuilder
        .AddSource("MyApplication")
        .AddAspNetCoreInstrumentation()
        .AddSqlClientInstrumentation()
        .AddJaegerExporter();
});

After configuration, OpenTelemetry automatically captures traces, metrics, and logs from your application, providing insights into request flow, performance, and errors. Remember to configure your exporter's endpoint to point to your tracing backend.

.NET Core MCQ

Question 1.

In .NET, what is the key difference between using async Task and async void as the return type of an asynchronous method?

Options:
Question 2.

In .NET, what is the primary difference between IEnumerable and IQueryable when used with LINQ?

Options:
Question 3.

Which of the following best describes the relationship between Dependency Injection (DI) and Inversion of Control (IoC) in .NET Core?

Options:
Question 4.

In .NET, what is the primary difference between the Dispose() method (implementing IDisposable) and the Finalize() method (destructor)?

  • A) Dispose() is called by the garbage collector, while Finalize() is called explicitly by the user.
  • B) Dispose() is used for deterministic cleanup of resources, while Finalize() is used for non-deterministic cleanup and as a last resort.
  • C) Dispose() is automatically called when an object goes out of scope, while Finalize() requires explicit invocation.
  • D) Dispose() is used to release memory, while Finalize() is used to release unmanaged resources.
Options:
Question 5.

What is the primary difference between the Action and Func delegates in .NET?

Options:
Question 6.

What is the key difference between an abstract class and an interface in C#?

Options:
Question 7.

What is the key difference between using var, dynamic, and object when declaring a variable in C#?

Options:
Question 8.

What is the key difference between using Task.Run() and Task.Factory.StartNew() in .NET?

Options:
Question 9.

What is the key difference between using FirstOrDefault() and SingleOrDefault() in LINQ queries?

  • A) FirstOrDefault() returns the first element or a default value if the sequence is empty, while SingleOrDefault() throws an exception if the sequence is empty.
  • B) FirstOrDefault() throws an exception if the sequence contains more than one element, while SingleOrDefault() returns the first element or a default value if the sequence is empty or contains only one element.
  • C) FirstOrDefault() returns the first element or a default value if the sequence is empty, while SingleOrDefault() returns the only element or a default value if the sequence is empty but throws an exception if the sequence contains more than one element.
  • D) FirstOrDefault() and SingleOrDefault() are functionally equivalent and can be used interchangeably in all scenarios.
Options:
Question 10.

In C#, what is the key difference between using the == operator and the .Equals() method when comparing two objects?

Options:
Question 11.

What is the primary difference between HttpClient and WebClient in .NET?

Options:
Question 12.

In .NET asynchronous programming, what is the primary benefit of using .ConfigureAwait(false)?

Options:
Question 13.

In ASP.NET Core, what is the key difference between the [Authorize] and [AllowAnonymous] attributes?

Options:
Question 14.

In ASP.NET Core, what is the key difference between using IActionResult and ActionResult<T> as a return type for a controller action?

Options:
Question 15.

In ASP.NET Core, what is the primary difference between IMemoryCache and IDistributedCache?

Options:
Question 16.

In ASP.NET Core, what is the primary difference between using services.AddTransient(), services.AddScoped(), and services.AddSingleton() when registering services in the ConfigureServices method?

Options:
Question 17.

What is the primary difference between using string and StringBuilder classes for string manipulation in .NET, and when would you prefer one over the other?

Options:
Question 18.

What is the primary difference between using ToList() and AsEnumerable() in LINQ?

Options:
Question 19.

What is the key difference between calling an async method and calling a synchronous method in .NET?

Options:
Question 20.

What is the key difference between using yield return and return within an iterator method in C#?

Options:
Question 21.

In .NET, what is the primary difference between using Thread and Task for asynchronous operations?

Options:
Question 22.

What is the key difference between a Semaphore and a Mutex in .NET?

Options:
Question 23.

What is the key difference between a Delegate and an Event in C#?

Options:
Question 24.

In ASP.NET Core MVC, what is the key difference between ViewBag, ViewData, and TempData for passing data from a controller to a view?

Options:
Question 25.

What is the primary difference between using a using statement and directly implementing the IDisposable interface in C#?

Options:

Which .NET Core skills should you evaluate during the interview phase?

You can't fully gauge a candidate's .NET Core prowess in a single interview. However, focusing on a few key skills will give you a solid understanding of their capabilities. These skills represent the core competencies needed to succeed in a .NET Core role.

Which .NET Core skills should you evaluate during the interview phase?

C# Fundamentals

Assess C# proficiency with an online test. Adaface's C# test includes questions on syntax, data structures, and common C# concepts.

To test their grasp of C# fundamentals, pose a question about inheritance.

Explain the difference between abstract classes and interfaces in C# and when you would use one over the other.

Look for a clear understanding of the purpose of each construct. The candidate should explain that an abstract class can have method implementations and state, while an interface only defines a contract.

ASP.NET Core

Gauge their ASP.NET Core skills with targeted MCQs. You can use Adaface's ASP.NET test to filter candidates based on their knowledge of ASP.NET Core concepts.

To assess their understanding of ASP.NET Core, ask about middleware.

Describe what middleware is in ASP.NET Core and provide an example of a custom middleware you might create.

The candidate should be able to explain that middleware components sit in the HTTP request pipeline. They should also be able to give a plausible example of custom middleware, such as logging or authentication.

.NET Core Dependency Injection

You can efficiently evaluate a candidate's understanding of DI using a skills assessment test. While Adaface does not have a dedicated .NET Core DI test, questions related to DI principles might be present in our C#/.NET test.

A good question to ask is about the benefits of DI.

What are the benefits of using Dependency Injection in .NET Core applications?

The candidate should mention improved testability, loose coupling, and increased maintainability. They should also demonstrate an understanding of how DI promotes the SOLID principles.

3 Tips for Using .NET Core Interview Questions

Before you start putting these .NET Core interview questions to use, here are a few tips to help you maximize their effectiveness. These insights will help you refine your approach and ensure you get the most value from your interviews.

1. Leverage Skills Assessments for Enhanced Candidate Screening

Skills assessments are invaluable tools for objectively evaluating a candidate's proficiency. Incorporating them early in your hiring process significantly streamlines the selection process, helping you focus on candidates with the most promising skill sets.

For .NET Core roles, consider using assessments that evaluate C#, .NET, and related technologies like Entity Framework or ASP.NET MVC. Adaface offers a range of .NET online tests, including a .NET online test, C# online test, and Entity Framework online test to assess these skills.

By using these skills assessments, you can easily pinpoint the areas where candidates excel or need improvement. This allows you to tailor your interview questions to focus on specific strengths and weaknesses, leading to a more insightful and productive conversation.

2. Strategically Outline Key Interview Questions

Time is of the essence during interviews, so focus on asking a curated set of high-impact questions. Compiling the right mix of questions helps you efficiently evaluate candidates on the most important aspects of the role.

Consider supplementing your .NET Core questions with inquiries about related technologies like SQL or front-end frameworks. You may find our C# interview questions page helpful, as well as our Javascript interview questions page to explore candidates’ related skillsets.

By strategically choosing your interview questions, you'll be able to quickly gauge a candidate's suitability and make well-informed hiring decisions. This maximizes your interview time and helps avoid overlooking crucial skills.

3. Master the Art of Asking Follow-Up Questions

Simply asking interview questions isn't always enough to uncover a candidate's true abilities. Asking the right follow-up questions is crucial for validating their knowledge and understanding the depth of their expertise.

For example, if a candidate explains the concept of dependency injection, a follow-up could be: "Can you describe a scenario where using dependency injection would significantly improve the maintainability of a .NET Core application?" This probes beyond theoretical knowledge and reveals practical application skills and candidate depth.

Evaluate .NET Candidates with Precision: Skills Tests & Targeted Interview Questions

Looking to hire top .NET talent? Ensuring candidates possess the necessary skills is paramount. The most effective way to accurately gauge their abilities is through dedicated skills tests. Explore Adaface's range of .NET assessments, including our .NET Online Test and C# Online Test, to identify candidates with proven expertise.

Once you've pinpointed promising applicants using skills tests, streamline your hiring process by focusing on the most qualified individuals. Shortlist the top performers and invite them for targeted interviews. Ready to get started? Sign up and transform your .NET hiring today.

.NET Online Test

40 mins | 10 MCQs and 1 Coding Question
The Dot Net Online Test uses scenario-based MCQs to evaluate candidates on their proficiency in working with Microsoft .NET technologies, including the .NET framework, C#, and ASP.NET. The test assesses candidates' ability to write .NET code, create and manage .NET projects, use .NET libraries and frameworks, and develop web applications using ASP.NET.
Try .NET Online Test

Download .NET Core interview questions template in multiple formats

.NET Core Interview Questions FAQs

What are some common .NET Core interview questions for freshers?

Common questions for freshers might cover basic concepts like the .NET Core framework, C# syntax, and object-oriented programming principles.

How can I effectively evaluate experienced .NET Core developers?

For experienced developers, focus on questions related to architectural patterns, performance optimization, dependency injection, and their experience with various .NET Core libraries and tools.

What key areas should I cover during a .NET Core interview?

Key areas include understanding of ASP.NET Core, Entity Framework Core, dependency injection, middleware, and experience with testing and deployment strategies.

What are some tips for conducting a successful .NET Core interview?

Some tips are to use a mix of theoretical and practical questions, have candidates write code, and ask about their experience with real-world projects.

How can skills tests complement .NET Core interview questions?

Skills tests provide a standardized way to assess a candidate's coding abilities and problem-solving skills, helping you objectively compare candidates and identify top talent.

Related posts

Free resources

customers across world
Join 1200+ companies in 80+ countries.
Try the most candidate friendly skills assessment tool today.
g2 badges
logo
40 min tests.
No trick questions.
Accurate shortlisting.