.Net Core WebApi Dependency Injection - asp.net-core

I have a solution and I have different projects in it.
One of them is the api project and I want to use dependency injection in this project, but I get the following error:
Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: CCM.Business.Abstract.ICompanyService Lifetime: Scoped ImplementationType: CCM.Business.Concrete.CompanyManager': Unable to resolve service for type 'CCM.DataAccess.Concrete.CompanyDal' while attempting to activate 'CCM.Business.Concrete.CompanyManager'.)
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddScoped<ICompanyDal, CompanyDal>();
services.AddScoped<ICompanyService, CompanyManager>();
}
ICompanyDal:
public interface ICompanyDal: IGenericDal<Company>
{
}
CompanyDal:
public class CompanyDal:GenericDal<Company,CCMContext>,ICompanyDal
{
}
ICompanyService:
public interface ICompanyService
{
Company GetById(int id);
List<Company> GetAll();
void Create(Company entity);
void Update(Company entity);
void Delete(Company entity);
}
CompanyManager:
public class CompanyManager : ICompanyService
{
private CompanyDal _companyDal;
public CompanyManager(CompanyDal companyDal)
{
_companyDal = companyDal;
}
public void Create(Company entity)
{
_companyDal.Create(entity);
}
public void Delete(Company entity)
{
_companyDal.Delete(entity);
}
public List<Company> GetAll()
{
return _companyDal.GetAll();
}
public Company GetById(int id)
{
return _companyDal.GetById(id);
}
public void Update(Company entity)
{
_companyDal.Update(entity);
}
}
Is there anything else I should pass on to you? please help.

