Is connection pool shared based on connection string value? - sql-server

I have ASP.NET Core Web API. The app has three functionalities that connects to DB. EF DbContext, Hangfire and Serilog Logging. All 3 reads the connection string from appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Error"
}
},
"Serilog": {
"Using": [ "Serilog.Sinks.MSSqlServer"],
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Server=serverip;Database=MyDb;Integrated Security=True;",
"tableName": "Logs",
"schemaName": "logging",
"autoCreateSqlTable": false
}
}
]
},
"ConnectionStrings": {
"DefaultConnection": "Server=serverip;Database=MyDb;Integrated Security=True;"
}
}
in Programs.cs I have configured Serilog that auto reads the connectionString from appsettings
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUrls("http://*:30000")
.UseStartup<Startup>()
.ConfigureLogging((hostingContext, logging) =>
{
if (!hostingContext.HostingEnvironment.IsLocal())
{
logging.ClearProviders();
}
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(hostingContext.Configuration)
.CreateLogger();
logging.AddSerilog();
});
in Startup.cs we have Hangfire and EF DbContext using the same connection value
public void ConfigureServices(IServiceCollection services)
{
//dbContext
var connection = configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<MyDBContext>(options => options.UseSqlServer(connection));
services.AddHangfire(config => config.UseSqlServerStorage(connection));
}
Serilog, has separate entry in appsettings for connection string but the value for the connection string is same.
Each funcationality has its own SQL schema. DbContext -> dbo schema, Hangfire->hangfire schema, Serilog ->logging schema
As per the documentation
A connection pool is created for each unique connection string. When a
pool is created, multiple connection objects are created and added to
the pool so that the minimum pool size requirement is satisfied.
Connections are added to the pool as needed, up to the maximum pool
size specified (100 is the default).
Since the value of the connection string is same, does that mean all these 3 funcationalities sharing the same connection pool?
UPDATE 1
The reason I asked this question because we were seeing error
System.InvalidOperationException: Timeout expired. The timeout period
elapsed prior to obtaining a connection from the pool. This may have
occurred because all pooled connections were in use and max pool size
was reached.
Here is my implementation of service. Since service is registered with Scope lifetime, the DI container should dispose service at the end of request and that should dispose the dbContext as well.
public interface IBaseService : IDisposable
{
}
public abstract class BaseService : IBaseService
{
private bool _disposed = false;
protected readonly MyDBContext _dbContext;
protected BaseService(MyDBContext dbContext)
{
_dbContext = dbContext;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Releases unmanaged and - optionally - managed resources.
/// </summary>
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
if (_dbContext != null)
{
_dbContext.Dispose();
}
// Free any other managed objects here.
}
// Free any unmanaged objects here.
_disposed = true;
}
}
public interface IOrderService : IBaseService
{
Task<Order> Create(Order order);
}
public class OrderService:BaseService,IOrderService
{
public OrderService():base(MyDBContext dbContext)
{
}
public async Task<Order> Create(Order order)
{
_dbContext.Orders.Add(order);
await _dbContext.SaveChangesAsync();
// at this point I am guessing the SQL connection will be closed by the DBContext
}
}
and in Startup.cs it service is regiered with Scope lifetime
services.AddScoped<IOrderService, OrderService>();

Related

How connect to an existing Azure SQL database with ASP.NET CORE MVC using Entity Framework Core with migrations?

