Tuesday, October 22, 2024

Part 2 - How to become Professional Programmer (Answers)

 Let's tackle these ASP.NET Core questions topic by topic:

1. ASP.NET Core Basics

Q1: What are the key differences between ASP.NET and ASP.NET Core?

  • Answer: ASP.NET Core is a cross-platform, high-performance framework, while ASP.NET (the older version) is Windows-only. ASP.NET Core is designed for cloud-based and internet-connected applications, with a modular and lightweight architecture. Key differences include:
    • Cross-platform support (Windows, macOS, Linux).
    • Built-in dependency injection.
    • Unified framework for MVC and Web API.
    • No longer depends on System.Web, resulting in better performance.

Q2: How does middleware work in the ASP.NET Core request pipeline?

  • Answer: Middleware components are assembled into a pipeline that handles HTTP requests. Each middleware component:
    1. Can handle an incoming request.
    2. Can decide whether to pass the request to the next middleware in the pipeline.
    3. Can perform operations after the downstream middleware has completed processing. Middleware is configured in Startup.cs via the Configure method.

Q3: What is the purpose of Startup.cs in an ASP.NET Core application?

  • Answer: Startup.cs is the entry point of an ASP.NET Core application and is responsible for:
    • Configuring services (via ConfigureServices method).
    • Configuring the HTTP request pipeline (via Configure method). It defines how the application behaves and responds to HTTP requests.

Q4: How can you configure dependency injection in ASP.NET Core?

  • Answer: Dependency injection is configured in the ConfigureServices method in Startup.cs. Services are added using AddSingleton, AddScoped, or AddTransient methods depending on the desired lifetime (singleton, scoped, transient). Example:
1
services.AddScoped<IMyService, MyService>();

Q5: Explain the role of appsettings.json and how to read configuration values from it.

  • Answer: appsettings.json is a file used to store configuration settings in JSON format, including database connections, API keys, and environment-specific configurations. These settings can be accessed using the IConfiguration interface:
1
2
3
4
5
6
7
8
9
public class MyClass {
    private readonly IConfiguration _config;
    public MyClass(IConfiguration config) {
        _config = config;
    }
    public void PrintConfigValue() {
        var myValue = _config["MyKey"];
    }
}

2. Routing and Endpoints

Q1: How does attribute routing differ from conventional routing in ASP.NET Core?

  • Answer: Attribute routing uses attributes on controller actions to define routes, while conventional routing is defined globally in the Startup.cs file. Attribute routing provides more control at the individual action level:
1
2
[Route("products/{id}")]
public IActionResult GetProduct(int id) { }


Q2: How can you define custom route constraints in ASP.NET Core?

  • Answer: Custom route constraints can be defined using regular expressions or by implementing IRouteConstraint. Example using a regular expression:
1
2
[Route("products/{id:regex(^\\d{{4}}$)}")]
public IActionResult GetProduct(int id) { }


Q3: What is endpoint routing, and how does it improve routing in ASP.NET Core 3.0+?

  • Answer: Endpoint routing decouples routing decisions from middleware execution. It improves performance by determining the endpoint before middleware is invoked, allowing middleware components to interact with the selected endpoint more efficiently.

Q4: How do you create and use route parameters in an MVC action method?

  • Answer: Route parameters can be used to capture values from the URL and pass them to the action method. For example:

1
2
3
4
[Route("products/{id}")]
public IActionResult GetProduct(int id) {
    // id is captured from the route and passed as an argument
}


Q5: How can you handle route-specific errors in ASP.NET Core?

  • Answer: Route-specific errors can be handled using exception filters, middleware, or custom error pages. For example, use UseExceptionHandler middleware for global exception handling:
1
app.UseExceptionHandler("/Home/Error");

3. Model Binding and Validation

Q1: How does ASP.NET Core bind form data to controller action parameters?

  • Answer: ASP.NET Core uses model binding to map form data (from query strings, route data, and form posts) to action method parameters. It binds data to simple types (int, string) and complex types (classes).

Q2: What are the different ways to perform input validation in ASP.NET Core?

  • Answer: Input validation can be performed using:
    • Data Annotations (e.g., [Required], [Range], [EmailAddress]).
    • FluentValidation (a more flexible validation library).
    • Custom validation attributes or logic in the controller.

Q3: How can you create custom validation attributes in ASP.NET Core?

  • Answer: Custom validation attributes can be created by inheriting from ValidationAttribute and overriding the IsValid method:
1
2
3
4
5
6
public class CustomEmailAttribute : ValidationAttribute {
    protected override bool IsValid(object value) {
        var email = value as string;
        return email != null && email.EndsWith("@example.com");
    }
}

Q4: Explain how you would use FluentValidation in an ASP.NET Core project.

  • Answer: FluentValidation is used to create validation logic in a more fluent and customizable way. Install the FluentValidation.AspNetCore package, and create a validator:
1
2
3
4
5
public class ProductValidator : AbstractValidator<Product> {
    public ProductValidator() {
        RuleFor(p => p.Name).NotEmpty().WithMessage("Name is required.");
    }
}

Q5: How does model binding handle complex objects and collections?

  • Answer: ASP.NET Core can bind complex objects and collections by recursively binding properties. For example:
1
2
3
public IActionResult CreateOrder(Order order) {
    // ASP.NET Core binds nested objects like Order.Customer automatically
}


4. Dependency Injection (DI)

Q1: What are the different service lifetimes (Scoped, Transient, Singleton) in ASP.NET Core DI?

  • Answer:
    • Singleton: The service is created once and shared across the entire application lifetime.
    • Scoped: The service is created once per request (or scope) and shared within that request.
    • Transient: A new instance of the service is created every time it is requested.

Q2: How would you inject a service into a middleware?

  • Answer: To inject a service into middleware, use constructor injection or the Invoke method. The service must be registered in Startup.cs. Example:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class MyMiddleware {
    private readonly RequestDelegate _next;
    private readonly IMyService _myService;
    public MyMiddleware(RequestDelegate next, IMyService myService) {
        _next = next;
        _myService = myService;
    }
    public async Task Invoke(HttpContext context) {
        // Use the service
        await _next(context);
    }
}

Q3: Explain how you can implement multiple constructors in a class using DI.

  • Answer: ASP.NET Core's DI system selects the constructor with the most parameters that it can resolve. If you have multiple constructors, ensure that at least one of them has all dependencies resolvable by DI. You can manually select a constructor by modifying the service registration.

Q4: How do you handle circular dependencies in ASP.NET Core DI?

  • Answer: Circular dependencies occur when two or more services depend on each other, leading to a deadlock. You can resolve this by:
    • Refactoring the code to remove circular dependencies.
    • Using lazy loading (Lazy<T> or Func<T>) to delay instantiation.

Q5: What is the benefit of using IServiceProvider in ASP.NET Core?

  • Answer: IServiceProvider is used to resolve services manually, typically in scenarios where DI isn't automatically handled (e.g., within middleware). It allows dynamic resolution of dependencies at runtime.

5. Middleware

Q1: How can you create a custom middleware component in ASP.NET Core?

  • Answer: Custom middleware can be created by implementing a class with an Invoke or InvokeAsync method, and registering it in the Startup.cs file. Example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class MyCustomMiddleware {
    private readonly RequestDelegate _next;
    public MyCustomMiddleware(RequestDelegate next) {
        _next = next;
    }
    public async Task Invoke(HttpContext context) {
        // Middleware logic here
        await _next(context);
    }
}

Q2: Explain the order of middleware execution in the ASP.NET Core pipeline.

  • Answer: Middleware components execute in the order they are registered in the Startup.Configure method. Each middleware can either:
    • Handle the request and prevent further processing.
    • Pass the request to the next middleware by calling _next(context).

Q3: What are the benefits of using the built-in UseExceptionHandler middleware?

  • Answer: UseExceptionHandler allows centralized handling of exceptions in ASP.NET Core. It ensures that any unhandled exceptions are caught and can be logged or redirected to a custom error page, improving user experience and simplifying error management.

Q4: How does the Run, Use, and Map methods differ in middleware configuration?

  • Answer:
    • Use: Registers a middleware and passes control to the next component in the pipeline.
    • Run: Registers a terminal middleware, meaning it handles the request and doesn’t call the next middleware.
    • Map: Branches the middleware pipeline based on the request path.

Q5: How would you implement middleware to handle request logging?

  • Answer: Create custom middleware to log request details (e.g., URL, headers) and register it in the pipeline:

1
2
3
4
5
public async Task Invoke(HttpContext context) {
    var request = context.Request;
    Console.WriteLine($"Request URL: {request.Path}");
    await _next(context);  // Call the next middleware
}

No comments:

Post a Comment