Make a HomeController inherit from a BaseController with attribute session - c#

The IHttpContextAccessor gives me:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
My HomeController:
public class HomeController : BaseController
{
private static IHttpContextAccessor httpContextAccessor;
private static seiren_devContext context;
public HomeController() : base(httpContextAccessor,context)
{
}
}
My BaseController:
public class BaseController : Controller
{
protected readonly seiren_devContext _context;
protected readonly IHttpContextAccessor _httpContextAccessor;
protected ISession _session => _httpContextAccessor.HttpContext.Session;
public BaseController(IHttpContextAccessor httpContextAccessor, seiren_devContext context)
{
_context = context;
_httpContextAccessor = httpContextAccessor;
}
}
How can I make the HomeController Class inherit from BaseController in a proper way?

Nothing is setting the static (note: static is very bad in this context) variables in HomeController so they will always be null. Instead, make the HomeController also take the two values as constructor parameters and let the dependency injection system take care of the rest.
public class HomeController : BaseController
{
public HomeController(IHttpContextAccessor httpContextAccessor, seiren_devContext context)
: base(httpContextAccessor,context)
{
}
}
You may also need this line in ConfigureServices in your Startup.cs:
services.AddHttpContextAccessor();

You need to add in ConfigureServices
services.AddHttpContextAccessor();

Related

How do I resolve "Unable to resolve service for type '' while attempting to activate ''"

When I attempt requests to a .net core 3.1 WebAPI from Postman I am getting error
System.InvalidOperationException: Unable to resolve service for type 'PaymentsAPI.Repository.PaymentService' while attempting to activate 'PaymentsAPI.Controllers.PaymentController'
'
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddCors(c =>
{
c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
});
services.AddDbContext<ApplicationDbContext>(o => o.UseSqlServer(Configuration.GetConnectionString("SqlSvrConn")));
services.AddTransient<IAsyncPaymentsService<PaymentDetail>, PaymentService>();
}
IAsyncPaymentsService.cs
public interface IAsyncPaymentsService<TEntity>
{
Task<IEnumerable<TEntity>> GetAllAsync();
}
PaymentService.cs
public class PaymentService : IAsyncPaymentsService<PaymentDetail>
{
private readonly ApplicationDbContext _dbContext;
public async Task<IEnumerable<PaymentDetail>> GetAllAsync()
{
return await _dbContext.PaymentDetails.ToListAsync();
}
}
PaymentController.cs
[ApiController]
[Route("[controller]")]
public class PaymentController : ControllerBase
{
private readonly ApplicationDbContext _context;
private readonly PaymentService _service;
public PaymentController(ApplicationDbContext context, PaymentService service)
{
_context = context;
_service = service;
}
[HttpGet]
public async Task<ActionResult<IEnumerable<PaymentDetail>>> GetAsync()
{
var items = (await _service.GetAllAsync());
return Ok(items);
}
}
I have tried rearranging the order of services in the container but the error still persists. What am I missing ?
The quick fix would be to change the controller constructor to depend on the abstraction instead of the implementation since the abstraction is what was registered with the container.
//...
private readonly ApplicationDbContext _context;
private readonly IAsyncPaymentsService<PaymentDetail> _service;
public PaymentController(ApplicationDbContext context, IAsyncPaymentsService<PaymentDetail> service)
{
_context = context;
_service = service;
}
//...
However, the generic abstraction could derived to a closed type if so desired
public interface IPaymentService : IAsyncPaymentsService<PaymentDetail> {
}
applied to the implementation
public class PaymentService : IPaymentService {
//...omitted for brevity
}
registered with the container
services.AddTransient<IPaymentService, PaymentService>();
and refactored in the controller
//...
private readonly ApplicationDbContext _context;
private readonly IPaymentService _service;
public PaymentController(ApplicationDbContext context, IPaymentService service)
{
_context = context;
_service = service;
}
//...
The only thing you should have to change to make this work is to accept the interface into your controller instead of the concrete service.
public PaymentController(ApplicationDbContext context, IAsyncPaymentsService<PaymentDetail> service)
{...}
This is recommended over taking the concrete type for various reasons such as testing. If you truly need the concrete type, you'd have to instead change your registration to
services.AddTransient<PaymentService>();
and leave your controller's constructor as is.