In startup, you add the service ICompanyDal with the implementation CompanyDal. But in CompanyManager, you inject the implementation CompanyDal, not the service ICompanyDal.
Solution, inject the service in the constructor :
public class CompanyManager : ICompanyService
{
private ICompanyDal _companyDal;
public CompanyManager(ICompanyDal companyDal)
{
_companyDal = companyDal;
}
...

Change the CompanyManager to explicitly depend on the registered abstraction
CompanyManager:
//...
private ICompanyDal _companyDal;
//CTOR
public CompanyManager(ICompanyDal companyDal) {
_companyDal = companyDal;
}
//...
since that is what was registered with the container
Startup:
//...
services.AddScoped<ICompanyDal, CompanyDal>();
//...
Make sure that your controller(s) follow a similar format and explicitly depends on the registered abstraction(s) as well
Controller:
//...
public MyController(ICompanyService service) {
//...
}
//...

Related

How to get AppSetting values in startup by using services in asp.net core?

I want to get value of appsetting inside StartUp and also using services for saving them.
I create a static IServiceCollection method for AddTransient my custom service.
I define a readonly variable for keep the appsetting values. My problem is that, this service creates new instance for readonly variable, for all calling.how can I prevent this?
and I have a question that other extensions like AddOpenIdConnect, how to work with their configs, I mean how to save and use them?
this is startup:
public void ConfigureServices(IServiceCollection services){
...
services.AddMyIntegration(conf =>
{
conf.ConnectionString = Configuration.GetConnectionString("Integration");
conf.AgentApiAddress = Configuration["AgentApiAddress"];
});
}
....
public static class MyExtension
{
public static IServiceCollection AddMyIntegration(this IServiceCollection services, Action<MyConstantsProvider> myConstantsProvider)
{
services.AddTransient((t) =>
{
return new MyService(myConstantsProvider);
});
return services;
}
}
this is my service:
public class MyService
{
public readonly MyConstantsProvider Provider;
public MyService(Action<MyConstantsProvider> configure)
{
Provider = new MyConstantsProvider();
configure(Provider);
}
}
public class MyConstantsProvider
{
public string ConnectionString { get; set; }
public string AgentApiAddress { get; set; }
}
Update my question:
Finally I fixed my issue by add MyConstantsProvider as singletone instead of MyService so this creates new instance of variable at the first time in extension class:
public static class MyExtension
{
public static IServiceCollection AddMyIntegration(this IServiceCollection services, Action<MyConstantsProvider> myConstantsProvider)
{
var provider = new MyConstantsProvider();
myConstantsProvider(provider);
services.AddSingleton(provider);
services.AddTransient<MyService>();
return services;
}
}
this is MyService class:
public class MyService
{
public readonly MyConstantsProvider Provider;
public MyService(MyConstantsProvider provider)
{
Provider = provider;
}
}
I wonder why we make it so complicated ? I just saw we're trying to read appsettings later in the application somewhere, and for this, the framework have default implementation to back us up.
Our app settings might look like
{
"Catalog": {
"ConnectionString": "SomeConnection",
"AgentApiAddress": "http://somewhere.dev"
}
}
Then our class could be
public class MySetting
{
public string ConnectionString { get; set; }
public string AgentApiAddress{ get; set; }
}
Config register it in startup (or somewhere we like in .net 6)
services.Configure<MySetting>(configuration.GetSection("Catalog"));
Retrive it later in the app via DI
public class SomeService
{
private readonly MySetting _setting;
public SomeService(IOptions<MySetting> config)
{
_setting = config.Value;
}
}
For setting that can be change dynamically, take a look at IOptionsMonitor
Or that might be some special case that I miss ?

inject Database Context into Custom Attribute .NET Core

I'm creating ASP.NET Core 3.1 app, using SPA for front end. So I decided to create custom Authentication & Authorization. So I created custom attributes to give out and verify JWTs.
Lets say it looks like this:
[AttributeUsage(AttributeTargets.Method)]
public class AuthLoginAttribute : Attribute, IAuthorizationFilter
{
public async void OnAuthorization(AuthorizationFilterContext filterContext)
{
//Checking Headers..
using (var EF = new DatabaseContext)
{
user = EF.User.Where(p => (p.Email == username)).FirstOrDefault();
}
filterContext.HttpContext.Response.Headers.Add(
"AccessToken",
AccessToken.CreateAccessToken(user));
}
}
Everything was Okay, but my DatabaseContext, looked like this:
public class DatabaseContext : DbContext
{
public DbSet<User> User { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySQL("ConnectionString");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//....
}
}
I wanted to take Connection string from Appsettings.json and maybe use Dependency injection. I
Changed Startup.cs to look like this:
//...
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<DatabaseContext>(
options => options.UseMySQL(Configuration["ConnectionStrings:ConnectionString"]));
services.Add(new ServiceDescriptor(
typeof(HMACSHA256_Algo), new HMACSHA256_Algo(Configuration)));
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
//...
Changed Database Context class to this:
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { }
public DbSet<User> User { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
///..
}
}
In Controllers I injected DB context and everything works. It looks like this:
[ApiController]
[Route("API")]
public class APIController : ControllerBase
{
private DatabaseContext EF;
public WeatherForecastController(DatabaseContext ef)
{
EF = ef;
}
[HttpGet]
[Route("/API/GetSomething")]
public async Task<IEnumerable<Something>> GetSomething()
{
using(EF){
//.. this works
}
}
}
But my custom Attribute doesn't work no more. I can't declare new Database context, because it needs DatabaseContextOptions<DatabaseContext> object to declare, so how do I inject DBContext to Attribute as I did to Controller?
This doesn't work:
public class AuthLoginAttribute : Attribute, IAuthorizationFilter
{
private DatabaseContext EF;
public AuthLoginAttribute(DatabaseContext ef)
{
EF = ef;
}
public async void OnAuthorization(AuthorizationFilterContext filterContext)
{
using(EF){
}
}
}
this works with controller, but with attribute complains about there not being constructor with 0 arguments.
What you can do is utilize the RequestServices:
[AttributeUsage(AttributeTargets.Method)]
public class AuthLoginAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
var dbContext = context.HttpContext
.RequestServices
.GetService(typeof(DatabaseContext)) as DatabaseContext;
// your code
}
}
If you allow me to add two comments to your code:
Try not to use async void because in the event of an exception you will be very confused what is going on.
There is no need to wrap injected DbContext in a using statement like this using(EF) { .. }. You will dispose it early and this will lead to bugs later in the request. The DI container is managing the lifetime for you, trust it.

.Net Core How to Access Configuration Anywhere in application