I have an app using Azure App Services with SQL server and SQL database that are connect to my web app on asp MVC. I've used Distributed Sql Server Cache as a table on my database and so far everything is working well and connected to each other.
Now I want to do two things:
Add entity framework to my app (I already have the database and
connection string)
Run migration – after I've published my app (If I've added for a
example new line or new
table, now I have new version)
I'm not sure how to do those things , I've looked up on many guides and couldn't find an answer. I found a post similar to mine – but using azure functions - here
. I would appreciate it if someone can help me with the steps that I need to follow (like they did in that post) to get entity framework and the migration.
Here is my code:
Program.cs-
using Microsoft.Extensions.Azure;
using Azure.Identity;
var builder = WebApplication.CreateBuilder(args);
if(!builder.Environment.IsDevelopment())
builder.Configuration.AddAzureKeyVault(new Uri(Environment.GetEnvironmentVariable("VaultUri")), new DefaultAzureCredential());
builder.Services.AddControllersWithViews();
builder.Services.AddAzureClients(clientBuilder =>
{
clientBuilder.AddBlobServiceClient(builder.Configuration["storage:blob"], preferMsi: true);
clientBuilder.AddQueueServiceClient(builder.Configuration["storage:queue"], preferMsi: true);
});
builder.Services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = builder.Configuration.GetConnectionString("db");
options.SchemaName = "dbo";
options.TableName = "_Cache";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
Home Controller:
namespace WebAppAzure.Controllers
{
public class HomeController : Controller
{
private readonly BlobServiceClient storage;
private readonly ILogger<HomeController> logger;
private readonly IDistributedCache cache;
public HomeController(BlobServiceClient storage, ILogger<HomeController> logger,
IDistributedCache cache)
{
this.storage = storage;
this.logger = logger;
this.cache = cache;
}
public IActionResult Index()
{
var containerClient = storage.GetBlobContainerClient("public");
var blob = containerClient.GetBlobClient("image.jpeg");
var model = blob.Uri.ToString();
return View(model: model);
}
public IActionResult Privacy()
{
var stringModel = DateTime.Now.ToString();
cache.SetString("name", stringModel);
return View(model: $"SET: {stringModel}");
}
public IActionResult About()
{
var stringModel = cache.GetString("name");
return View(model: $"GET: {stringModel}");
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
Add entity framework to my app (I already have the database and connection string)
Use below code for add Entity framework and upload to azure app service and run migration command to migrate database.
DBcontext file in project.
using Microsoft.EntityFrameworkCore;
using WebApplication_72783922.Entity;
namespace WebApplication_72783922
{
public class DbConnectionEntity : DbContext
{
public DbConnectionEntity()
{
}
//string connectionString = Environment.GetEnvironmentVariable("ConnectionStrings:dbcon").ToString();
public DbConnectionEntity(DbContextOptions<DbConnectionEntity> options)
: base(options)
{
}
public virtual DbSet<Users> users { get; set; }
public virtual DbSet<department> Departments { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("Server=xxxx;Initial Catalog=database;Persist Security Info=False;User ID=adminserver72783922;Password=xxxx;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
}
Program.cs File code.
using Microsoft.Extensions.Azure;
using Azure.Identity;
using Microsoft.Extensions.Configuration;
var builder = WebApplication.CreateBuilder(args);
if (!builder.Environment.IsDevelopment())
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = "Server=xxxx;Initial Catalog=database;Persist Security Info=False;User ID=adminserver72783922;Password=xxxx;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";
options.SchemaName = "dbo";
options.TableName = "_Cache";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Run migration – after I’ve published my app
Enable Migration using this command on Package Manager Console enable-migrations
Then add-migration InitialCreate
Then create migrationadd-migration test-v1
update database update-database -verbose

ApplicationIntent=ReadOnly missing

I'm trying to create EF Core 3.1 context with readonly application intent for connection redirection to replica database.
When context's .ctor are called, connection string in SqlServerOptionsExtension extension of DbContextOptions has no ApplicationIntent=ReadOnly option.
Example code:
Startup.cs
protected override void DoEndConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkSqlServer()
.AddDbContext<ReadOnlyContext>(options =>
{
options.UseSqlServer("...;ApplicationIntent=ReadOnly");
}, ServiceLifetime.Scoped);
}
ReadOnlyContext.cs
public class ReadOnlyContext : DbContext
{
protected MovedContext(DbContextOptions<MovedContext> options) : base(options)
{
}
}
I have tried to set up connection in OnConfiguring method and it worked as intended.
How i could pass readonly connection string to context upon creating it from Startup class?

PostgreSQL and Blazor .Net Core 3.1

Are there any resources on how to use the current version of Blazor (3.1) and PostgreSQL?
I've tried writing the simplest code, just to see whether it connects to the database but I get this error message: System.Net.Dns:GetHostByName is not supported on this platform
a button click would activate this code:
async void connection()
{
var connString = "Host=Server1;Username=postgres;Password=pass;Database=BlazorData";
try
{
await using var conn = new NpgsqlConnection(connString);
await conn.OpenAsync();
errcheck = "success";
}
catch (Exception ex)
{
errcheck = ex.Message;
}
}
I explain how I use it with entity framework. It might help you.
in startup.cs, ConfigureServices method have this
services.AddEntityFrameworkNpgsql().AddDbContext<ApplicationDbContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("DefaultConnection")));
You need two packages to be installed through nuget
Npgsql.EntityFrameworkCore.PostgreSQL
Npgsql.EntityFrameworkCore.PostgreSQL.Design
in appsetting.json make sure you have setup connection string correctly, below one is mine. Host can be localhost if database is in the same machine as the database
"DefaultConnection": "Host=192.168.16.240;Port=5432;Username=postgres;Password=mypassword;Database=mydatabase;"
That's basically it.
then define a application db context with your tables
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions options) : base(options)
{
}
public DbSet<Room> Rooms { get; set; }
public DbSet<Meal> Meals { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
in package mangaer console
add-migration initial
update-database
you should see the tables created in PgAdmin.
and use your dbsets like usual c# lists. and remember to inject applicationdbcontext in the controllers you need it.
The error says you need to resolve the hostname by yourself. Either pass an IP address or use Dns.GetHostEntry
using System.Linq;
using System.Net;
using System.Net.Sockets;
...
async void connection()
{
var host = Dns.GetHostEntry("Server1");
var firstIpV4Address = host.AddressList.First(a => a.AddressFamily == AddressFamily.InterNetwork);
var connString = $"Host={firstIpV4Address};Username=postgres;Password=pass;Database=BlazorData";
try
{
await using var conn = new NpgsqlConnection(connString);
await conn.OpenAsync();
errcheck = "success";
}
catch (Exception ex)
{
errcheck = ex.Message;
}
}

Can't specify database name during jdbc connection

I'm using Spring MVC 4.3 to connect to a Miscorosft SQL Server with JDBC. My SQL Server have some databases, I'm trying to connect to TEST_DB one. But when I try to establish connection I receive this error:
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The server principal "testuser" is not able to access the database "A_Source_Db" under the current security context.
A_Source_Db is the first db in alphabetical order, so I think I can't specify the db name to connect to.
I use Hibernate too and Spring Data. These are some files I think are useful
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = "com.test.domain")
#PropertySource("classpath:db.properties")
#ComponentScan({"com.test", "com.test.domain.repository"})
public class HibernateConfig {
#Autowired
private Environment env;
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getRequiredProperty("mssql.driver"));
dataSource.setUrl(env.getRequiredProperty("mssql.url"));
dataSource.setUsername(env.getRequiredProperty("mssql.user"));
dataSource.setPassword(env.getRequiredProperty("mssql.password"));
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setPackagesToScan("com.test.domain");
entityManagerFactoryBean.setJpaProperties(hibProperties());
return entityManagerFactoryBean;
}
private Properties hibProperties() {
Properties properties = new Properties();
properties.put(DIALECT, "org.hibernate.dialect.SQLServerDialect");
properties.put(SHOW_SQL, true);
return properties;
}
}
This is my db.properties
mssql.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
mssql.url=jdbc:sqlserver://192.168.1.100:1433;databaseName=TEST_DB
mssql.user=testuser
mssql.password=testPwd

