[Part 5] If You Can Answer These Additional 7 Questions Correctly, You’re Decent at .NET

ssukhpinder

Sukhpinder Singh

Posted on October 1, 2024

[Part 5] If You Can Answer These Additional 7 Questions Correctly, You’re Decent at .NET

Enhance your .NET knowledge with Part 5 of our interview series! Get detailed answers to complex questions on topics like IHostedService, concurrent collections, and more.

Hello .NET Enthusiasts,

Welcome to Part 5 of our C# knowledge test challenge! Please go through the series here.
C# .Net Interview Series

The next set of questions will test your knowledge of advanced .NET concepts and practices.

1. Differences Between ToList() on IEnumerable and IQueryable

IEnumerable.ToList()

  • Pulls all the data into memory, then runs the ToList() operation in memory.

  • Very helpful when dealing with in-memory collections, or when you’ve already pulled the data.

  • Massive performance overhead if dealing with large datasets; it’s pulling everything into memory.

Example:

IEnumerable<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
List<int> numberList = numbers.ToList();  // In-memory operation
Enter fullscreen mode Exit fullscreen mode

IQueryable.ToList()

  • It translates the query into SQL and runs it against the database. Results only are loaded into memory.

  • More efficient for querying large datasets because it leaves the querying capabilities to the database server.

  • The ToList() method executes the query directly and materializes the result into a list.

Example

IQueryable<int> numbers = dbContext.Numbers.Where(n => n > 3);
List<int> numberList = numbers.ToList();  // Database query
Enter fullscreen mode Exit fullscreen mode

Use IQueryable.ToList() for querying data from databases, and IEnumerable.ToList() for in-memory collections.

2. Global Exception Handling Middleware in ASP.NET Core

Global Exception Handling Middleware

  • ASP.NET Core middleware facilitates the global handling of exceptions, which means a universal mechanism to handle faults.

  • It will catch unhandled exceptions, log them, and return a user-friendly error response.

Example: Create Custom Exception Handling Middleware

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.ContentType = "application/json";
            context.Response.StatusCode = StatusCodes.Status500InternalServerError;
            await context.Response.WriteAsync("An unexpected error occurred.");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Register Middleware in Startup.cs

public void Configure(IApplicationBuilder app)
{
    app.UseMiddleware<ExceptionHandlingMiddleware>();
    app.UseRouting();
    app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
Enter fullscreen mode Exit fullscreen mode

The central error-handling middleware contains error handling in one place and offers consistency in error response throughout the application.

3. Concurrency with ConcurrentDictionary

ConcurrentDictionary

  • This is a thread-safe collection of pairs of key-value that provides readability as well as writability by several threads without explicit locks.

  • It is also thread-safe with fine-grained locking and lock-free implementations. So, the library can be used in any multi-threading application.

Use Cases

  • Best suited for when multiple threads are accessing and updating the same dictionary concurrently.

  • It supports high performance, even for thread-safe applications where using the common caching mechanism or shared state is prevalent.

Example:

ConcurrentDictionary<int, string> dictionary = new ConcurrentDictionary<int, string>();

// Add items
dictionary.TryAdd(1, "Value1");

// Update an item
dictionary[1] = "UpdatedValue1";

// Retrieve an item
string value = dictionary.GetValueOrDefault(1);
Enter fullscreen mode Exit fullscreen mode

ConcurrentDictionary Is highly suitable for concurrent operation, when thread safety and performance prevail.

4. Configuration Providers in ASP.NET Core

Configuration Providers

  • JSON Configuration Provider: Reads configuration from appsettings.json files.

  • Environment Variables Provider: Reads configuration from environment variables.

  • Command-Line Provider: Reads configuration from command-line arguments.

  • In-Memory Provider: Uses an in-memory configuration source, typically for testing.

Example: Configure Multiple Providers in Startup.cs

public void ConfigureAppConfiguration(IConfigurationBuilder builder)
{
    builder.AddJsonFile("appsettings.json")
           .AddEnvironmentVariables()
           .AddCommandLine(args);
}
Enter fullscreen mode Exit fullscreen mode

Access Configuration in Code:

public class MyService
{
    private readonly IConfiguration _configuration;
    public MyService(IConfiguration configuration)
    {
        _configuration = configuration;
    }
    public string GetSetting()
    {
        return _configuration["MySetting"];
    }
}
Enter fullscreen mode Exit fullscreen mode

Summary:

ASP.NET Core configuration providers make it possible for you to dynamically and flexibly manage application settings from multiple sources, such as files, environment variables, or in-memory collections.

5. Lazy Initialization with Lazy

Lazy

  • The object is created when it must be used; thus, its creation is postponed to the time when it must be used.

  • The object is created only once. By default, lazy objects are thread-safe.

Use Cases:

  • Resource-intensive object creation: The creation of objects is expensive, and there is no need to create an object beforehand.

  • Useful for performance enhancement because it includes no unnecessary initialization of objects that are not used.

Example:

public class Resource
{
    public Resource() { /* Expensive initialization */ }
}

public class MyService
{
    private readonly Lazy<Resource> _resource = new Lazy<Resource>(() => new Resource());
    public Resource GetResource()
    {
        return _resource.Value;  // Resource is created only when needed
    }
}
Enter fullscreen mode Exit fullscreen mode

Lazy relieves overhead due to resource-consuming object creation, as initialization only takes place when needed.

6. Dependency Injection Scopes in ASP.NET Core

Dependency Injection Scopes:

  • Transient: Created every time they are requested. Ideal for lightweight, stateless services.

  • Scoped: Created once per request or scope. Suitable for services that need to hold a state in one request.

  • Singleton: Created only once and it's available throughout your application. Suitable for services that hold a state over requests.

Example: Registering Services in Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<ITransientService, TransientService>();
    services.AddScoped<IScopedService, ScopedService>();
    services.AddSingleton<ISingletonService, SingletonService>();
}
Enter fullscreen mode Exit fullscreen mode

Using Scoped Services in a Controller:

public class MyController : Controller
{
    private readonly IScopedService _scopedService;
    public MyController(IScopedService scopedService)
    {
        _scopedService = scopedService;
    }
    public IActionResult Index()
    {
        // Use _scopedService
        return View();
    }
}
Enter fullscreen mode Exit fullscreen mode

Exploring the range of services in ASP.NET Core: services play correctly with the different kinds of lifetimes, from a request-scoped to an application-wide singleton scope.

7. Using IHostedService for Background Tasks

IHostedService

  • Provides an abstraction on which you can execute background services or tasks within an ASP.NET Core application.

  • Allows for long or periodically running jobs in the background.

Example: Implementing a Background Service

public class MyBackgroundService : BackgroundService
{
    private readonly ILogger<MyBackgroundService> _logger;

    public MyBackgroundService(ILogger<MyBackgroundService> logger)
    {
        _logger = logger;
    }
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogInformation("Background service is running.");
            await Task.Delay(10000, stoppingToken);  // Delay 10 seconds
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Registering the Background Service Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddHostedService<MyBackgroundService>();
}
Enter fullscreen mode Exit fullscreen mode

IHostedService is useful to run some scheduled jobs or periodic operations in ASP.NET Core applications.

So, how did you do?

If you know the concept with confidence and understand the code examples, you’re likely well-versed in .NET.

Let’s keep the conversation going and help each other grow as .NET professionals.

Happy coding!

💖 💪 🙅 🚩
ssukhpinder
Sukhpinder Singh

Posted on October 1, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related