EF Core DbContext sql connection string error (Tried Following info in MS Docs) - asp.net

I have a .net Core application and I've been attempting to read from my local instance of SQL Server (2014) with Windows Authentication and continue to run into a repeat error about my connection string. I've been reviewing the MSDN docs as well as connectionstrings.com and thought I had everything configured correctly.
This is my error:
"System.ArgumentException: 'Format of the initialization string does
not conform to specification starting at index 0.'"
Which I take to mean the very start of my connection string.
I have read the other posts related to this exact issue but haven't been able to use them to find a solution.
Here is what I attempt when the error occurs:
public class HomeController : Controller
{
private ModelContext _context;
public HomeController()
{}
public IActionResult Index()
{
var viewModel = new HomeViewModel();
var optionsBuilder = new DbContextOptionsBuilder<ModelContext>();
optionsBuilder.UseSqlServer("DefaultConnection");
using (_context = new ModelContext(optionsBuilder.Options))
{
>>>>>> viewModel.List = _context.TableName.ToList(); <<<<<<<<
I have the following in my "appsettings.json" file:
"ConnectionStrings": {
"DefaultConnection": "Server=MyComputerName; Database=DBName; IntegratedSecurity=SSPI;"
},
In my "ModelContext.cs" file
public class ModelContext : DbContext
{
public ModelContext(DbContextOptions<ModelContext> options)
:base(options)
{ }
[<Table Properties>]
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("DefaultConnection");
}
And "Startup.cs" file:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDbContext<ModelContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
Thanks for taking a look!

After much contemplation and re-review of the MS Documents site for EF Core DbContext, I found that I was attempting to implement ALL 3 methods of DbContext configuration: Constructor Argument, OnConfiguring, and dependency injection.
Decided to go with OnConfiguring to get the app moving.

Related

How to distinguish between multiple databases with the same structure and same context in the URL for an ASP.Net Core Web API

I'm trying to make a web api in asp.net core which can target multiple databases on the same server with the exact same structure. As such they should be able to share the same context and controllers. Making separate contexts and controllers for each database would quickly get out of hand and make it a pain to maintain. As such I should be able to do this in Startup.cs.
services.AddDbContext<DatabaseContext>(opt => opt.UseMySQL(Configuration.GetConnectionString("db1")));
services.AddDbContext<DatabaseContext>(opt => opt.UseMySQL(Configuration.GetConnectionString("db2")));
services.AddDbContext<DatabaseContext>(opt => opt.UseMySQL(Configuration.GetConnectionString("db3")));
The problem I'm running into is how I can distinguish which database is being queried. Ideally I would like to have it such that the url can be ...{database}[controller]... where the database parameter can be used to determine which database is being queried. I've tried looking into the multi-tenant approach however I can't work out how to adapt it to my specific use case.
Any help would be greatly appreciated.
Take a look at this:
https://entityframeworkcore.com/knowledge-base/58123230/connect-multiple-databases-to--net-core-project-via-entity-framework-core
You can do it with multiple DB Contexts from inheriting the principal DB Context where you define the DbSets.
Create base context and including all settings into this, DBSET:
public abstract class BaseContext : DbContext
{
public BaseContext(DbContext options)
: base(options)
{ }
public DbSet<object> FirstDbSet { get; set; }
...
}
inherit from BaseContext for both DBs(Databases):
public class NavaContext : BaseContext
{
public NavaContext (DbContext<NavaContext> options) : base(options)
{
}
}
public class StackContext : BaseContext
{
public StackContext(DbContext<StackContext> options) : base(options)
{
}
}
and register both in Startup.cs:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddDbContext<NavaContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LATAMConnectionString")));
services.AddDbContext<StackContext>(options => options.UseSqlServer(Configuration.GetConnectionString("EUConnectionString")));
// Autofac
var builder = new ContainerBuilder();
// needed only if you plan to inject ICollection<BaseContext>
builder.RegisterType<NavaContext>().As<BaseContext>();
builder.RegisterType<StackContext>().As<BaseContext>();
builder.Populate(services);
return new AutofacServiceProvider(builder.Build());
}
add connection strings in appsettings.json:
"ConnectionStrings": {
"NavaConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true",
"StackConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity1;Trusted_Connection=True;MultipleActiveResultSets=true"
}
and now you can inject both contexts:
public class ReportRepository : IReportRepository
{
private readonly NavaContext latamDbContext;
private readonly StackContext euDbContext;
public ReportRepository(NavaContext latamDbContext, StackContext euDbContext)
{
this.latamDbContext = latamDbContext;
this.euDbContext = euDbContext;
}
}
or if you plan to inject collection of contexts:
public class ReportRepository : IReportRepository
{
private readonly ICollection<BaseContext> dbContexts;
public ReportRepository(ICollection<BaseContext> dbContexts)
{
this.dbContexts = dbContexts;
}
}
to access specific context:
var _stackContext= dbContexts.FirstOrDefault(x => x is StackContext) as StackContext;
var _navaContext= dbContexts.FirstOrDefault(x => x is NavaContext) as NavaContext;
The best way to create connection when there are multiple databases in dot net core is with IDesignTimeDbContextFactory
public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
{
public BloggingContext CreateDbContext(string[] args)
{
// logic to determine which connection string to use
var optionsBuilder = new DbContextOptionsBuilder<BloggingContext>();
optionsBuilder.UseSqlite("connectionString");
return new BloggingContext(optionsBuilder.Options);
}
}
Inject BloggingContextFactory using register services and pass args[] for logic to use connection string

ASP .NET Core Publish Errors AddDbContext

i actually dont know deploy IIS for LAN server. We are working on this project together with my friend. We share same Wifi. So we want shared api project. Because i working on backend (API-DAL-BLL) layers, my friends working on FrontEnd. But i cant deploy very well.
First my publish cant see my DBContext.So i added Startup addDbContext.
My Startup.cs like this
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<GastroDB>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IMainCategoryService, MainCategoryService>();
}
My Program.cs like this
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseKestrel().UseContentRoot(Directory.GetCurrentDirectory()).UseUrls("myIpAdress:80").UseIISIntegration().UseStartup<Startup>();
});
}
But iis can not get start. This is my errors ;
.Net Runtime:
Description: The process was terminated due to an unhandled exception.
Exception Info: System.ArgumentException: 'AddDbContext' was called with configuration, but the context type 'GastroDB' only declares a parameterless constructor. This means that the configuration passed to 'AddDbContext' will never be used. If configuration is passed to 'AddDbContext', then 'GastroDB' should declare a constructor that accepts a DbContextOptions<GastroDB> and must pass it to the base constructor for DbContext.
2)IIS AspNetCore Module V2
Application '/LM/W3SVC/1/ROOT' with physical root 'C:\Users\Tuğçe\Desktop\almanya projesi BE\EcommerceGastro.API\bin\Release\net5.0\publish\' hit unexpected managed exception, exception code = '0xe0434352'. First 30KB characters of captured stdout and stderr logs:
Unhandled exception. System.ArgumentException: 'AddDbContext' was called with configuration, but the context type 'GastroDB' only declares a parameterless constructor. This means that the configuration passed to 'AddDbContext' will never be used. If configuration is passed to 'AddDbContext', then 'GastroDB' should declare a constructor that accepts a DbContextOptions<GastroDB> and must pass it to the base constructor for DbContext.
I understand i will shoul add my context constructor like this
public GastroDB(DbContextOptions<GastroDB> options):base(options){}
But i cant add because first start like that on DBContext:
public class GastroDB : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("server=.; database=GastroDB; user id=sa; password=123;");
}
private static GastroDB _dbInstance;
public static GastroDB DBInstance
{
get
{
if (_dbInstance == null)
{
_dbInstance = new GastroDB();
}
return _dbInstance;
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new MyMap());
...
}
public DbSet<MyClass> MyClass{ get; set; }
....
}
}
If i add ctor on this code, my some services throw exeption because i use like this
using (var transaction = new GastroDB())
{
var productList = transaction.Set<DBProduct>().Include(x => x.ProductImage).ToList();
return this.mapper.Map<List<Product>>(productList);
}
How can i fix this problems i dont know how. Please help me
You Should create a constructor that accept
DbContextOptions<GastroDB>.
You don't need to use public static GastroDB DBInstance because
DbContext are registerd as Scoped life time.
public class GastroDB : DbContext
{
public GastroDB(DbContextOptions<GastroDB> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("server=.; database=GastroDB; user id=sa; password=123;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new MyMap());
...
}
public DbSet<MyClass> MyClass{ get; set; }
....
}
}
3 . If you want your DbContext register as singleton lifetime you can use below code instead of create a static property in DbContext
services.AddDbContext<GastroDB>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"))
}, ServiceLifetime.Singleton);