CodeFirst: Cannot open database "MyDatabase " requested by the login. The login failed. Login failed for user 'MyDomain\MyUser'

So I've been getting this error all of a sudden, and I have no idea how to resolve it. MyDomain\MyUser is listed under server users, but since I'm using CodeFIrst, the database is not created yet, so I can't add MyDatabase to the user.
Here is my code:
ConnectionString:
<add name="MyDatabaseConnection" connectionString="Data Source=myServer; Database=MyDatabase.sdf;Trusted_Connection=True;Persist Security Info=True;Pooling=false" providerName="System.Data.SqlClient" />
Code:
public class MyDbContext: DbContext
{
public MyDbContext()
: base("MyDatabaseConnection")
{
}
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new UserConfiguration());
}
}
public class UserConfiguration : EntityTypeConfiguration<User>
{
public UserConfiguration()
{
ToTable("User");
Property(u => u.ID).HasColumnName("UserID").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
protected void Application_Start()
{
Database.SetInitializer<MyDbContext>(new MyDbContextInitializer());
using (MyDbContext db = new MyDbContext())
{
db.Database.Initialize(false);
}
...
}
public class MyDbContextInitializer : DropCreateDatabaseIfModelChanges<MyDbContext>
{
protected override void Seed(MyDbContextcontext)
{
base.Seed(context);
SeedMembership();
}
private void SeedMembership()
{
WebSecurity.InitializeDatabaseConnection(ConfigurationManager.ConnectionStrings["MyDatabaseConnection"].ConnectionString, "System.Data.SqlClient", "User", "UserID", "UserName", true);
WebSecurity.CreateUserAndAccount("doe1", "password11", new { FirstName = "John", LastName = "Doe" });
}
}
Open the IIS Management Console
Open the Application Pools node
Select the Application Pool which corresponds to your website
Right click the Application Pool and select "Advanced Settings"
Select Identity in Process Model section
Choose LocalSystem
I had a similar issue, try changing your connection string to:
<add name="MyDatabaseConnection" connectionString="Data Source=myServer; Database=MyDatabase.sdf;Trusted_Connection=True;" providerName="System.Data.SqlClient" />
So just remove Persist Security and Pooling. See if that works

Resources