This property cannot be set after a connection has been opened - c#

I'm trying to connect to Oracle through .NET Core following this docs:
https://docs.oracle.com/en/database/oracle/oracle-data-access-components/19.3/odpnt/InstallCoreConfiguration.html#GUID-24C963AE-F20B-44B5-800C-594CA06BD24B
But I'm facing this error:
This property cannot be set after a connection has been opened
System.InvalidOperationException: This property cannot be set after a
connection has been opened at
Oracle.ManagedDataAccess.Client.OracleDataSourceCollection.Add(String
tnsName, String tnsDescriptor) at
Infrastructure.Persistence.Factory.ConnectionFactory.SetupOracleConnection()
in
C:\Users\WINDOWS\RiderProjects\TicketsAPI\Infrastructure\Persistence\Factory\ConnectionFactory.cs:line
22
I don't have clue why this is happening, there's my ConnectionFactory:
using System.Data;
using Microsoft.Extensions.Logging;
using Oracle.ManagedDataAccess.Client;
namespace Infrastructure.Persistence.Factory;
public class ConnectionFactory : IConnectionFactory
{
private const string TnsName = "ORCL";
private readonly ILogger<ConnectionFactory> _logger;
public ConnectionFactory(ILogger<ConnectionFactory> logger)
{
_logger = logger;
}
public IDbConnection? Connection => SetupOracleConnection();
private OracleConnection? SetupOracleConnection()
{
OracleConfiguration.OracleDataSources.Add(TnsName,
"(DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = DESKTOP-FP8GDE4)(PORT = 1521))(CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = orcl)))"); // <-- This is the line 22 mentioned in the StackTrace
. . . //Some configs that are in the doc file.
OracleConnection oracleConnection = null!;
try
{
oracleConnection = new OracleConnection($"user id=kevinadmin; password=1234; data source={TnsName}");
oracleConnection.Open();
return oracleConnection;
}
catch (Exception e)
{
_logger.LogError("An error occurred while trying to connect to database {EMessage}", e.Message);
return null;
}
finally
{
oracleConnection?.Close();
}
}
}

[edit:
I may have misunderstood the issue. If the exception is happening on second and subsequent calls to Connection, then this answer might apply]
By declaring your property like
public IDbConnection? Connection => SetupOracleConnection();
you're instructing the { get; } (which is what the => is sugar for) to execute the SetupOracleConnection() every time it is accessed.
You should try to encapsulate that into a singleton instance.
private IDbConnection? _connection = null;
public IDbConnection? Connection => _connection ?? ( _connection = SetupOracleConnection());

Related

Database locked error when using Begintransaction, multiple repositories, SQLite, UnitOfWork and Dapper

I'm trying to implement transactions with SQLite and Dapper but I'm getting "database is locked" error.
I'm using the UnitOfWork pattern suggested here.
This is the code:
Controller.cs:
public async Task MyMethodAsync()
{
//**injecting unitOfWork but this is the implementation**
var unitOfWork = new UnitOfWork(new SQLiteConnection($"Data Source=TestDb;Mode=Memory;Cache=Shared"));
using (var connection = unitOfWork.Connection)
{
connection.Open();
unitOfWork.Begin();
var myFirstRepository = new MyFirstRepository(unitOfWork);
var mySecondRepository = new MySecondRepository(unitOfWork);
try
{
myFirstRepository.CreateStuff(); //Here it throws the exception "database is locked"
mySecondRepository.CreateOtherStuff();
unitOfWork.Commit();
}
catch(Exception e)
unitOfWork.Rollback();
throw;
}
}
}
MyFirstRepository.cs:
public class MyFirstRepository
{
private IUnitOfWork _unitOfWork;
public MyFirstRepository(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}
public void CreateStuff()
{
using (var connection = _unitOfWork.Connection)
{
connection.Open();
await connection.ExecuteAsync("INSERT INTO ...", param).ConfigureAwait(false);
}
}
}
MySecondRepository.cs:
Similar implementation like MyFirstRepository.cs.
Does anyone have any idea what I'm missing here?
It looks like you're opening the connection twice - once in MyMethodAsync and again in MyFirstRepository.CreateStuff. I don't see anything in the documentation for the SQLiteConnection class about what happens if you try to open a connection twice, but maybe that's causing the issue for you? I also noticed that in the post you linked about UnitOfWork that connection.Open() is only called once as well.

