This is my C# code to send info to the data basee:
private void DbConnection_Set(string user_login, string user_password, string user_name)
{
using (DB_Connection db = new DB_Connection())
{
Users users = new Users
{
Name = user_name,
Password = user_password,
Login = user_login
};
db.users.Add(users);
db.SaveChanges();
}
}
So I'm getting the error at the line db.SaveChanges()
My connection to data base:
public partial class DB_Connection : DbContext
{
public DB_Connection() { }
public DB_Connection(DbContextOptions<DB_Connection> options) : base(options) { }
public virtual DbSet<Users> users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySql(
"server=https:https://mysql80.hostland.ru;database=db;uid=smth;password=smth!;",
new MySqlServerVersion(new Version(8, 0))
);
}
}
I can definitely say there's a total mistake at this line "server=https:https://mysql80.hostland.ru;database=db;uid=smth;password=smth;" but I have no any idea how to correct this.
The error I got:
System.InvalidOperationException: 'An exception has been raised that is
likely due to a transiet failure. Consider enabling transient error resiliency by adding
'EnableRetryOnFailure()' to the 'UseMySql' call'
The server I use is MySQL80
Related
I'm trying to test the below function using Nunit:
public static void Create(Contact contact)
{
using (var db = new PhonebookContext())
{
db.Database.EnsureCreated();
try
{
db.Contacts.Add(contact);
db.SaveChanges();
Console.WriteLine($"Successfully added {contact.Name}!");
}
catch
{
Console.WriteLine(Helpers.CreateErrorMessage, contact.Name);
}
}
}
This is my current test:
[Test]
public void Create_Contact_DbRowIsAdded()
{
var contact = new Contact { Name = "Abhinav", PhoneNumber = 1234567890, };
SqlAccess.Create(contact);
Assert.Equals(contact, SqlAccess.GetLastContact());
}
The test fails with the following error:
System.InvalidOperationException : No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
If it helps, here's the code for the dbContext (which I believe the test has no access to):
public class PhonebookContext : DbContext
{
public DbSet<Contact> Contacts => Set<Contact>();
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
try
{
optionsBuilder.UseSqlServer(System.Configuration
.ConfigurationManager
.ConnectionStrings["SQLServer"]
.ConnectionString);
}
catch (Exception ex)
{
Console.WriteLine("An unknown error occurred while creating the database. Please make sure SQL server is running.");
Console.WriteLine(ex.Message);
}
}
}
The function works perfectly, except when it is put through the test.
Am I missing something?
That's because you do not provide in your's PhonebookContext the db configuration for Contact class (which is db entry i guess).
So in order to fix that you should do something simmilar:
internal class ContactDbConfiguration : IEntityTypeConfiguration<Contact>
{
public void Configure(EntityTypeBuilder<TaskDto> builder)
{
// register your properties of contact class here for example:
builder.HasKey(t => t.Id);
}
}
And please add on model creating method in your PhonebookContext:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new ContactDbConfiguration());
base.OnModelCreating(modelBuilder);
}
Finally your dbContext should be like this:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// your code here
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new ContactDbConfiguration());
base.OnModelCreating(modelBuilder);
}
public DbSet<Contact> Contacts { get; set; }
I'll try to add more information as requested:
appsettings.json
"ConnectionStrings": {
"Debug": "server=Server;user id=myuser;password=password;port=3306;database=database1;",
"Demo": "server=Server;user id=myuser;password=password;port=3306;database=database2;"
}
Both servers are the same, but two different databases (1 and 2 for example).
Startup.cs:
services.AddTransient<AppDb>(_ => new Controllers.AppDb(Configuration["ConnectionStrings:Database1"]));
services.AddTransient<AppDb>(_ => new Controllers.AppDb(Configuration["ConnectionStrings:Database2"]));
I have both this services for the ConnectionStrings, currently the Database isn't working.
AppDb.cs
namespace ProjectDatabase.Controllers
{
public class AppDb
{
public MySqlConnection Connection { get; }
public AppDb(string connectionString)
{
Connection = new MySqlConnection(connectionString);
}
public void Dispose() => Connection.Dispose();
}
}
I have this that calls and connects to the database, but it's only connecting to Database1.
ClientsController
namespace ProjectDatabase.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ClientsController : ControllerBase
{
public ClientsController(AppDb db)
{
Db = db;
}
// GET api/clients
[HttpGet]
public async Task<IActionResult> GetLatest()
{
await Db.Connection.OpenAsync();
var query = new clientsQuery(Db);
var result = await query.LatestClientsAsync();
return new OkObjectResult(result);
}
public AppDb Db { get; }
}
}
I place the Get Request for the Database1.
Question: I already have connected to Database1 and would like to connect to Database2 one at a time, how can achieve this ? How can I tell the app to Get the data from Database2 ? I already have the 2nd Connection String how can i access both of them ?
Edited for more clarity.
If i understand correctly, you want to switch between connection that depends on environment.
So you can look into asp.net configuration.
Create 2 env files and then put your connection strings into them.
For example:
appsettings.Development.json
"ConnectionStrings": {
"MySql": "Dev DB connection string"
},
appsettings.Demo.json
"ConnectionStrings": {
"MySql": "Demo DB connection string"
},
and your setup code will looks like this
services.AddTransient(_ => new
Controllers.AppDb(Configuration["ConnectionStrings:MySql"]));
So after that manipulations you just need to switch environment and you will get right connection string.
Read about how to setup multi environment configuration you can here:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/environments
Startup.cs:
services.AddTransient<AppDb>(_ => new Controllers.AppDb(Configuration["ConnectionStrings:Debug"], Configuration["ConnectionStrings:Demo"]));
AppDb.cs
public class AppDb
{
public MySqlConnection conDebug { get; }
public MySqlConnection conDemo { get; }
public AppDb(string connectionStringDebug, string connectionStringDemo)
{
conDebug = new MySqlConnection(connectionStringDebug);
Hashtable hasDB = new Hashtable();
hasDB["debug"] = conDebug;
}
public void Dispose() => conDebug.Dispose();
}
}
Solved.
namespace ProjectDatabase.Controllers
{
public class AppDb
{
public MySqlConnection Connection { get; }
public MySqlConnection Con { get; }
public AppDb(string connectionString)
{
Connection = new MySqlConnection(connectionString);
Con = new MySqlConnection(connectionString);
}
public void Dispose() => Connection.Dispose();
}
}
This is my AppDb.cs, my controller for the connection, what if I add a second MySqlConnection and then in my ClientsController I specify the connection to be open:
namespace ProjectDatabase.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ClientsController : ControllerBase
{
public ClientsController(AppDb db)
{
Db = db;
}
// GET api/clients
[HttpGet]
public async Task<IActionResult> GetLatest()
{
await Db.Connection.OpenAsync();
var query = new clientsQuery(Db);
var result = await query.LatestClientsAsync();
return new OkObjectResult(result);
}
public AppDb Db { get; }
}
}
Instead of having await Db.Connection.OpenAsync() I could create another Controller and do await Db.Con.OpenAsync() which will be my 2nd Connection to the my 2nd database.
Is this something that will not cause me any problems or has any cons to it ?
I am trying to unit test with the EF Core in-memory database like so:
namespace ContosoTests
{
public class TrendServiceTests
{
private static Microsoft.EntityFrameworkCore.DbContextOptions<TestContext> options = new
Microsoft.EntityFrameworkCore.DbContextOptionsBuilder<TestContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
private static TestContext _context = new TestContext(options);
private readonly TrendService trendService = new TrendService(_context);
private void SeedInMemoryDb()
{
if (!_context.TrendHistories.Any())
{
_context.TrendHistories.Add(new TrendHistory { IsActive = true, Quarter = E_Quarter.Q1,
TrendYear = 2020 });
}
if (!_context.Controls.Any())
{
_context.Controls.Add(new Control { IsActive = true});
_context.Controls.Add(new Control { IsActive = true});
_context.Controls.Add(new Control { IsActive = false});
}
_context.SaveChanges();
}
}
My TestContext inherits from my live context class to avoid the error:
Services for database providers 'Microsoft.EntityFrameworkCore.InMemory', 'Microsoft.EntityFrameworkCore.SqlServer' have been registered in the service provider. Only a single database provider can be registered in a service provider
So my TestContext just looks like:
public class TestContext : ContosoContext
{
public TestContext(DbContextOptions<TestContext> options)
{
}
public TestContext()
{
}
}
When I use the new instance of TestContext (_context) in my test class, all the live data for ContosoContext is there.
I was expecting it to be a new instance of the context class with no data so that I could test my DAL code with controlled data. But this is not the case.
I am fairly new to unit testing so any help is much appreciated.
Edit:
Here are the relevant parts of my contoso context class
public class ContosoContext: IdentityDbContext<ContosoApplicationUser>
{
public ContosoContext(DbContextOptions<ContosoContext> options) : base
(options)
{
}
public ContosoContext()
{
}
//all my DBSets here
protected override void OnConfiguring(DbContextOptionsBuilder
optionsBuilder)
{
optionsBuilder.UseSqlServer("MyConnectionString");
}
}
So the issue is that my onconfiguring method handles the connection string directly??
To fix the error you need to remove optionsBuilder.UseSqlServer("MyConnectionString"); in OnConfiguring method to avoid registering multiple database providers, change it to this:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if(!optionsBuilder.IsConfigured)
optionsBuilder.UseSqlServer("MyConnectionString");
}
I'm trying to have a migration using dotnet ef migrations add MyMigration, but shell returns an error: Unable to create an object of type 'AuthDbContext'. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728.
This is my AuthDbContext.cs file:
using Auth.Data.Models;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace Auth.Data
{
public class AuthDbContext : IdentityDbContext<User>
{
private readonly string connStr;
//public DbSet<User> Users { get; set; }
public AuthDbContext(DbContextOptions<AuthDbContext> options) : base(options) //string connStr)
{
//this.connStr = connStr;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// string connStr = "";
// connStr = "";
// if (!optionsBuilder.IsConfigured)
// {
// optionsBuilder
// .EnableSensitiveDataLogging(true)
// .UseSqlServer(connStr);
// }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("auth");
//modelBuilder.Entity<User>().HasKey(p => new { p.User_id });
base.OnModelCreating(modelBuilder);
}
}
}
Can somebody help me to understand? Thanks.
You forgot to add this line
base.OnConfiguring(optionsBuilder);
EF Core can't finish context instantiating.
I am trying to add some data to a ASP.NET Web API from the same solution, but somehow I am getting this error from SQL Server.
This is my context
public class SampleCtxt: DbContext
{
public DbSet<TodoItem> TodoItems { get; set; }
public SampleCtxt(DbContextOptions<SampleCtxt> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(#"Server=.\SQLEXPRESS;Database=APITESTDB; Initial Catalog=APITestDb; Trusted_Connection=True;");
}
}
Configure services method from API
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<SampleCtxt>(opt =>
Catalog=master;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False; Database = APITESTDB;"));
opt.UseSqlServer(
Configuration
.GetConnectionString("DefaultConnection")));
services.AddControllers();
}
Connection string from json
"ConnectionStrings": {
"DefaultConnection": "Server=.\\SQLEXPRESS;Database=APITESTDB; Initial Catalog=APITestDb Trusted_Connection=True;"
},
Adding data from another console project
static void Main(string[] args)
{
using (SampleCtxt ctxt = new SampleCtxt(
new Microsoft.EntityFrameworkCore.DbContextOptionsBuilder<SampleCtxt>().Options))
{
TodoItem todoItem = new TodoItem() { Name = "qualquer" };
ctxt.TodoItems.Add(todoItem);
ctxt.SaveChanges();
}
}
Everything seems fine but I am getting this error:
Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)
Its seens that the ConnectionString was wrong and the instantiation of the class context, I solved the problem by adding a parameterless constructor and by correcting the OnConfiguring Method
public class SampleCtxt: DbContext
{
public DbSet<TodoItem> TodoItems { get; set; }
public SampleCtxt()
{
}
public SampleCtxt(DbContextOptions<SampleCtxt> options)
: base(options)
{
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=APITESTDB;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False;");
}
}