Error while validating the service descriptor 'ServiceType: INewsRepository Lifetime: Singleton ImplementationType: NewsRepository':

I try get data from my database with repository Pattern
i have 3 project
Bmu.Mode 'this is for model to create database'
Bmu.Repo 'it have 2 folder for repository include contract/InewsRepository.cs' and 'Repository/NewsRepository' for implement Interface
Bmu.Api for invoke data from Repo project
news class in Model Project
namespace bmu.model
{
public class News
{
public int Id { get; set; }
public string SubTitle { get; set; }
public string Title { get; set; }
public string Summery { get; set; }
}
}
context class in model project
namespace bmu.model
{
public class BmuContext : DbContext
{
public BmuContext(DbContextOptions<BmuContext> options): base(options)
{
}
public DbSet<News> News { get; set; }
}
}
My interface in Repo project
namespace bmu.repo.Contracts
{
public interface INewsRepository
{
Task<IEnumerable<News>> GetAllAsync();
Task<IEnumerable<News>> GetAllActiveAsync();
}
}
implement interface in bmu.repo
namespace bmu.repo.IRepository
{
public class NewsRepository : INewsRepository
{
private readonly BmuContext _context;
private readonly MemoryCache _memoryCache;
public NewsRepository(BmuContext context, MemoryCache memoryCache)
{
_context = context;
_memoryCache = memoryCache;
}
public async Task<IEnumerable<News>> GetAllAsync()
{
return await _context.News.ToListAsync();
}
public async Task<IEnumerable<News>> GetAllActiveAsync()
{
return await _context.News.Where(x => x.Active).ToListAsync();
}
}
}
Also add
services.AddControllers();
services.AddSingleton<INewsRepository, NewsRepository>();
in startup of Api project
and this is my controller
namespace bmu.api.Controllers
{
[ApiController]
[Route("[controller]")]
public class NewsController : ControllerBase
{
private readonly ILogger<NewsController> _logger;
private readonly INewsRepository _newsRepository;
public NewsController(ILogger<NewsController> logger,INewsRepository newsRepository)
{
_logger = logger;
_newsRepository = newsRepository;
}
[HttpGet]
public async Task<IEnumerable<News>> Get()
{
return await _newsRepository.GetAllActiveAsync();
}
}
}
but when run project i got this error
AggregateException: Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: bmu.repo.Contracts.INewsRepository Lifetime: Singleton ImplementationType: bmu.repo.IRepository.NewsRepository': Unable to resolve service for type 'bmu.model.BmuContext' while attempting to activate 'bmu.repo.IRepository.NewsRepository'.)
also because of multi project add DbContext with this
UPDATE:
namespace bmu.model
{
public class BmuContextFactory : IDesignTimeDbContextFactory<BmuContext>
{
public BmuContext CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<BmuContext>();
optionsBuilder.UseSqlite("Data Source=bmu.db");
return new BmuContext(optionsBuilder.Options);
}
}
}
Is there any solution for this error ?
Firstly,you need to change:
services.AddSingleton<INewsRepository, NewsRepository>();
To:
services.AddTransient<INewsRepository, NewsRepository>();
Secondly,you need to inject IMemoryCache instead of MemoryCache in NewsRepository.
Here is a simple demo like below:
1.Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSession();
services.AddTransient<INewsRepository, NewsRepository>();
services.AddDbContext<BmuContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Connectionstring")));
services.AddMemoryCache();
}
2.appsettings.json:
"ConnectionStrings": {
"Connectionstring": "Server=(localdb)\\mssqllocaldb;Database=Bmu;Trusted_Connection=True;MultipleActiveResultSets=true"
}
3.NewsRepository:
public class NewsRepository : INewsRepository
{
private readonly BmuContext _context;
private readonly IMemoryCache _memoryCache;
public NewsRepository(BmuContext context, IMemoryCache memoryCache)
{
_context = context;
}
//...
}
My Error was that I was injecting the service class instead of the interface
It was
//This is wrong
Private readonly DataSerive _dataService;
public void EmployeeHandler(DataSerive dataService)
{
_dataService = dataService;
}
But it should be
//This is correct
Private readonly IDataSerive _dataService;
public void EmployeeHandler(IDataSerive dataService)
{
_dataService = dataService;
}
Here DataService is the class that handles operation
and IDataService is the interface
There is a lifetime type mismatch in your API. EntityFramework DbContext is a scoped service, and you cannot have a singleton instance of the NewsRepository, as it depends on an instance that is generated for each request.
You either have to use NewsRepository as a scoped service, or restructure your dependency resolution, like shown in this SO answer: Use DbContext in ASP .Net Singleton Injected Class
Like Sotiris Koukios-Panopoulos -san comment
I see you are only setting up the options for design time, not in your Startup.cs. I expect a:
services.AddDbContext<BmuContext>(options => options.UseSqlite("your connection string"));
instead.
In my case, I forgot to set this in my Startup.cs
services.AddDbContext<myDbContext>(o => o.UseSqlServer(myConnectionString));
and I forgot to mention this, because I'm using interface an service
services.AddScoped<IMyTruckService, MyTruckService>();
I was adding singleton service that was injecting DbContext class.
services.AddSingleton<WeatherForecastService>();
I changed above to below (Added a transient service scope) and it worked.
services.AddTransient<FoodItemService>();
This error can be caused by circular dependency.
Because probably, you inject service1 in service2 and also service2 in service1.
You should change it and break circular dependency.
I was having two dbcontext, and forgotten to mention this in startup.cs file
services.AddDbContext<Abc>(option => option.UseSqlServer(Configuration.GetConnectionString("ConStr")));
It was because of
private readonly IMemoryCache _memoryCache;
when i remove it every think work fine

