Tech Point Fundamentals

Sunday, December 18, 2022

.Net Core Interview Questions and Answers - Part 16

ASP.Net Core Interview Questions and Answers - Part 16

AspDotNetCoreInterviewQuestionsAndAnswers

Are you preparing for the .Net Core Interview? If yes, then you are at the right place. This is the ASP.Net Core Interview Questions and Answers article series. Here we will see the Top 150+ .Net Core Interview Questions with Answers. 

Please visit our YouTube Channel for Interviews and other videos by below link:




Please read the complete Design Pattern, C#, MVC, WebAPI, and .Net Framework Interview Questions and Answers article series here.




Introduction


This is the 16th part of the .Net Core Interview Questions and Answers article series. Each part contains ten .Net Core Interview Questions. Please read all the .Net Interview Questions list here.

I will highly recommend to please read the previous parts over here before continuing the current part:







ASP.Net Core Interview Questions and Answers - Part 16


Q156. What is dependency injection? What problems does Dependency Injection solve?

A dependency is an object that another object depends on.  Dependency Injection (DI) is a design pattern used to implement IoC.  Dependency Injection (DI) is a way that implements the IoC principle to invert the creation of dependent objects. Dependency Injection is about how one object knows about another, dependent object. 

It allows the creation of dependent objects outside of a class and provides those objects to a class in different ways.  By using DI, we move the creation and binding of the dependent objects outside of the class that depends on them. So DI is just a way to achieve IoC.

There are different ways of injecting the dependency (DI) - Constructor Dependency Injection, Interface Dependency Injection, Method  Parameter Dependency Injection, and Setter Property  Dependency Injection.



The Dependency Injection addresses the dependency problems through:

  1. The use of an interface or base class to abstract the dependency implementation.
  2. Registration of the dependency in a service container. 
  3. Injection of the service into the constructor of the class where it is used.

So by using the DI pattern, the controller or Razor Page: 

  1. Doesn't use any concrete type instead only the IDependency interface it implements. That makes it easy to change the implementation without modifying the controller or Razor Page.
  2. They don't create an instance of the dependent class, it's created by the DI container.

Please read more here.




Q157. How to implement Dependency Injection in .NET Core? How dependency injection works in ASP.NET Core?

ASP.NET Core is designed from scratch to support Dependency Injection. ASP.NET Core injects objects of dependency classes through a constructor or method by using a built-in IoC container. You can extend the current DI with a container of your choice like AutoFac, StructureMap, CastleWindsor, etc.

ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. Dependency Injection comes as a part of the ASP.NET Core Framework and everything is built around it.

You have to add the namespace Microsoft.Extensions.DependencyInjection in Startup.cs file to get enable IServiceCollection. In the ConfigureServices method, you can add your decencies to a container that will automatically resolve your dependencies and you can access your classes anywhere in the application.

There are basically two types of services in ASP.NET Core i.e. Framework Services and Application Services.  Framework Services are part of ASP.NET Core framework such as IApplicationBuilder, IHostingEnvironment, ILoggerFactory, etc. Application Services are the user defines custom service or class which you as a programmer create for your application.




Q158. What is the built-in IoC Container in ASP.Net Core?

ASP.NET Core framework contains a simple out-of-the-box IoC container for automatic dependency injection which does not have as many features as other third-party IoC containers. If you want more features such as auto-registration, scanning, interceptors, or decorators then you may replace the built-in IoC container with a third-party container as well.

The built-in container is represented by IServiceProvider implementation that supports constructor injection by default. The types (classes) managed by the built-in IoC container are called services.

In order to let the IoC container automatically inject your application services, you first need to register them with the IoC container. ASP.NET Core allows you to register your application services with an IoC container, in the ConfigureServices method of the Startup class. The ConfigureServices method includes a parameter of IServiceCollection type which is used to register application services.

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.Add(new ServiceDescriptor(typeof(ILog), new ConsoleLogger()));        
}   
}



The ServiceDescriptor is used to specify a service type and its instance. We have specified ILog as the service type and ConsoleLogger as its instance. This will register the ILog service as a singleton by default. 