How to use MongoDB connection globally

My API is on .net mvc c# platform. I am using mongo DB to drop and store data the following way. It is not working properly when I try to drop and insert data concurrently. The connections are multiplying and the requests are not executed in the same order. How can I use the MongoDB in a global class with only one connection open? do give some reference to look into.
public static string DB= DBConnection.MongoDB;
public bool Insert(Data data)
{
try
{
var con = new MongoClient(DBConnection.ConnectionString);
var db = con.GetDatabase(DB);
db.InsertOne(data);
return true;
}
catch (Exception exception)
{
}
}
using System.Configuration;
namespace DataAccess.Implementations
{
internal class DBConnection
{
#region ConnectionString
public static string ConnectionString { get { return ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; } }
#endregion
#region Database
public static string MongoDB{ get { return ConfigurationManager.AppSettings["MongoDB"].ToString(); } }
#endregion
}
}
Try using a Singleton pattern:
https://social.msdn.microsoft.com/Forums/en-US/9e152212-2109-4d07-adbf-4ff0326c077b/how-to-establish-db-connection-using-singleton-pattern?forum=csharpgeneral
Singleton design pattern is preferred to get a DB Connection

Migrating from StackExchangeRedisCacheClient to RedisCacheClient

I am building a project based on StackExchangeRedisCacheClient and obsolete has popped out:
'StackExchangeRedisCacheClient' is obsolete: 'This interface will be removed with the next major. Please use RedisCacheClient instead.'
so i'm trying to move from StackExchangeRedisCacheClient to RedisCacheClient
unfortunately there is no documentation or some helpful info for doing that.
how do i create a cache client? with RedisCacheClient ? the require args are 'RedisCacheClient(IRedisCacheConnectionPoolManager, ISerializer, RedisConfiguration)'
i have looked at the following link and tried to implement a Single pool with no success https://github.com/imperugo/StackExchange.Redis.Extensions/issues/176#
couldn't create a cacheClient after providing the connection string.
StackExchangeRedisCacheClient:(works fine)
public CacheManager()
{
string connectionString = "localhost:300....."
var serializer = new NewtonsoftSerializer();
cacheClient = new StackExchangeRedisCacheClient(serializer, connectionString);
clientName = cacheClient.Database.Multiplexer.ClientName;
}
RedisCacheClient:
public CacheManager()
{
string connectionString = "localhost:300....."
var serializer = new NewtonsoftSerializer();
cacheClient = new RedisCacheClient( *** ??? *** );
clientName = cacheClient.Database.Multiplexer.ClientName;
}
As per https://github.com/imperugo/StackExchange.Redis.Extensions/issues/176 if you don't care about having multiple connections you can use the following class:
internal class SinglePool : IRedisCacheConnectionPoolManager
{
private readonly IConnectionMultiplexer connection;
public SinglePool(string connectionString)
{
this.connection = ConnectionMultiplexer.Connect(connectionString);
}
public IConnectionMultiplexer GetConnection()
{
return connection;
}
}

Why is my Entity Framework connection string not working

