2017-10-25 2 views
0

Ich benutze asp.net Core 2.0 und Dapper. Ich habe eine Klasse, die eine IDbConnection-Schnittstelle umschließt und nur bestimmte Methoden verfügbar macht. Hier ist eine kurze Version dieser Klasse.ConnectionString verloren bei zweiter Ausführung

public class MyConnectionString : IMyConnectionString 
{ 
    private readonly IDbConnection _connection; 

    public int ConnectionTimeout => _connection.ConnectionTimeout; 
    public string Database => _connection.Database; 
    public string ConnectionString { get => null; set => _connection.ConnectionString = value; } 
    public ConnectionState State => _connection.State; 

    public MyConnectionString(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper) 
    { 
     var con = "some logic to get the connection string."; 
     _connection = new SqlConnection(con); 
    } 

    public int Execute(string query, object parameters = null) 
    { 
     using (var con = _connection) { return con.Execute(query, parameters); } 
    } 
} 

Ich injiziere diese Klasse über einen Konstruktor zu meinen Repository-Diensten. Zum Beispiel ist dies ein Verfahren, das es nennen würde:

internal class SomeRepository 
{ 
    private readonly IMyConnectionString _connection; 

    public SomeRepository(IMyConnectionString connection) 
    { 
     _connection = connection; 
    } 

    public void ExecuteSomeQuery(Object params) 
    { 
     var query = "Some query..."; 
     _connection.Execute(query, params); 
    } 
} 

Nun ist das Problem, dass wenn ich _connection.Execute(query, params); zweimal in einer einzigen Anfrage nennt (2 verschiedene Dienste), ist es das zweite Mal den ConnectionString Wert innerhalb MyConnectionString aufgerufen wird Die Klasse ist leer. Ich habe versucht, es in Transient und Request Umfang binden, um zu sehen, ob es es erhalten würde, aber kein Glück. Irgendeine Idee, warum das passiert oder wie kann ich es bewahren, so dass ich nicht die Verbindungszeichenfolge jedes Mal erstellen muss, wenn es angefordert wird?

+2

"ConnectionString-Wert innerhalb der MyConnectionString-Klasse ist leer" ... ConnectionString {get => return null; ... ', wie erwartest du, dass es alles andere als" null "zurückgibt? –

+4

Auch 'using (var con = _connection)' disponiert effektiv die '_connection' nach der ersten Ausführung. – Jasen

+1

Sie sollten stattdessen bei jeder Anfrage eine neue Verbindung erstellen. Es wird kaum Overhead geben, aufgrund des Verbindungs-Pools. Was ist der Zweck der Verwendung einer Fassade, um nur bestimmte Dappers-Methoden zu zeigen? Ich sehe darin keinen Gewinn. –

Antwort

2

wickeln die Connection innerhalb einer using entsorgt die Connection an seinem Ende der Ausführung: genau wie @Jasen in Kommentaren sagte.

Ich würde, in Ihrem Fall, nur die Verbindung und führen Sie auf dem Connection erstellt im Konstruktor: Entfernen der using vollständig.

Sie sollten die SqlConnection nicht erstellen, da Sie die Abhängigkeitsinjektion implementieren. Sie sollten:

  • Implementieren Sie IDisposable, um Ihre Verbindung zu entsorgen, wenn Ihre Klasse gesammelt wird.
  • Übergeben Sie eine SqlConnection Fabrik, um Ihre SqlConnection zu erstellen, indem Sie Ihre Erstellungslogik von Ihrer Klasse trennen.

Ihre Klasse sollte wie folgt aussehen:

public class MyConnectionString : IMyConnectionString 
{ 
    private readonly IDbConnection _connection; 

    public int ConnectionTimeout => _connection.ConnectionTimeout; 
    public string Database => _connection.Database; 
    public string ConnectionString 
    {  
     get => null; 
     set => _connection.ConnectionString = value; 
    } 

    public ConnectionState State => _connection.State; 

    public MyConnectionString(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper) 
    { 
     string con = "some logic to get the connection string."; 
     _connection = new SqlConnection(con); 
    } 

    public int Execute(string query, object parameters = null) 
    { 
     return _connection.Execute(query, parameters); 
    } 
} 

Mit IDisposable Umsetzung:

using System; 
public class MyConnectionString : IMyConnectionString, IDisposable 
{ 
    private readonly IDbConnection _connection; 

    public int ConnectionTimeout => _connection.ConnectionTimeout; 
    public string Database => _connection.Database; 
    public string ConnectionString 
    {  
     get => null; 
     set => _connection.ConnectionString = value; 
    } 

    public ConnectionState State => _connection.State; 

    public MyConnectionString(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper) 
    { 
     string con = "some logic to get the connection string."; 
     _connection = new SqlConnection(con); 
    } 

    public int Execute(string query, object parameters = null) 
    { 
     return _connection.Execute(query, parameters); 
    } 

    public void Dispose() 
    { 
     _connection.Dispose(); 
    } 
} 

Mit dem eigenen ISqlConnectionFactory Fabrik: Persönlich

public class MyConnectionString : IMyConnectionString, IDisposable 
{ 
    private readonly IDbConnection _connection; 
    private readonly ISqlConnectionFactory _factory; 

    public int ConnectionTimeout => _connection.ConnectionTimeout; 
    public string Database => _connection.Database; 
    public string ConnectionString 
    {  
     get => null; 
     set => _connection.ConnectionString = value; 
    } 

    public ConnectionState State => _connection.State; 

    public MyConnectionString(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper, ISqlConnectionFactory factory) 
    { 
     _factory = factory; 
     _connection = _factory.CreateConnection(connProvOpts, encHelper); 
    } 

    public int Execute(string query, object parameters = null) 
    { 
     return _connection.Execute(query, parameters); 
    } 
} 

public interface ISqlConnectionFactory 
{ 
    SqlConnection CreateConnection(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper); 
} 

public class SqlConnectionFactory : ISqlConnectionFactory 
{ 
    public SqlConnectionFactory() 
    { 
     // Maybe initialization? 
    } 

    public SqlConnection CreateConnection(IOptions<ConnectionProviderOptions> connProvOpts, EncryptionHelper encHelper) 
    { 
     string con = "some logic to get the connection string."; 
     _connection = new SqlConnection(con); 
    } 
} 

, hätte ich erstellt und beseitigte die Connection jedes Mal, wenn Execute aufgerufen wird. Dies bedeutet, dass Ihre Verbindung außerhalb von Execute geschlossen ist und Ressourcen freigegeben werden.

+1

Wenn Sie dies tun, sollten Sie entweder die 'SqlConnection' injizieren oder' IDisposable' implementieren. – Jasen

+0

Stimmt, ich habe mich gefragt, woher seine Verbindungszeichenfolge kommt. Sicherlich von seinen Konstruktor-Parametern. –

+0

Vielen Dank für die Erklärung. Ich dachte, dass, weil ich eine neue Variable erstelle, das Objekt dupliziert wird und das neue Objekt entsorgt wird, nicht das Original. – Bojan

Verwandte Themen