Now, the IoC container will create a singleton object of ConsoleLogger class and inject it in the constructor of classes wherever we include ILog as a constructor or method parameter throughout the application.

There are two important interfaces in the built-in IoC container i.e. IServiceProvider and IServiceCollection

It also contains some implementation classes like ServiceProvider, ServiceCollection, ServiceDescription, ServiceCollectionServiceExtensions and ServiceCollectionContainerBuilderExtensions.

We can register application services with the built-in IoC container in the Configure method of the Startup class by using IServiceCollection.

The IServiceCollection interface is an empty interface. It just inherits IList<servicedescriptor>. The ServiceCollection class implements the IServiceCollection interface. So, the services you add in the IServiceCollection type instance, it actually creates an instance of ServiceDescriptor and adds it to the list.

IServiceProvider includes the GetService method. The ServiceProvider class implements the IServiceProvider interface which returns registered services with the container. We cannot instantiate ServiceProvider class because its constructors are marked with internal access modifier.




Q159. What are service lifetimes in .NET Core?  

The built-in IoC container manages the lifetime of a registered service type. It automatically dispose the service instance based on the specified lifetime.

During registration, dependencies require their lifetime to be defined. The lifetime of service decides under what condition the instance of the service will be created and till what time it will be live.  

Service lifetimes define the conditions in which a new service instance will be instantiated. When services are registered, there is a lifetime for every service. We can register services based on requirements.

There are three types of service lifetimes supported by .NET Core by default: 

  1. Singleton Service
  2. Transient Service
  3. Scoped Service

The container calls the Dispose() for the IDisposable types it creates. Services resolved from the container should never be disposed by the developer. If a type or factory is registered as a singleton, the container disposes the singleton automatically.




Q160. What is the difference between AddTransient(), AddScoped(), and AddSingleton in .Net Core?

Singleton Service:

When we register a service using AddSingleton(), the IoC container will create and share a single instance of a service throughout the application's lifetime. A single Instance is created once a lifetime of the application.

In AddSingleton() method, only one instance of service is created, when the service is executed for the very first time. For subsequent requests, the same instance is served by the service container. Singleton creates a single instance throughout the application. It creates the instance for the first time and reuses the same object in all calls.

Transient Service:

In this case, the IoC container will create a new instance of the specified service type every time you ask for it.

So with AddTransient() method, creates a new instance every time a service request is raised, doesn’t matter it is in the same HTTP request or a different HTTP request.

Services with transient lifetime are created each time they are requested from the service container. So it's best suited for stateless, lightweight services.



Scoped Service:

IoC container will create an instance of the specified service type once per request and will be shared in a single request.

With AddScope() method, we get a new instance with different HTTP requests. But we get the same instance if it is within the same scope.

public void ConfigureServices(IServiceCollection services)
{
services.Add(new ServiceDescriptor(typeof(ILog), new ConsoleLogger()));
services.Add(new ServiceDescriptor(typeof(ILog), typeof(ConsoleLogger), ServiceLifetime.Transient));
services.Add(new ServiceDescriptor(typeof(ILog), typeof(ConsoleLogger), ServiceLifetime.Scoped));  
}

ASP.NET Core framework includes extension methods for each type of lifetime; AddSingleton(), AddTransient(), and AddScoped() methods for the singleton, transient, and scoped lifetime respectively.



public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ILog, ConsoleLogger>();
    services.AddSingleton(typeof(ILog), typeof(ConsoleLogger));

    services.AddTransient<ILog, ConsoleLogger>();
    services.AddTransient(typeof(ILog), typeof(ConsoleLogger));

    services.AddScoped<ILog, ConsoleLogger>();
    services.AddScoped(typeof(ILog), typeof(ConsoleLogger));
}

Once we register a service, the IoC container automatically performs constructor injection if a service type is included as a parameter in a constructor.

public HomeController(ILog log)
{
_log = log;
}



Q161. What are the different ways to inject and access the registered services in the DI container?

Once we register a service, the IoC container automatically performs constructor injection if a service type is included as a parameter in a constructor.

1. By Constructor Injection:

We can access the registered services by injecting them into the controller.

public class HomeController: Controller
{
ILog _log;

public HomeController(ILog log)
{
_log = log;
}
public IActionResult Index()
{
_log.info("Executing /home/index");
return View();
}
}



2. By Method Injection:

Sometimes we may only need dependency service type in a single action method directly instead of constructor injection. 

public IActionResult Index([FromServices] ILog log)
{
log.info("Index method executing");
return View();
}


3. Direct by using HttpContext:

It is not required to include dependency services in the constructor or individual method. We can access dependent services configured with the built-in IoC container manually using the RequestServices property of HttpContext as well.

public IActionResult Index()
{
var services = this.HttpContext.RequestServices;
var log = (ILog)services.GetService(typeof(ILog));
log.info("Index method executing");

return View();
}

Services and their dependencies within an ASP.NET Core request are exposed through HttpContext.RequestServices. The framework creates a scope per request, and RequestServices exposes the scoped service provider. All scoped services are valid for as long as the request is active.



4. Property Injection:

The built-in IoC container does not support property injection. You will have to use a third-party IoC container for that.

5. View Injection:

ASP.net core can also able to inject the dependency to View as well. This method will bypass the controller call and fetch data directly from the service.

We can inject the service dependency into the view using the @inject directive. Here we need to pass the service type that needs to inject and the service instance name that is used to access the service method.

@inject DepedencyInjectionExample.Service.IUserService user

<h5>
Hello @user.UserName() 
</h5>

 View injection can be used to populate the UI elements such as dropdown.



Q162.  How can you register and use the Entity Framework Context in the ASP.Net Core?

By default, Entity Framework contexts are added to the service container using the scoped lifetime because web app database operations are normally scoped to the client's request.

To use a different lifetime, specify the lifetime by using an AddDbContext overload. Services of a given lifetime shouldn't use a database context with a lifetime that's shorter than the service's lifetime.



Q163. How do the services disposed from the built-in IoC container of the .Net Core? 

The container calls Dispose() for the IDisposable types it creates. Services resolved from the container should never be disposed by the developer. If a type or factory is registered as a singleton, the container disposes the singleton automatically.

But the services which are not created by the service container will not be disposed automatically. The developer has to dispose it explicitly.

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();

builder.Services.AddSingleton(new ServiceOne());
builder.Services.AddSingleton(new Service2Two());

Here:

  • The service instances aren't created by the service container.
  • The framework doesn't dispose of the services automatically.
  • The developer is responsible for disposing the services.



Q164. How to register a service with multiple interfaces in ASP.NET Core DI?

It's pretty common to see classes that implement multiple interfaces. For example, if you have the following class:

public class UserClass: IEmployee, IManager { }

Then you will be able to inject either IEmployee or IManager and you will receive the same UserClass instance.  How you can achieve this with the ASP.NET Core DI container?

Now at the same time, it's also important that you register the UserClass in a specific way to avoid unexpected lifetime issues, such as having two instances of a singleton.

The general pattern of having an implementation registered against multiple services is a common one. Most of the third-party DI containers have this concept built-in for example Autofac, Windsor, StructureMap, etc.

But the ASP.NET Core DI container doesn't natively support registering an implementation as multiple services (sometimes called "forwarding"). Instead, you have to manually delegate the resolution of the service to a factory function.



1. Provide a Singleton instance of the service:

The simplest approach is to provide an instance of UserClass when you're registering your services. Each registered service will return the exact instance you provided when requested, ensuring there is only ever a single instance.

public void RegisteredAsInstance_InstancesAreTheSame()
{
var user = new UserClass(); // The singleton instance
var services = new ServiceCollection();

services.AddSingleton<IEmployee>(user);
services.AddSingleton<IManager>(user);

var provider = services.BuildServiceProvider();

var emp = provider.GetService<IEmployee>();
var mgr = provider.GetService<IManager>();

Assert.Same(emp, user); // PASSES;
Assert.Same(mgr, user); // PASSES;
}

The problem with this approach is that you have to be able to instantiate Foo at configuration time, and you have to know and provide all of it's dependencies.

