How to inject dependency in Entity Framework based controller - dependency-injection

I need to read the appsetings.json from inside an auto generate controller based on entity framework and I'm trying to inject the IConfiguration interface on it but I cannot find out how.
In the Startup.cs file, I just have this:
services.AddDbContext<controle_eventosContext>(options => options.UseNpgsql(connection));
and in the controller this:
public ContatosController(controle_eventosContext context)
{
_context = context;
}
Where should I inject the IConfiguration dependency?

As Dhreeraj comment, you can inject in controller constructor, for example:
In your Startup.cs:
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration, IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IConfiguration>(Configuration);
}
In your Controller
public class ContactController : Controller
{
private readonly IConfiguration _configuration;
public AccountController(IConfiguration configuration)
{
_configuration = configuration;
}
public IActionResult Index()
{
var data = Configuration["version"].ToString();
data += Configuration["Settings:Name"].ToString();
return Content(data);
}
}
Your appsettings.json:
{
"Version": "1.0.0",
"Settings": {
"Name": "App"
}
}
More info:
https://mva.microsoft.com/en-US/training-courses/aspnet-core-advanced-18155
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.1&tabs=basicconfiguration

Related

Azure function v3 config file with DI getting nulls

We have an Azure function v3 and we need to inject a service that requires an IConfiguration so our code is the following:
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton<IService>((s) =>
{
var configuration = s.GetService<IConfiguration>();
return new Service(configuration);
});
}
}
The local.settings.json:
{
"IsEncrypted": false,
"Values": {
"myConfig1": "xx"
}
}
The service is attempting to get the values but gets nulls:
public Service(IConfiguration configuration)
{
string myConfig1 = configuration["myConfig1"];
I solved it with this:
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton<IService>((s) =>
{
IConfiguration configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("local.settings.json", true, true)
.Build();
return new Service(configuration);
});
}
}

Asp core, Object reference not set to an instance of an object in Repository pattern

I am working on an asp core 1.1 and i want to create a select repository pattern in my project.
my code in repository class :
public class AuthorReposetory : IDisposable
{
private static ApplicationDbContext _context;
public AuthorReposetory(ApplicationDbContext context)
{
_context = context;
}
public static List<Author> GetAuthorList()
{
List<Author> model = new List<Author>();
model = _context.authors.Select(a => new Author
{
AuthorId = a.AuthorId,
AuthorName = a.AuthorName,
AuthorDescription = a.AuthorDescription
}).ToList();
return model;
}
public void Dispose()
{
throw new NotImplementedException();
}
~AuthorReposetory()
{
Dispose();
}
}
and in controller
[HttpGet]
public IActionResult Index()
{
var q = AuthorReposetory.GetAuthorList();
return View(q);
}
Update
Here is my StartUp Class
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
//define Connection string
services.AddDbContext<ApplicationDbContext>(option => option.UseSqlServer(Configuration.GetConnectionString("DefualtConnection")));
//For Create and use identity in database
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Add framework services.
services.AddMvc();
services.AddAutoMapper();
services.AddPaging();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseIdentity();
app.UseMvc(routes =>
{
//New Area For Admin
routes.MapRoute(
name: "Admin",
template: "{area:exists}/{controller=Admin}/{action=Index}/{id?}");
//New Area For User
routes.MapRoute(
name: "UserProfile",
template: "{area:exists}/{controller=UserProfile}/{action=Index}/{id?}");
//tranditional Routing
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
My Connection string in appsettings.json
{
"ConnectionStrings": {
"DefualtConnection" : "Data Source=.;Initial Catalog=DataBaseName;User ID = sa; Password = 123"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
}
}
The problem is Object reference not set to an instance of an object when run model = _context.authors.Select(a => new Author in repository.
In the above i show controller code, Repository class code and start up code to figure out.
Where can the problem be?
Note : everything is good in controller. just problem is in repository class.
You are using static methods and the constructor is never called as you never create the object. You would have to change your constructor to:
public static AuthorReposetory()
{
_context = new ApplicationDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("DefualtConnection")));
}
but that's quite bad practice since you have to setup the connection in the constructor and this also created a hard dependency on your context class.
A better solution would be to create a non static class
public class AuthorRepository : IAuthorRepository
{
private ApplicationDbContext _context;
public AuthorRepository(ApplicationDbContext context)
{
_context = context;
}
// ...
}
public interface IAuthorRepository
{
// ...
}
Reverse the dependency with injection:
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
//define Connection string and setup dependency injection
services.AddDbContext<ApplicationDbContext>(option => option.UseSqlServer(Configuration.GetConnectionString("DefualtConnection")));
services.AddScoped<IAuthorRepository, AuthorRepository>();
// ...
}
Controller:
public HomeController
{
private IAuthorRepository _authorRepository;
public HomeController(IAuthorRepository authorRepository)
{
_authorRepository = authorRepository;
}
[HttpGet]
public IActionResult Index()
{
var q = _autorRepository.GetAuthorList();
return View(q);
}
}
Probably your _context object is null. How is your DI/IoC configured? I would investigate in that way.
Your db context should be added like this :
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext(options => options.UseSqlite("Data Source=blog.db"));
}
Here is the documentation on how to configure your db context: https://learn.microsoft.com/en-us/ef/core/miscellaneous/configuring-dbcontext
You have not registered your repository class in the services so it is not getting resolved via the container. In your ConfigureServices method try this:
services.AddScoped<AuthorReposetory>();

