How to specify an Entity Framework Connection String in API Project - c#

Question: How do I specify the Entity Framework connection string within a .NET API?
I am accustomed to creating a DAL class and specifying the base connection string like I did here.
public class LocalContext : DbContext
{
public LocalContext() : base("LocalDBContext")
{
}
public DbSet<Weapons> Weapons { get; set;
}
Which in turn grabs the LocalDBContext connection string from the web.config or appsettings.json.
"ConnectionStrings": {
"LocalDBContext": "Server=.;Database=Weapons;Trusted_Connection=True;"
},
This is what I have done in the past in various web apps but not sure if I have to do something different with an API?
I would expect it to call and save into "Weapons" at "Server=." however it instead created a new Database called "LocalDBContext" at the connection of "(localdb)\mssqllocaldb". Any tips would be greatly appreciated!

In EF core you don't need to send a connection to the base class with the constructor, just follow this approach:
public partial class LocalContext : DbContext
{
public LocalContext ()
{
}
public LocalContext(DbContextOptions<LocalContext> options) :
base(options)
{
}
public virtual DbSet<Weapon> Weapons { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
//warning You can move this code to protect potentially sensitive
information
//in connection string.
optionsBuilder.UseSqlServer("Data Source= .;Initial
Catalog=Weapons;Trusted_Connection=True;");
}
}
}

The given String "LocalDBContext" is interpreted as Connectionstring, see official Documentation on DbContext(String).
Do something like:
public class LocalContext : DbContext
{
public LocalContext (DbContextOptions<LocalContext> options)
: base(options)
{
}
....

I have some questions below:
Questions:
Did you add Entity data model in your API solution?
If yes, didn't you save connection string in config file while adding EDM?
While adding EDMX in solution, model window asks to connect the database. Once EDM connects with database, it asks to save connection string in configuration file. You can add tables, functions, SPs, views. This way EDM connects with actual database rather picking different database.

Related

C# EF Core 6 How do I pass connection string into Context constructor as a string and not as an option

I have a strange requirement here. We have a ton of databases that are basically idential but with different clients. So each db has the same table structures. With that being said, I can't use the standard way of setting up the connectionstring in the startup. I would like to see if there is a way I can pass the connectionstring in the contructor without it being the DbContextOptions<> object. We use to be able to do that in earlier versions of EF but now it's expecting that option in the base().
The other option is just doing raw ADO with a command object, which I REALLY don't want to do, I would prefer if I could use EF.
So this is what it looks like, but would prefer to have a second constructor that allows the connectionString to be passed in. NO Start Up or NO appsettings.json, just want to pass in a string with the connectionString.
`
public class Context : DbContext
{
public Context(DbContextOptions<Context> options) : base(options) // <== base expects only options
{
Database.SetCommandTimeout(9000);
}
public Context(string connectionString) : base()
{
this.Database.Connection ????? What to do here
}
public DbSet<Transcription> Transcriptions { get; set; }
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.HasDefaultSchema("dbo");
builder.Entity<Transcription>().ToTable("Transcriptions", "dbo");
}
}`
Any idea why this keeps throwing errors or why it won't allow me to set the connectionString instead of using options?
I have looked an keep getting old solutions from 12+ years ago, nothing for EF 6
Possibly more convenient would be to use multitenancy approaches described in the docs but if you still want to use just the ctor you can override the OnConfiguring method and use connection string from the ctor there:
public class Context : DbContext
{
private readonly string _connectionString;
public Context(string connectionString)
{
_connectionString = connectionString;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
// setup options - provider, connection string, etc.
optionsBuilder.UseNpgsql(_connectionString);
}
}
}
Or manually building options from the connection string:
public class Context : DbContext
{
public Context(string connectionString):base(BuildOpts(connectionString))
{
}
private static DbContextOptions<Context> BuildOpts(string connectionString) =>
new DbContextOptionsBuilder<Context>()
.UseNpgsql(connectionString) // setup options - provider, connection string, etc.
.Options;
}

ASP.NET Web Forms - Seeder not working with MySQL connection

I am trying to follow the ASP.NET Web Forms tutorial, just with a MySQL connection instead of local: ASP.NET Web Forms - Create the Data Access Layer
I already tested that the connection string works, because I made a dummy table in an existing DB and I can see it in the Server Explorer when I run the app.
But according to the tutorial, it was also supposed to create a DB and tables and seed it. But nothing happens.
This is my connection string:
<add name="myProject" connectionString="Data Source=MY_PC_NAME;User Id=testuser; Password=testpassword; Integrated Security=False" providerName="System.Data.SqlClient"/>
This is the ProjectContext file:
namespace myProject.Models
{
public class ProjectContext : DbContext
{
public ProjectContext() : base("base_name")
{
}
public DbSet<Item> Items { get; set; }
public DbSet<Category> Categories{ get; set; }
}
}
And the ProjectDatabaseInitializer:
public class ProjectDatabaseInitializer : DropCreateDatabaseIfModelChanges<ProjectContext>
{
protected override void Seed(ProjectContext context)
{
GetItems().ForEach(i => context.Items.Add(i));
GetCategories().ForEach(c => context.Categories.Add(c));
}
// some seeding lists below
I then added the initializer to the Global.asax.cs:
Database.SetInitializer(new ProjectDatabaseInitializer());
And both Items and Categories have their corresponding Item and Category models.
But when I run the app, the Server Explorer remains empty.
Note that I modified the original code of the tutorial a bit

How to configure Entity Framework in a separate project?

I have an ASP.NET MVC application EducationalCenter with the following structure of projects:
DbContext file is EducationalCenterContext.cs in the Data project and looks as follows:
public sealed class EducationalCenterContext: DbContext
{
public DbSet<Student> Students { get; set; }
public EducationalCenterContext( DbContextOptions<EducationalCenterContext> options)
: base(options)
{
Database.EnsureCreated();
}
}
And in Startup.cs file, the dbContext configured as follows in ConfigureService():
services.AddDbContext<EducationalCenterContext>
(options => options.UseSqlServer("Server=localhost;Database=EducationalCenterDb;Trusted_Connection=True;MultipleActiveResultSets=true"));
This is my working version to which I came by fixing errors when try to add-migration. However it seems awful to me that my web app has project reference to the Data project.
What was my first idea:
In appsettings.json I created this section :
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=EducationalCenterDb;Trusted_Connection=True;MultipleActiveResultSets=true"
}
Then I created AppSettings class in the Common project:
public class AppSettings
{
public string ConnectionString { get; set; }
}
Then I try to pass ConnectionString in DAL via DI:
services.Configure<AppSettings>(Configuration.GetSection("ConnectionStrings"));
And created EducationalDbContext.cs:
public sealed class EducationalCenterContext: DbContext
{
private readonly string _connectionString;
public DbSet<Student> Students { get; set; }
public EducationalCenterContext( IOptions<AppSettings>, DbContextOptions<EducationalCenterContext> options)
: base(options)
{
_connectionString = app.Value.ConnectionString;
Database.EnsureCreated();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
}
But when I try to add-migration via PM Console, I ran into this error:
Could not load assembly 'EducationalCenter.Data'. Ensure it is referenced by the startup project 'EducationalCenter'
Then I added project reference and ran into the next error:
Unable to create an object of type 'EducationalCenterContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728
Then I added services.AddDbContext<> in Startup.cs and came to the working version which I mentioned above.
So...
Is it normal that my web app has reference to the data access project?
Is it possible to configure EF in the Data project and ensure normal separation between DAL, BLL and web app?
Putting the context and configuration in a separate project is fine.
You got the first error because "Education Center" was set as start up project but did not have reference to data project.
The second error is because the migration builder needs some connection information in the data project to resolve the connection (to compare EF state and database state) to determine what changes are needed.
First add reference in your data project to:
Microsoft.EntityFrameworkCore.Design
Then add a context factory in your data project that migration console command will discover:
internal class MyContextFactory : IDesignTimeDbContextFactory<MyContext>
{
public MyContext CreateDbContext(string[] args)
{
var dbContextBuilder = new DbContextOptionsBuilder<MyContext>();
var connString = "myconnection string";
dbContextBuilder.UseSqlServer(connString);
return new MyContext(dbContextBuilder.Options);
}
}

c# - Entity Framework ConnectionString won't update after changing App.Config in runtime

I'm developing a WPF application which depends on Entity Framework for data access.
At the first time installation I need to create a new connection string based on the User input, then updating App.Config according to that.
The problem is: after updating the App.Config file, Entity Framework doesn't detect the change and uses the old startup-time ConnectionString for instantiating the DbContext.
How can I update the Entity Framework's ConnectionString setting at runtime?
Entity Framework caches connection string, there isn't a method to force a refresh.
From this article: connection string given in DbContext constructor isn't cached then you can use this as workaround:
public class MyContext : DbContext {
public MyContext()
: base(ConfigurationManager.ConnectionStrings["MyConnection"].ConnectionString)
{
}
}
Had same issue today. Connection string is stored in cached App.Config file in obj folder.
Solution: Delete obj folder.
I had the same error. My new connection string was missing "Initial Catalog="
Global.cs
public class Global
{
public static string ConnectionString=String.Empty;
}
Store connection string as temporary in Global.cs first time after connection string saved in App.config.
DBContext.cs
public class DBContext: DbContext
{
public DbSet<User> UserInfo { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(
String.IsNullOrEmpty(Global.ConnectionString) ? ConfigurationManager.ConnectionStrings["your_connectionstring"].ConnectionString
: Global.ConnectionString
);
}
}
Firstly, you have already defined connection string in your App.config.
Hope you enjoy!

\Web Api and Frontend database

I want to have ASP.NET MVC website that would have some frontend for looking into, adding and other things with data. And then I want to have Web Api for getting data for mobile devices and so. I want to use code first from EF (and I am using Ninject). I create classes for hotel and others. I created HotelManagerContext and database is created and looks good. I am adding data by HomeController and by Repository for this. When I looked at database in Visual Studio data are there. But when I tried to use my HotelsController for Api datacontext is empty. What's wrong? What I forget to set? Something with connection string or what?
This is my ApiController:
public class HotelsController : ApiController
{
private IHotelRepository _hotelRepo { get; set; }
public HotelsController(IHotelRepository repo)
{
_hotelRepo = repo;
}
// GET api/Hotels
public IEnumerable<Hotel> GetHotels()
{
return _hotelRepo.GetAll();
}
// GET api/Hotels/5
public Hotel Gethotel(int id)
{
return _hotelRepo.Get(id);
}
}
This is part of my controller for frontend:
public class HomeController : Controller
{
private IHotelRepository _hotelRepo { get; set; }
public HomeController(IHotelRepository repo)
{
_hotelRepo = repo;
}
public ActionResult Index()
{
return View();
}
// next methods, for adding data and so
}
This is my repository:
public class HotelRepository : IHotelRepository
{
private HotelManagerContext db { get; set; }
public HotelRepository()
:this (new HotelManagerContext())
{
}
public HotelRepository(HotelManagerContext hotelManagerContext)
{
// TODO: Complete member initialization
this.db = hotelManagerContext;
}
public Models.Hotel Get(int id)
{
return db.hotels.SingleOrDefault(h => h.hotId == id);
}
public IQueryable<Models.Hotel> GetAll()
{
return db.hotels;
}
public Hotel Add(Hotel hotel)
{
db.hotels.Add(hotel);
db.SaveChanges();
return hotel;
}
}
This is my HotelManagerContext:
public class HotelManagerContext : DbContext
{
public HotelManagerContext() : base("name=HotelManagerContext")
{
}
public DbSet<Hotel> hotels { get; set; }
}
Edit:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IHotelRepository>().To<HotelRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new NinjectResolver(kernel);
}
Edit2:
Here is my connection string:
<add name="HotelManagerContext" connectionString="Data Source=(localdb)\v11.0; Initial Catalog=HotelManagerContext-20121219191411; Integrated Security=True; MultipleActiveResultSets=True; AttachDbFilename=|DataDirectory|HotelManagerContext-20121219191411.mdf" providerName="System.Data.SqlClient" />
And I just found that even in HomeController I have empty datacontext. So when I check content of database in Server Explorer there are data which I added (in HomeController). But everytime when I have request page (web api or frontend) datacontext is empty and I can add items there are counting from zero but in database there are already next but can't get it. It's really weird.
What does your connection string look like? "name=HotelManagerContext" seems incomplete. I think you would want to also explicitly specify providerName="System.Data.EntityClient" at the very least (see here). In any case, it is common practice to put the connection string in the Web.Config file and assign the name there (i.e. name="HotelMamangerContext") then, under normal circumstances, EF will just discover the connection string by convention as long as the name of your DbContext class matches the name of the connection string in Web.Config (otherwise you can still specify it explicitly in the constructor).
On a different note (I don't think this should be related to you current problem), you could consider injecting you DbContext as well. Then you could drop the parameter-less constructor on your repository class unless you need to keep it around for another reason such as unit testing. Also, if you are using Ninject.Web.Common, you may want to consider scoping the instances to the request level (see InRequestScope).
...
kernel.Bind<HotelMamangerContext>().ToSelf().InRequestScope();
kernel.Bind<IHotelRepository>().To<HotelRepository>().InRequestScope();
...
I can't find solution for this so I create new project and I did everything like in the question. I have same classes, copy and paste code frome question. I can't find any important difference but second time it's working.
I know this isn't exactly solution but in this case I could start my project from begging so I tried it and it really helps. Just don't know where is problem.

Categories

Resources