I'm new to .NET Core 2.1 MVC and I'm having trouble understanding how a few things work

I'm currently following a .Net Core Angular 8 tutorial in Udemy. I'm able do get/post requests in Postman and I can also see what I've posted in a .db file using sqlite as my database and viewing the data through Db Browser. Everything seems to be working great but is all for nothing if I can't comprehend what's going on in some areas of the application. I would really appreciate it if someone could help me answer a few questions.
My entire project is in GitHub: https://github.com/cjtejada/ASP.NetCoreAngular8/tree/master/DatingApp.API
Problem 1: I have the following the following controller:
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly IAuthRepository _repo;
private readonly IConfiguration _config;
public AuthController(IAuthRepository repo, IConfiguration config)
{
_repo = repo;
_config = config;
}
[HttpPost("register")]
public async Task<IActionResult> Register(UserForRegisterDto userForRegisterDto)
{
// validate request
userForRegisterDto.Username = userForRegisterDto.Username.ToLower();
if (await _repo.UserExists(userForRegisterDto.Username))
return BadRequest("User already exists");
var userToCreate = new User
{
Username = userForRegisterDto.Username
};
var createdUser = await _repo.Register(userToCreate, userForRegisterDto.Password);
return StatusCode(201);
}
}
I know that when the client makes a request to register, the register() method will be called and the Username that gets passed in will set the Username from DTO userForRegisterDto. After this then we call method UserExists() to check if the user exists in our database.
Question 1:
How is _repo aware of the logic in method UserExists() when it is only using the interface IAuthRepository? I know that IAuthRepository and class AuthRepository are somehow linked but I don't see anywhere in the app where Constructor DI is happening. My suspicion is that it has something to do with this line in startup.cs under the ConfigureServices method :
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(x => x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddCors();
services.AddScoped<IAuthRepository, AuthRepository>(); //<---- This Line
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("AppSettings:Token").Value)),
ValidateIssuer = false,
ValidateAudience = false
};
});
}
After these two are "linked up", then the UserExists() method can be accessed through the AuthRepository class:
public class AuthRepository : IAuthRepository
{
private readonly DataContext _context;
public AuthRepository(DataContext context)
{
_context = context;
}
public async Task<User> Login(string username, string password)
{
}
private bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
{
}
public async Task<User> Register(User user, string password)
{
byte[] passwordHash, passwordSalt;
CreatePasswordHash(password, out passwordHash, out passwordSalt);
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
await _context.Users.AddAsync(user);
await _context.SaveChangesAsync();
return user;
}
private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
{
}
public async Task<bool> UserExists(string username)
{
if (await _context.Users.AnyAsync(x => x.Username == username))
return true;
return false;
}
}
I've been reading about the AddScoped method and what it does but this is not clear to me that this is the case. Any clarification as to how this works would be great.
Problem 2:
This one is more or less the same. If we keep following the path of the request we will hit the register() method in the AuthRepository class.
Question 2:
How does this class have access to the properties of DataContext _context when I also can't spot any instances of constructor DI anywhere?
Here are the rest of my project files if needed:
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(x => x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddCors();
services.AddScoped<IAuthRepository, AuthRepository>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("AppSettings:Token").Value)),
ValidateIssuer = false,
ValidateAudience = false
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
//app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
app.UseAuthentication();
app.UseMvc();
}
}
DataContext.cs
public class DataContext : DbContext
{
public DataContext(DbContextOptions<DataContext> options) : base (options){}
public DbSet<Value> Values { get; set; }
public DbSet<User> Users { get; set; }
}
Any clarifications and suggestions are greatly appreciated. Thanks, all.
You are correct. The line services.AddScoped<IAuthRepository, AuthRepository>(); simply instructs the ASP.NET Core service container to substitute an instance of concrete class AuthRepository wherever it sees a reference to IAuthRepository at runtime.
The various Add* methods all do the same thing under the hood regarding registering the mapping of interfaces => classes, the key difference is the scope of the created class, i.e. how long it persists for:
AddScoped classes will be created at the beginning of every request to the server, and destroyed at the end of every request. In other words, every request results in a new instance of that class being created.
AddSingleton classes are created when your ASP.NET Core application starts up, and are destroyed when it shuts down. In other words, only a single instance of that class exists within your application.
AddTransient classes are recreated whenever they are requested. In other words, if a page on your site used the same service transient twice, there would be two instances created. (Contrast this with a scoped service, where only a single instance would be created, as each page is a single request.)
A fuller explanation, including examples: https://stackoverflow.com/a/38139500/70345
In order to fulfill (1) by creating an instance of your class AuthRepository, the service container needs to call that class's constructor. The container inspects your class to find the first public constructor and retrieves any arguments to that constructor, in this case an instance of the DataContext class. The container then searches its internal class mappings for that class and, because you have registered that mapping via services.AddDbContext<DataContext>(...), is able to construct and return the class instance. Thus it's able to pass that instance to AuthRepository, so AuthRepository is constructed successfully.
The AddDbContext method is simply a wrapper around AddScoped, that performs some additional scaffolding to allow Entity Framework DbContexts to work correctly.
For the official explanation, refer to Microsoft's official page on DI and IoC.
Question 1 - You've right this line in Startup.cs provide creating a new object AuthRepository. For this example you must to know that DI container creates an AuthRepository object for you based on the interface and his own implementation and you only need to pass an interface in properly constructor. AddScope() is related with lifetime of created objects. When you register object by method AddScope() then the object will be created for a single request and after the request, the object will be disposed.
Question 2 - Your dbContext is registered in DI container. AddDbContext() is a specific extension method provided to registration of entity framework dbContextes. This line of code registers your dbContext with connection strings got from the appSetting.json file.
services.AddDbContext<DataContext>(x =>
x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
This DbContext is injected into the constructor of the AuthRepository class and when you use this class DI container created DbContext instance for you.
private readonly DataContext _context;
public AuthRepository(DataContext context)
{
_context = context;
}

asp.net core web api, how to inject the connection string

Here is my asp.net core project structure
1- ASP.NET CORE Web API (contains aspsettings.json)
"ConnectionStrings": {
"DefaultConnection": "Server=(local)\\SQLEXPRESS;Database=testdb;Trusted_Connection=True;"
}
2-SERVICES Project (Web API Call method from Services Project)
3-REPOSITORY Project (Services call method from Repository Project and Repository Project include the DATA Project where all the models are)
4-DATA Project where it's contain all the model with code first
public class TtEntities : DbContext
{
public virtual DbSet<RoomMessage> RoomMessage { get; set; }
public virtual DbSet<UserRoom> UserRoom { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=(local)\SQLEXPRESS;Database=testdb;Trusted_Connection=True;");
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
....
As you can see, I hardcoded the connection on the method OnConfiguring which is not the best practice for sure.
Is there a way to pass the connection string from the configuration file of the Web API Project?
Is update database command will still work if we pass the connection from the file aspsettings.json from web api project ?
Thanks a lot
A simple solution is like this:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
}
Consider how DefaultConnection is used in line 13. Also a sample appsettings is like as follow:
{
"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-WebApplication5;"
}
}
DI solves this problem perfectly and .NET Core 2.0 has Microsoft DI thats provides clearly experience with DI.
oh, lets starts(i think that DATA Project and REPOSITORY Project should be one)
from REPOSITORY Project
change your REPOSITORYClass to
public class REPOSITORYClass
{
private readonly TtEntities _db;
public REPOSITORYClass (TtEntities db){
_db = db;
}
//some your staff of REPOSITORYClass thats uses _db
}
now go to SERVICES Project
lets change some service that uses REPOSITORYClass
public class SomeService
{
private readonly REPOSITORYClass _repo;
public SomeService (REPOSITORYClass repo){
_repo = repo;
}
//other staff of SomeService thats uses _repo
}
after that go to ASP.NET CORE Web API startup file and add to
public void ConfigureServices
// Get connection of your repo
string connection = Configuration.GetConnectionString("DefaultConnection");
// add TtEntities as service
services.AddDbContext<TtEntities>(options =>
options.UseSqlServer(connection));
//add your repo
services.AddTransient<REPOSITORYClass>();
//add your service
services.AddTransient<SomeService>();
now go to the contoller thats uses your SomeService
public class SomeController: Controller
{
private readonly SomeService _someService;
public SomeController(SomeService someService){
_someService = someService;
}
//And use whatever your wants from your service that injected with deps of repo and injected db entity with connection
public string SomeMethod()
{
return _someService.SomeMethod();
}
}
And use whatever your wants from your service that injected with deps of repo and injected db entity with connection
thats all
PS also recommend to read this Introduction to Dependency Injection in ASP.NET Core

ASP.NET 5 - Using a Configuration Setting

I am playing with ASP.NET 5. I am trying to understand the new configuration model. I have read several articles. However, I am still unsuccessful in loading a configuration setting. My config.json file looks like this:
{
"App" : {
"Info" : {
"Version":"1.0.0",
"ReleaseDate":"03-15-2015"
}
}
}
My Startup.cs file looks like this:
public class Startup
{
public IConfiguration Configuration { get; private set; }
public Startup()
{
Configuration = new Configuration()
.AddJsonFile("config.json");
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseErrorPage();
app.UseMvc(routes =>
{
routes.MapRoute("default", "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index" });
});
app.UseMvc();
app.UseWelcomePage();
}
}
In one of my controllers, I have the following
MyController.cs
using System;
using Microsoft.AspNet.Mvc;
namespace MyOrg.MyApp
{
public class MyController : Controller
{
[HttpGet()]
public ActionResult Index()
{
var version = Configuration.Get("App:Info:Version");
return new HttpStatusCodeResult(200);
}
}
}
When I start the app, I get an error that says:
error CS0103: The name 'Configuration' does not exist in the current context
at Microsoft.Framework.Runtime.Roslyn.RoslynProjectReference.Load(IAssemblyLo
adContext loadContext)
at Microsoft.Framework.Runtime.Loader.ProjectAssemblyLoader.Load(String name,
IAssemblyLoadContext loadContext)
at Microsoft.Framework.Runtime.Loader.ProjectAssemblyLoader.Load(String name)
at kre.host.LoaderContainer.Load(String name)
at kre.hosting.RuntimeBootstrapper.<>c__DisplayClass6_0.<ExecuteAsync>b__4(As
semblyName assemblyName)
at kre.hosting.RuntimeBootstrapper.<>c__DisplayClass6_0.<ExecuteAsync>b__7(Ob
ject sender, ResolveEventArgs a)
at System.AppDomain.OnAssemblyResolveEvent(RuntimeAssembly assembly, String assemblyFullName)
What am I doing wrong? I feel like I've followed the examples I've seen. Yet, I can figure out what I'm doing wrong.
Clearly you want to access Configuration property in your Startup class. And the error method says it doesn't know what Configuration is. So you need a using statement or a fully qualified name. Also, you should avoid naming things the same thing as stuff found in the framework. Your Startup class has a Configuration property, but it also tries to use the Configuration class from Microsoft.Framework.ConfigurationModel. How confusing is that?
Your Configure() method in Startup needs a using statement or fully qualified name so it knows what the Configuration class is.
using Microsoft.Framework.ConfigurationModel; //at the top of your class
Configuration = new Configuration(); //later in the code, we can access without fully qualifying name
or
Configuration = new Microsoft.Framework.ConfigurationModel.Configuration();
In your controller, you may have a similar issue. Replace MyOrg.MyApp.Startup in the example below with whatever the namespace is for your Startup class.
using MyOrg.MyApp.Startup //at the top of your class
Startup.Configuration.Get("App:Info:Version"); //later in the code, we can access without fully qualifying name
or
MyOrg.MyApp.Startup.Startup.Configuration.Get("App:Info:Version");
Better way of doing things
That should be enough to get you started. However, accessing the Startup class to retrieve your configuration isn't ideal, because now your controller's action methods depend on having the Startup class there. That's not very unit testable. Ideally your controllers should be isolated from each other. You should define some sort of interface to hold the configuration info you want, then have the controller depend on that interface. When you're in your site, you'll respond with a class specific to the site's configuration. When unit testing, you can have tight control over the test values by using a different class.
interface ISiteConfig
{
string Version {get; set;}
DateTime ReleaseDate {get; set;}
}
public class SiteConfig : ISiteConfig
{
public string Version {get; set;}
public DateTime ReleaseDate {get; set;}
public SiteConfig()
{
var c = new Configuration()
.AddJsonFile("config.json");
Version = c.Get("App:Info:Version");
ReleaseDate = c.Get("App:Info:ReleaseDate"); //may need to parse here
}
}
public class TestConfig : ISiteConfig
{
public string Version {get; set;}
public DateTime ReleaseDate {get; set;}
public TestConfig(string version, DateTime releaseDate)
{
Version = version;
ReleaseDate = releaseDate;
}
}
Then you'd use Dependency Injection to inject instances of your configuration into the Controller.
public class MyController : Controller
{
private readonly ISiteConfig Config;
public MyController(ISiteConfig config)
{
Config = config;
}
[HttpGet()]
public HttpStatusCodeResult Index()
{
var version = Config.Version;
return new HttpStatusCodeResult(200);
}
}
public class Startup
{
public void Configure(IBuilder app)
{
...
app.UseServices(services =>
{
...
// Set up the dependencies
services.AddTransient<ISiteConfig, SiteConfig>();
...
});
...
}
}
Now you can more easily unit test your action methods, because your unit tests can use the TestConfig class while the site can use the SiteConfig class. And also if you want to change how your configuration is done, you don't have to replace strings in a bunch of different places. You'll have one class where you do so, the rest is strongly typed and easy to change without blowing up your application.
Your unit test might look like this:
//Arrange
var testConfig = new TestConfig("1.0", DateTime.Now );
var controller = new MyController(testConfig );
//Act
var response = controller.Index();
//Assert
Assert.AreEqual(200, response.StatusCode);
As of Beta 5 the accepted answer is no longer correct. There is no longer a Get method on IConfiguration. Also the way of constructing the configuration object is also changed.
The following code works on Beta 7:
// showing using statements here since this is new from Beta 5
using Microsoft.Dnx.Runtime; // renamed was Microsoft.Framework.Runtime
using Microsoft.Framework.Configuration; // renamed was Microsoft.Framework.ConfigurationModel
// other using statements here
// Startup constructor. Note: now takes IApplicationEnvironment
// this is required in order to get base path
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
// Setup configuration sources.
var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
.AddJsonFile("config.json")
.AddJsonFile("dbconfig.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
// property to hold configuration object created in constructor
public IConfiguration Configuration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
// this will bind to an IOptions<AppSettings> instance
// where AppSettings is a class you define that has a set of
// properties that match your configuration section loaded from the
// json file
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
// here I am loading a connection string from a json file and passing into an
// new EF 6.x DB Context class
services.AddInstance<TalentAgencyContainer>(new TalentAgencyContainer(Configuration["ConnectionStrings:TalentAgencyContainer"]));
// Add MVC services to the services container.
services.AddMvc();
}

Resources