Core
Core
There are different ways of injecting the dependency (DI) - Constructor Dependency
Injection, Interface Dependency Injection, Method Parameter Dependency Injection, and
Setter Property Dependency Injection.
Middleware in ASP.NET Core is a powerful tool that allows you to add modular and
reusable components to your application's request/response pipeline. By using
middleware, you can handle cross-cutting concerns in a centralized and flexible way,
making it easier to maintain and extend your application over time
.Net Core --- Advanced QUESTIONS and ANSWERS
Output:
Hello app.Use
Hello app.Run
Synchronous programming in ASP.NET Core blocks the execution of source code until a task
is completed. In contrast, asynchronous programming allows the execution of code to
continue while a task is being processed in the background.
Asynchronous programming is useful for long-running operations that would otherwise block
the application's main thread, such as reading from a file or making a network request.
Asynchronous programming is typically achieved using the async and await keywords in C#.
The async keyword defines an asynchronous method, which can be called by other code and
will run in the background. The await keyword indicates that the calling code should wait for
the asynchronous method to complete before continuing.
class Test{
// requires using Microsoft.Extensions.Configuration;
Configuration = configuration;
Default configuration provider first load the values from appsettings.json and then from
appsettings.Environment.json file.
Environment specific values override the values from appsettings.json file. In development
environment appsettings.Development.json file values override the appsettings.json file
values, same apply to production environment.
You can also read the appsettings.json values using options pattern described Read values
from appsettings.json file.
ASP.NET Core, middleware and filters are two mechanisms used for processing requests and
responses.
Middleware is a software component between the web server (like Apache) and the
application and processes requests and responses during the application development.
Middleware can be used for various tasks, such as authentication, logging, and error
handling. Middleware is executed in a pipeline, and each middleware component can modify
the request or response before passing it to the next component in the pipeline.
Conversely, filters are used to perform cross-cutting concerns on controllers and actions in an
MVC application. Filters can be used for authorization, validation, and caching tasks. Filters
are executed before and after the action method, and they can modify the request or
response or short-circuit the request processing if necessary.
The main difference between middleware and filters is their scope and the way they are
executed. Middleware is executed globally and can be used for any request or response. In
contrast, filters are executed only for specific controllers or actions and can be used to modify
the request or response before or after the action method.
The IHostedService interface defines two methods: StartAsync and StopAsync. The
StartAsync method is called when the application starts and is used to start the background
task or service. The StopAsync method is called when the application is stopped or restarted.
It’s used to stop the background task or service, releasing acquired resources.
Dependency injection is a design pattern of ASP.NET Core that’s handled by the built-in
dependency injection container. This container can register and resolve dependencies,
typically defined as interfaces implemented by concrete classes.
There are several ways to configure the container, including the ConfigureServices method in
the Startup class (the entry point of a .NET application), attributes on classes and properties,
and the service provider itself. ASP.NET Core supports constructor, property, and method
injection, allowing dependencies to be dynamically injected into methods at runtime.
Dependency Injection example. A class can use a direct dependency instance as below.
Public class A {
MyDependency dep = new MyDependency();
If you want to replace 'MyDependency' with a different implementation then the class
must be modified.
It's difficult to Unit Test.
If MyDependency class has dependencies then it must be configured by class. If
Multiple classes have dependency on 'MyDependency', the code becomes scattered.
How do you secure your .NET Core applications? What is the different authentication
and authorization mechanisms available.
To secure .NET Core applications, implement authentication and authorization mechanisms.
Authentication verifies user identity, while authorization determines access rights.
1. Cookie-based: Use ASP.NET Core Identity for storing user information and managing
authentication via cookies.
2. Token-based: Utilize JSON Web Tokens (JWT) to authenticate users without server-
side sessions.
3. OAuth 2.0/OpenID Connect: Integrate with external providers like Google or
Facebook using these protocols.
4. Windows Authentication: Employ this mechanism in intranet scenarios where Active
Directory is available.
5. Certificate Authentication: Authenticate clients based on X.509 certificates, suitable
for mutual TLS scenarios.
For authorization:
1. Role-based: Grant access based on predefined roles assigned to users.
2. Claims-based: Evaluate claims within a user’s identity to determine permissions.
3. Policy-based: Define custom policies with specific requirements, evaluated by the
Authorization Middleware.
How do you implement exception handling and logging in .NET Core applications?
In .NET Core applications, exception handling and logging are implemented using middleware
components. Middleware is a chain of components that handle requests and responses in the
application pipeline.
For exception handling, use the built-in “UseExceptionHandler” middleware to catch
exceptions and provide custom error pages or responses. Configure it in the “Startup.cs” file
within the “Configure” method:
app.UseExceptionHandler(options =>
{
options.Run(async context =>
{
// Custom error response logic here
});
});
_logger = logger;
What are the various ways to manage errors in .NET Core for web APIs?
There are mainly four ways to manage errors in .NET Core for web APIs.
1. Developer Exception Page
2. Exception Handler Page
3. Exception Handle Lambda
4. UseStatusCodePages
If you compare these four methods, the best way is "Developer Exception Page" as it
provides detailed information (stacks, query string parameters, headers, cookies) about
unhandled request exceptions. You can easily enable this page by running your applications
in the development environment. This page runs early in the middleware pipeline, so you can
easily catch the exception in middleware.
Model Validation.
Model Validation in ASP.NET Core is the process of ensuring that the data submitted by the
user meets certain rules and constraints before processing it further. It helps to maintain data
integrity and prevent invalid or malicious data from being processed by the application.
ASP.NET Core provides built-in support for model validation using data annotations. These
annotations are applied to the properties of the model class, and they define the validation
rules that should be enforced. For example, the [Required] attribute specifies that a property
must have a non-null value, and the [StringLength] attribute sets the minimum and maximum
length for a string property.
When a request is made, ASP.NET Core automatically validates the model based on the
defined validation rules. If any validation errors occur, they are added to the ModelState
object, which can be accessed and displayed to the user.
Liskov Substitution Principle (LSP): Subtypes must be substitutable for their base types.
Dependency Inversion Principle (DIP): High-level modules should not depend on low-level
modules. Both should depend on abstractions.
Adhering to the SOLID principles helps create modular, flexible, and maintainable code that is
easier to understand, test, and extend over time.
Marking Phase: During this phase, the GC identifies the root objects (objects that are
currently in use, such as static objects, objects on the stack, and objects referenced by CPU
registers). It then traverses all references from these root objects, marking all reachable
objects as "live."
Marking Phase Ending: After marking all live objects, the GC checks for sufficient memory to
continue execution. If not, it proceeds to the next phase.
Relocating Phase: In this phase, the GC compacts the heap by moving all live objects to one
end of the heap, creating a contiguous block of free memory.
Reclaiming Phase: After compacting the heap, the GC reclaims the memory occupied by
unreachable (dead) objects, making it available for future allocations.
The GC employs various techniques and algorithms to optimize its performance. These
techniques include generational garbage collection, which divides the heap into generations
based on object lifetime, and background garbage collection, which allows the GC to run
concurrently with the application’s threads.
a web server performs a database query for an HTTP request. The server has 16
threads in total. Each HTTP request executes a database query and waits for the
results, blocking the thread. Can this be optimized using .NET means?
This scenario can be optimized using asynchronous programming in .NET. Instead of
blocking threads waiting for database queries, use async/await with asynchronous database
operations, allowing threads to be released back to the thread pool while waiting. Also,
consider increasing the maximum thread pool size if expecting high concurrency.
What is loosely-coupled code? How is it better than tightly-coupled code? How would
you achieve loose coupling?
Loosely-coupled code has minimal dependencies between components, enabling
independent development and evolution. It’s better than tightly-coupled code, which is harder
to maintain and change. Achieve loose coupling through abstractions (interfaces),
dependency injection, event-driven communication, and modular design.