Use DI in Data Access Layer with ApplicationDbContext (netcore 2.0)

I have some problem with DI (Dependancy Injection). My project is on netcore 2.0 and has few layers (standard N-Tier Architecture). I'm trying to move EF Core 2 from Presentation Layer to Data Access Layer and I have created the following classes in DAL:
namespace MyProject.Infrastructure.Implementation.MySql.Contexts
{
public class ApplicationDbContext : DbContext
{
private readonly IConfiguration _configuration;
public ApplicationDbContext(IConfiguration configuration)
{
_configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySql(
Configuration.GetConnectionString("MySql")
);
}
public DbSet<Test> Test { get; set; }
}
}
Then I prepared base class for all DAL engines:
namespace MyProject.Infrastructure.Implementation.MySql
{
public class BaseEngine : IBaseEngine
{
private readonly ApplicationDbContext _context;
protected ApplicationDbContext Db => _context;
public BaseEngine(ApplicationDbContext context)
{
_context = context;
}
}
}
So, my common engine should look like this:
namespace MyProject.Infrastructure.Implementation.MySql
{
public class TestEngine : BaseEngine
{
public List<Test> GetTestList()
{
return Db.Test.ToList();
}
}
}
The problem is that I get error, BaseEngine needs parameter to be passed in constructor and I don't want to create all instances manually, I need somehow use Dependancy Injection that automatically creates instances of ApplicationDbContext and IConfiguration when BaseEngine and ApplicationDbContext will be created..
Any ideas?
Create a public interface for ApplicationDbContext, like IApplicationDbContext. Put that in the constructor for BaseEngine instead of the concrete class. Make the BaseEngine constructor protected. The BaseEngine constructor should look like:
protected BaseEngine(IApplicationDbContext context)
Then, since TestEngine is derived from BaseEngine, and BaseEngine requires a constructor argument, you have to pass that in from the TestEngine constructor like:
public TestEngine(IApplicationDbContext context) : base(context)