I am trying to connect to a database without using App.Config but i keep getting the following error:
An unhandled exception of type 'System.Data.Entity.Core.EntityException' occurred in EntityFramework.dll
Additional information: The underlying provider failed on ConnectionString.
I can't see where I've gone wrong so i thought i'd ask here.
namespace MyNameSpace
{
using System;
using System.Data.Entity;
using System.Data.Entity.Core.EntityClient;
using System.Data.Entity.Infrastructure;
public partial class Entities : DbContext
{
public Entities()
: base(entityString.ToString())
{
}
public static EntityConnectionStringBuilder entityString = new EntityConnectionStringBuilder()
{
Provider = "System.Data.SqlServerCe.4.0",
Metadata = "res://*/RS.csdl|res://*/RS.ssdl|res://*/RS.msl",
ProviderConnectionString = #"C:\RestOfPath\database.sdf;Password=3476dfg423434563466e85rcsd"
};
}
}
Thank you in advance for your help.
The problem is that you are passing your sdf file directly on your connection string. Try changing:
ProviderConnectionString = #"C:\RestOfPath\database.sdf;Password=3476dfg423434563466e85rcsd"
To:
ProviderConnectionString = #"Data Source=C:\RestOfPath\database.sdf;Password=3476dfg423434563466e85rcsd"
Or better yet, use a SqlCeConnectionStringBuilder to construct this property:
var connectionStringBuilder = new SqlCeConnectionStringBuilder();
connectionStringBuilder.DataSource = #"C:\RestOfPath\database.sdf";
connectionStringBuilder.Password = "3476dfg423434563466e85rcsd";
EFConnectionBuilder.ProviderConnectionString = connectionStringBuilder.ToString(),
Try this : make this parameterise
public Entities(string connString)
: base(connString)
{
}
and pass string connection string when creating object of Context class.
public class TestController : Controller
{
Entity _context = new Entity("data source=Dev-4;initial catalog=test1;
integrated security=True;MultipleActiveResultSets=True;
App=EntityFramework");
}
Try this : here you din't need to pass connection string again and again -->
public Model1()
: base(connString)
{
}
public static string connString = "data source=tesst;initial catalog=test1;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework";
Use This method when using Database First Model of Entity Framework :
public test1Entities()
: base(nameOrConnectionString: ConnectionString())
{
}
private static string ConnectionString()
{
SqlConnectionStringBuilder sqlBuilder = new SqlConnectionStringBuilder();
sqlBuilder.DataSource = "DEV-4";
sqlBuilder.InitialCatalog = "test1";
sqlBuilder.PersistSecurityInfo = true;
sqlBuilder.IntegratedSecurity = true;
sqlBuilder.MultipleActiveResultSets = true;
EntityConnectionStringBuilder entityBuilder = new EntityConnectionStringBuilder();
entityBuilder.ProviderConnectionString = sqlBuilder.ToString();
entityBuilder.Metadata = "res://*/";
entityBuilder.Provider = "System.Data.SqlClient";
return entityBuilder.ToString();
}

Failover connection string in n-tier linq2sql

Scenario: ASP.Net web app (n-tier linq2sql) on local IIS with connection to SQL 2008 database over VPN. Some data is replicated to a local SQL 2008 express DB (different name). If the connection is down to VPN database, we would like to use the local instance for some parts of the web app.
My Question is, how can the following solution be improved. we have involves a lot of passing the connection string about. If this involved mirroring, we could set the failover partner but as it is a different database I don't think this is possible.
Current Code:
Check if we can connect remotely, put the working connection string in session
Session_Start()
{
//if can connect to remote db
Session["ConnStr"] = //remote connection
//else
Session["ConnStr"] = //local connection
}
Pass connection string in UI to BLL
protected void ods1_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
{
TestManager myTestManager = new TestManager(Session["ConnString"].ToString());
e.ObjectInstance = myTestManager;
}
Pass to DAL
public class TestManager
{
private readonly string _connectionString;
public TestManager(string connectionString)
{
_connectionString = connectionString;
}
[DataObjectMethod(DataObjectMethodType.Select, true)]
public List<Test> GetAll()
{
TestDB testDB = new TestDB(_connectionString);
return testDB.GetAll();
}
}
Set connection in DAL creating DataContext in constructor
public class TestDB
{
public TestDB(string connectionString)
{
_connectionString = connectionString;
_dbContext = new TestDataContext(_connectionString);
}
private TestDataContext _dbContext;
private string _connectionString;
public string ConnectionString
{
get
{
return _connectionString;
}
set
{
_connectionString = value;
}
}
public TestDataContext DbContext
{
get
{
return _dbContext;
}
set
{
_dbContext = value;
}
}
public List<Test> GetAll()
{
var query = from t in DbContext.Tests
select new DTO.Test()
{
Id = t.Id,
Name = t.Name
};
return query.ToList();
}

Categories