I have read through the documentation on the different ways to setup and access configuration in .Net Core 2.1 and also the options pattern that seems to be recommended (https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/options?view=aspnetcore-2.1). However, I can't seem to get what I want working:
I have done the following:
AppSettings:
{
"ConnectionStrings": {
"DefaultConnStr": "Server=(localdb)\\MSSQLLocalDB;Database=_CHANGE_ME;Trusted_Connection=True;MultipleActiveResultSets=true;Integrated Security=true",
"AW2012ConnStr": "Server=localhost;Database=AW2012;Trusted_Connection=True;MultipleActiveResultSets=true;Integrated Security=true"
}
}
MyConfig:
public class MyConfig
{
public string AWConnStr { get; }
public string DefaultConnStr { get; }
}
Startup:
public class Startup
{
public IConfiguration _config { get; set; }
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
_config = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
//add config to services for dependency injection
//services.AddTransient<IMyConfig, MyConfig>();
//services.AddScoped<IMyConfig, MyConfig>();
var section = _config.GetSection("ConnectionStrings");
services.Configure<MyConfig>(section);
}
private static void HandleGetData(IApplicationBuilder app)
{
//DataHelper dataHelper = new DataHelper(_dataHelper);
var _dataHelper = app.ApplicationServices.GetService<DataHelper>();
app.Run(async context =>
{
//await context.Response.WriteAsync("<b>Get Data</b>");
//await context.Response.WriteAsync(dataHelper.GetCompetitions(context.Request.QueryString.ToString()));
await context.Response.WriteAsync(_dataHelper.GetCompetitions(context.Request.QueryString.ToString()));
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Map("/Route1", HandleRoute1);
app.Map("/Route2", HandleRoute2);
app.Map("/GetData", HandleGetData);
app.Run(async (context) =>
{
await context.Response.WriteAsync("Non Mapped Default");
});
}
}
I would like to then access the configuration in any class anywhere in my code. So for example I have the following class where I would like to just read the configuration information:
public interface IDataHelper
{
string GetCompetitions(string val);
}
public class DataHelper : IDataHelper
{
private readonly MyConfig _settings;
public DataHelper(IOptions<MyConfig> options)
{
_settings = options.Value;
}
public string GetCompetitions( string queryStringVals)
{
return _settings.AWConnStr;
}
}
As shown above in my Startup class I then want to access/call something in the HandleGetData function in my startup, so that when I browse to the following route: http://localhost:xxxxx/getdata I get back the response from the Something.GetData function.
Is this correct? The problem I'm having is that when I create an instance of class Something, it is requiring me to pass in the configuration object, but doesn't that defeat the purpose of injecting it. How should I be setting this up to work similar to how DBContext gets the context injected with the configuration options. And what's the difference between services.AddTransient and services.AddScoped? I've seen both as a way to register the service.
I would say that in .Net Core application you shouldn't pass instance of IConfiguration to your controllers or other classes. You should use strongly typed settings injected through IOtions<T> instead. Applying it to your case, modify MyConfig class (also property names should match names in config, so you have to rename either config (DefaultConnection->DefaultConnStr, AW2012ConnStr->AWConnStr or properies vice versa):
public class MyConfig
{
public string AWConnStr { get; set; }
public string DefaultConnStr { get; set; }
}
Register it:
public void ConfigureServices(IServiceCollection services)
{
// in case config properties specified at root level of config file
// services.Configure<MyConfig>(Configuration);
// in case there are in some section (seems to be your case)
var section = Configuration.GetSection("ConnectionStrings");
services.Configure<MyConfig>(section);
}
Inject it to required service:
public class MyService
{
private readonly MyConfig _settings;
public MyService(IOptions<MyConfig> options)
{
_settings = options.Value;
}
}
And what's the difference between services.AddTransient and
services.AddScoped? I've seen both as a way to register the service.
Transient lifetime services are created each time they're requested.
Scoped lifetime services are created once per request.
You have to do the same thing for the Something as you did for MyConfig like:
public interface ISomething
{
string GetSomeData();
}
Then:
public class Something : ISomething
{
public IConfiguration _config { get; set; }
public Something(IConfiguration configuration)
{
_config = configuration;
}
public string GetSomeData()
{
return _config["DefaultConnStr"];
}
}
Then in the ConfigureService method of the Startup class as follows:
services.AddScoped<ISomething,Something>();
Then call the GetSomeData() as follows:
public class CallerClass
{
public ISomething _something { get; set; }
public CallerClass(ISomething something)
{
_something = something;
}
public string CallerMethod()
{
return _something.GetSomeData();
}
}
Then:
And what's the difference between services.AddTransient and services.AddScoped? I've seen both as a way to register the service.
Here is the details about this from microsoft:
Service Lifetime details in ASP.NET Core

Not Able to call the service layer in controller in mvc

Exception:
Nullreference exception
Here is my Code:
Controller:
private IUserService UserService;
public HomeController()
{
}
public HomeController(IUserService UserService)
{
this.UserService = UserService;
}
[HttpPost]
public ActionResult Register(RegisterViewModel reg)
{
SADM_Users users = new SADM_Users();
if (reg == null)
{
return Json(false);
}
else
{
FillUserMaster(users, reg);
UserService.insertUser(users);
ViewBag.ErrorMsg = "Succesfully added";
}
return View();
}
Service Layer:
public interface IUserService
{
void insertUser(SADM_Users users);
}
public class UserService:IUserService
{
private readonly ILoginRepository LoginRepository;
private readonly IUnitOfWork unitOfWork;
public UserService(ILoginRepository LoginRepository)
{
this.LoginRepository = LoginRepository;
}
public void insertUser(SADM_Users users)
{
try
{
LoginRepository.Add(users);
unitOfWork.Commit();
}
finally {
users = null;
}
}
}
I'm creating an mvc app with a service layer. I'm used to call services using in my controllers, but these services have not been Called.
please some one help on this.and i wnt to know any dependancy factor.
Remove the default constructor from your HomeController and make sure that you are using a DI library that will inject the proper implementation of IUserService into it.

Is it possible to use one generic/abstract service in ServiceStack?

I am developing a (hopefully) RESTful API using ServiceStack.
I noticed that most of my services look the same, for example, a GET method will look something like this:
try
{
Validate();
GetData();
return Response();
}
catch (Exception)
{
//TODO: Log the exception
throw; //rethrow
}
lets say I got 20 resources, 20 request DTOs, so I got about 20 services of the same template more or less...
I tried to make a generic or abstract Service so I can create inheriting services which just implement the relevant behavior but I got stuck because the request DTOs weren't as needed for serialization.
Is there any way to do it?
EDIT:
an Example for what I'm trying to do:
public abstract class MyService<TResponse,TRequest> : Service
{
protected abstract TResponse InnerGet();
protected abstract void InnerDelete();
public TResponse Get(TRequest request)
{
//General Code Here.
TResponse response = InnerGet();
//General Code Here.
return response;
}
public void Delete(TRequest request)
{
//General Code Here.
InnerDelete();
//General Code Here.
}
}
public class AccountService : MyService<Accounts, Account>
{
protected override Accounts InnerGet()
{
throw new NotImplementedException();//Get the data from BL
}
protected override void InnerDelete()
{
throw new NotImplementedException();
}
}
To do this in the New API we've introduced the concept of a IServiceRunner that decouples the execution of your service from the implementation of it.
To add your own Service Hooks you just need to override the default Service Runner in your AppHost from its default implementation:
public virtual IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new ServiceRunner<TRequest>(this, actionContext); //Cached per Service Action
}
With your own:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new MyServiceRunner<TRequest>(this, actionContext); //Cached per Service Action
}
Where MyServiceRunner is just a custom class implementing the custom hooks you're interested in, e.g:
public class MyServiceRunner<T> : ServiceRunner<T> {
public override void OnBeforeExecute(IRequestContext requestContext, TRequest request) {
// Called just before any Action is executed
}
public override object OnAfterExecute(IRequestContext requestContext, object response) {
// Called just after any Action is executed, you can modify the response returned here as well
}
public override object HandleException(IRequestContext requestContext, TRequest request, Exception ex) {
// Called whenever an exception is thrown in your Services Action
}
}
Also for more fine-grained Error Handling options check out the Error Handling wiki page.
My solution was to add an additional layer where I can handle Logic per entity:
Base Logic Sample:
public interface IEntity
{
long Id { get; set; }
}
public interface IReadOnlyLogic<Entity> where Entity : class, IEntity
{
List<Entity> GetAll();
Entity GetById(long Id);
}
public abstract class ReadOnlyLogic<Entity> : IReadOnlyLogic<Entity> where Entity : class, IEntity, new()
{
public IDbConnection Db { get; set; }
#region HOOKS
protected SqlExpression<Entity> OnGetList(SqlExpression<Entity> query) { return query; }
protected SqlExpression<Entity> OnGetSingle(SqlExpression<Entity> query) { return OnGetList(query); }
#endregion
public List<Entity> GetAll()
{
var query = OnGetList(Db.From<Entity>());
return Db.Select(query);
}
public Entity GetById(long id)
{
var query = OnGetSingle(Db.From<Entity>())
.Where(e => e.Id == id);
var entity = Db.Single(query);
return entity;
}
}
Then we can use hooks like:
public interface IHello : IReadOnlyLogic<Hello> { }
public class HelloLogic : ReadOnlyLogic<Hello>, IHello
{
protected override SqlExpression<Hello> OnGetList(SqlExpression<Hello> query)
{
return query.Where(h => h.Name == "Something");
}
}
Finally our service only calls our logic:
public class MyServices : Service
{
IHello helloLogic;
public object Get()
{
return helloLogic.GetAll();
}
}