How to implement a UserFactory using IHttpContextAccessor

I used to have a UserFactory (before vNext) that used HttpContext.Current but since that is now gone I am having trouble recreating it.
I want it to be a static class that sets and gets the current user to access user data throughout the application.
I know I must use the DI system but not sure how.
Code so far:
public class CurrentContext : IHttpContextAccessor
{
private IHttpContextAccessor ctx;
public HttpContext HttpContext
{
get
{
return ctx.HttpContext;
}
set
{
ctx.HttpContext = value;
}
}
}
services.AddTransient<IHttpContextAccessor, CurrentContext>();
public class UserFactory
{
private IHttpContextAccessor _context;
public UserFactory(IHttpContextAccessor Context)
{
_context = Context;
}
public void Add(string s) => _context.HttpContext.Session.SetString(s, s);
public string Get(string s) => _context.HttpContext.Session.GetString(s);
}
How can I get a UserFactory instance anywhere in my app with the current context?
I suggest you make the UserFactory class non-static and register it as scoped:
services.AddScoped<UserFactory>();
This will create one instance per web request. You can inject this into every other class and let the UserFactory take a dependency on IHttpContextAccessor to get the current HttpContext.
This adheres to the dependency inversion philosophy Microsoft is trying to implement in ASP.NET 5. Static classes do not really fit into this and should be avoided as much as possible.
Example
UserFactory class:
public class UserFactory
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserFactory(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
// other code...
}
ConfigureServices() in Startup class:
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddScoped<UserFactory>();
// ...
}
Now you can inject an instance of UserFactory in a controller for example:
public class SomeController : Controller
{
private readonly UserFactory _userFactory;
public SomeController(UserFactory userFactory)
{
_userFactory = userFactory;
}
// ...
}
Now when UserFactory is begin resolved, IHttpContextFactory inside UserFactory will also be resolved.

Referencing a common instance from a DI constructor

Using Ninject DI, I have implemented two interfaces that I instantiate from my MVC controllers. For example:
public class MyController : Controller
{
private readonly IUnitOfWork _UnitOfWork;
private readonly IAssetService _AssetService;
public MyController(IUnitOfWork unitOfWork, IAssetService assetService)
{
this._UnitOfWork = unitOfWork;
this._AssetService = assetService;
}
// Controller actions etc.
}
In my Ninject module I have created the following bindings:
public class DomainModule : NinjectModule
{
public override void Load()
{
Bind<IUnitOfWork>()
.To<SqlUnitOfWork>()
.InRequestScope()
.WithConstructorArgument("connectionString", "MyDb.Database");
Bind<IAssetService>()
.To<FileSystemAssetService>()
.WithConstructorArgument("rootPath", "C:\\DataStore");
}
}
I now want to inject the IUnitOfWork instance into my IAssetService so I have considered making this a property of IAssetService and modifying my controllers as follows:
public class MyController : Controller
{
private readonly IUnitOfWork _UnitOfWork;
private readonly IAssetService _AssetService;
public MyController(IUnitOfWork unitOfWork, IAssetService assetService)
{
this._UnitOfWork = unitOfWork;
this._AssetService = assetService;
this._AssetService.UnitOfWork = this._UnitOfWork;
}
// Controller actions etc.
}
but I wondered if there was a better/cleaner way of doing this using a different DI technique - ideally I would like to add the IUnitOfWork to the AssetService constructor?
Then why not simply inject the IUnitOfWork into the AssetService?
public class FileSystemAssetService : IAssetService
{
private readonly IUnitOfWork unitOfWork;
private readonly string rootPath;
public FileSystemAssetService(IUnitOfWork unitOfWork, string rootPath)
{
this.unitOfWork = unitOfWork;
this.rootPath = rootPath;
}
}

Categories