Read AppSettings.json data in user defined class in Asp.net Core 2.0

I want to access the "BaseURL" key value in my user defined class instead of controller. Please help me how to do the same
Below is My AppSettings.json
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Warning"
}
},
"BaseURL": "http://192.168.0.72/mehcrm/CMS/public/api/v1/"`
}
Need your assistance.
You can take "BaseURL" value in Startup.cs like mentioned in below code.
public class Startup
{
public static string BaseUrl { get; private set; }
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
builder.AddEnvironmentVariables();
Configuration = builder.Build();
BaseUrl = Configuration.GetSection("BaseURL").Value;
}
}
public static string GetBaseUrl()
{
return Startup.BaseUrl;
}
Use it in other classes in the project like shown below:
string BaseUrl= Startup.GetBaseUrl();

Register classes with primitive dependencies in ASP NET Core

I got baffled on how can i resolve connection string dependency on UserRepo once it is injected on an mvc controller by ASP NET Core's DI? Note that my repo is targeting NET 4.6. and uses either sql db with dapper orm. Tips and advice will do.
Heres the code.
Interface to be depended
public interface IUserRepo
{
List<User> GetAll();
}
Concrete class that will be injected to mvc controller and has its own dependency
public class UserRepo: IUserRepo
{
private string connectionString = "";
//Depends on a connectionstring
public UserRepo(string connectionString)
{
this.connectionString = connectionString;
}
public List<User> GetAll()
{
//create an sqlconnection using provided connectionstring
//return list from db...
}
}
on ASP MVC CORE's startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
//inject UserRepo , how to resolve UserRepo's dependency?
services.AddScoped<IUserRepo, UserRepo>();
}
You should use the AddScoped overload that accepts a delegate:
services.AddScoped<IAccountRepo>(c => new AccountRepo("constr"));
I suggest you using configuration based on ASP.NET Core documentation
If you have configuration setting (appsettings.json) like this:
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-WebApplication1-26e8893e-d7c0-4fc6-8aab-29b59971d622;Trusted_Connection=True;MultipleActiveResultSets=true"
},
}
And your Startup.cs:
private readonly IConfigurationRoot _configuration;
public Startup(IHostingEnvironment env)
{
_configuration = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile($"appsettings.json", optional:false, reloadOnChange:true)
.Build();
}
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSingleton<IConfiguration>(provider => _configuration);
...
}
Then you can resolve it on the UserRepo easily:
public class UserRepo: IUserRepo
{
private readonly string connectionString;
public UserRepo(IConfiguration configuration)
{
this.connectionString = configuration.GetConnectionString("DefaultConnection");;
}
public List<User> GetAll()
{
//create an sqlconnection using provided connectionstring
//return list from db...
}
}

ASP.Net Core MVC Dependency Injection not working

I am trying to inject a interface into to my HomeController and I am getting this error:
InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Configuration.IConfiguration' while attempting to activate
My Startup class is as follows:
public Startup(IApplicationEnvironment appEnv)
{
var builder = new ConfigurationBuilder()
.SetBasePath(appEnv.ApplicationBasePath)
.AddEnvironmentVariables()
.AddJsonFile("appsettings.json");
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options => options
.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
services.AddSingleton(provider => Configuration);
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseApplicationInsightsRequestTelemetry();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
try
{
using (var serviceScope = app.ApplicationServices
.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
serviceScope.ServiceProvider
.GetService<ApplicationDbContext>()
.Database.Migrate();
}
}
catch { }
}
app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());
app.UseApplicationInsightsExceptionTelemetry();
app.UseStaticFiles();
app.UseIdentity();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.Run((async (context) =>
{
await context.Response.WriteAsync("Error");
}));
}
and my HomeController constructor is:
public HomeController(IConfiguration configuration, IEmailSender mailService)
{
_mailService = mailService;
_to = configuration["emailAddress.Support"];
}
Please tell me where I am mistaken.
Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites(ServiceProvider provider, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
Try injecting it as an IConfigurationRoot instead of IConfiguration:
public HomeController(IConfigurationRoot configuration
, IEmailSender mailService)
{
_mailService = mailService;
_to = configuration["emailAddress.Support"];
}
In this case, the line
services.AddSingleton(provider => Configuration);
is equivalent to
services.AddSingleton<IConfigurationRoot>(provider => Configuration);
because the Configuration property on the class is declared as such, and injection will be done by matching whatever type it was registered as. We can replicate this pretty easily, which might make it clearer:
public interface IParent { }
public interface IChild : IParent { }
public class ConfigurationTester : IChild { }
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
IChild example = new ConfigurationTester();
services.AddSingleton(provider => example);
}
public class HomeController : Controller
{
public HomeController(IParent configuration)
{
// this will blow up
}
}
However
As stephen.vakil mentioned in the comments, it would be better to load your configuration file into a class, and then inject that class into controllers as needed. That would look something like this:
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
You can grab these configurations with the IOptions interface:
public HomeController(IOptions<AppSettings> appSettings)
In Core 2.0 it's recommended to use IConfiguration instead of IConfigurationRoot
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
from https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/#add-configuration-providers
When moving a project from .Net Core 1.x to 2.0, change all IConfigurationRoot to IConfiguration

Resources