The second limitation of this approach is that you can only use this approach for registering Singletons. If you want UserClass to be a Scoped, then you're out of luck. 



2.  Implement forwarding using factory methods:

Our requirement is that:

  1. We want our registered service (UserClass) to have a specific lifetime (e.g. Singleton or Scoped)
  2. When IEmployee is requested, it returns the instance of UserClass
  3. When IManager is requested, also return the instance of UserClass

In order to "forward" requests for an interface to the concrete type you must do two things:

  1. Explicitly register the concrete type using services.AddSingleton<UserClass>()
  2. Delegate requests for the interfaces to the concrete type by providing a factory function: services.AddSingleton<IFoo>(x => x.GetRequiredService<Foo>())

With this approach, you will have a true singleton instance of Foo, no matter which implemented service you request.



public void WhenRegisteredAsForwardedSingleton_InstancesAreTheSame()
{
var services = new ServiceCollection();

services.AddSingleton<UserClass>(); // We must explicitly register UserClass
services.AddSingleton<IEmployee>(x => x.GetRequiredService<UserClass>()); // Forward requests to IEmployee
services.AddSingleton<IManager>(x => x.GetRequiredService<UserClass>()); // Forward requests to IManager

var provider = services.BuildServiceProvider();

var instance = provider.GetService<UserClass>(); // An instance of UserClass
var instance2 = provider.GetService<IEmployee>(); // An instance of UserClass
var instance3 = provider.GetService<IManager>(); // An instance of UserClass

Assert.Same(instance, instance2); // PASSES
Assert.Same(instance, instance3); // PASSES
}





Q165. How to implement the Repository Pattern in the ASP.Net Core project?

With the Repository pattern, we create an abstraction layer between the data access and the business logic layer of an application. By using it, we are promoting a more loosely coupled approach to access our data from the database. Data access logic is in a separate class, or set of classes called a repository, with the responsibility of persisting the application’s business model.

A repository pattern is an abstraction of the Data Access Layer. It hides the details of how exactly the data is saved or retrieved from the underlying data source. The details of how the data is stored and retrieved is in the respective repository.

RepositoryPatternInCore




The interface in the repository pattern specifies what operations (i.e methods) are supported by the repository. The implementation details are in the respective repository class that implements the Repository Interface

To implement the repository pattern in the ASP.Net Core project, follow these steps:

1. Create the repository interface and declare the required methods inside this interface.

public interface IEmployeeRepository
{
Task<IEnumerable<Employee>> GetEmployees();   
Task<Employee> GetEmployee(int employeeId);
}



2. Add the repository class and implement the interface created in step 1. Place the DbContext-dependent code in the Repository class.


using Microsoft.EntityFrameworkCore;

public class EmployeeRepository : IEmployeeRepository
{
private readonly AppDbContext appDbContext;

public EmployeeRepository(AppDbContext appDbContext)
{
this.appDbContext = appDbContext;
}

public async Task<IEnumerable<Employee>> GetEmployees()
{
return await appDbContext.Employees.ToListAsync();
}

public async Task<Employee> GetEmployee(int employeeId)
{
return await appDbContext.Employees
.FirstOrDefaultAsync(e => e.EmployeeId == employeeId);
}
}




4. Register Interface and repository class in the startup.cs class.

public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IEmployeeRepository, EmployeeRepository>();
}


5. Now in Controller, call the CRUD methods defined in the repository interface.

For setup and configure Entity Framework Core  install these Required Packages:

Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.SqlServer

Now use the DbContect in the class:

public class ApplicationContext : DbContext
{
public ApplicationContext(DbContextOptions<ApplicationContext> options) : base(options)
{
}
public DbSet<Employee> Employees { get; set; }
public DbSet<Role> Roles { get; set; }
}




To Be Continued Part-17...


Recommended Articles






Thanks for visiting this page. Please follow and join us on LinkedInFacebookTelegramQuoraYouTubeTwitterPinterestTumbler, and VK for regular updates.

    

No comments:

Post a Comment

Please do not enter any HTML. JavaScript or spam link in the comment box.