8

HttpContextSignalRハブなどのASP.NETMVCアプリケーションに永続的なHTTP接続がある場合にスコープされた、StructureMapを使用したオープンデータベース接続の有効期間の管理に問題があります。

私のDIコンテナであるStructureMapは、IDbConnectionいくつかのサービスにオープンを注入します。これらのデータベース接続が閉じられ、適切に破棄されるようにするために、私ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects()EndRequestイベントを呼び出します。

これは、データベース接続を必要とするサービスがSignalRハブに注入されるまで、MVCコントローラーに最適です。これにより、クライアントごとに永続的なHTTP接続が開いたままになり、最終的に接続プールが飽和状態になります。

シングルトンにスコープIDbConnectionを設定すると、アプリケーションごとに1つの接続のみが開かれ、プールが飽和状態になりませんが、接続がロックされたりタイムアウトになったりした場合に備えて、これはお勧めできません。

では、SignalRハブのデータベース接続の範囲をカスタマイズする方法はあるのでしょうか。各ハブメソッドでサービスインスタンスを解決しようとしましたが、これでもHttpContextスコープでデータベース接続がインスタンス化され、呼び出し元のクライアントのハブ接続の間、データベース接続が開いたままになります。

永続的なHTTP接続がある場合、HTTPスコープのコンテキストでStructureMapを使用してデータベース接続の有効期間をどのように管理する必要がありますか?

サンプルコード

典型的なサービス

public class MyService
{
    private IDbConnection _con;
    public MyService(IDbConnection con)
    {
        _con = con;
    }

    public IEnumerable<string> GetStuff()
    {
        return _con.Select<string>("SELECT someString FROM SomeTable").ToList();
    }
}

典型的なSignalRハブ

public class MyHub : Hub
{
    private MyService _service;
    public MyHub(MyService service)
    {
        _service = service; // Oh Noes! This will open a database connection
                            // for each Client because of HttpContext scope
    }

    public Task AddMessage()
    {
        var result = _service.GetStuff();
        // ...
    }
}

StructureMapの構成

For<IDbConnection>()
    .HybridHttpOrThreadLocalScoped()
    .Use(() => BaseController.GetOpenConnection(MyConnectionString));

Global.asax.cs

public class GlobalApplication : System.Web.HttpApplication
{
    public GlobalApplication()
    {
        EndRequest += delegate
        {
            ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
        };
    }
    // ...
 }
4

2 に答える 2

1

SignalR 1.0.0 Alphaでは、Hubの実装はIDisposable。SignalRHubインスタンスは、とは異なり一時的なものであるため、のメソッドでHttpContextを閉じる場合は、接続プールを不必要に飽和させないでください。IDbConnectionHubDispose

于 2012-11-21T03:18:23.677 に答える
1

一時的なデータベース接続とネストされたStructureMapコンテナを使用したソリューション

まず、StructureMapで名前付きの一時的なデータベース接続インスタンスを構成します。

For<IDbConnection>()
    .Transient() // scope
    .Add(x => BaseController.GetOpenConnection(connectionString, IsDebugging()))
    .Named("Transient");

デフォルトインスタンスの前にこれを設定してください。そうしないと、デフォルトインスタンスが上書きされます。

次に、IContainerSignalRハブにを挿入して、ネストされたStructureMapコンテナーを構築できるようにします。

public class JobHub : Hub
{
    private readonly IContainer _container;

    public JobHub(IContainer container)
    {
        _container = container;
    }

    public Task DoStuff(string input)
    {
        // ...

SignalRメソッドでネストされたコンテナーをインスタンス化し、名前付きの一時データベース接続を解決します。

        using (var httpRequestScope = _container.GetNestedContainer())
        {
            var transientConnection =
                    httpRequestScope.GetInstance<IDbConnection>("Transient");

.With<IDbConnection>(transientConnection)ネストされたコンテナによってインスタンス化されたサービスとリポジトリがこの接続を使用することを確認するために使用します。

            var myService = httpRequestScope
                .With<IDbConnection>(transientConnection)
                .GetInstance<MyService>();

            var result = myService.DoStuff(input);

            return Clients.addResult(result);
        }
    }
}

最後に、スコープ付きusing (...)ステートメントは、データベース接続を含め、ネストされたコンテナーがそれ自体の後でクリーンアップされることを保証します。

ここでの欠点は、SignalRメソッド呼び出しごとにデータベース接続を開いたり閉じたりすることですが、接続はプールされているため、早期に解放することはそれほど悪くない場合があります。マイレージは、SignalRリクエストの量によって異なります。

ネストされたコンテナを破棄しDependencyResolver.Currentて、名前付き接続インスタンスを要求することもできますが、リークを防ぐために、各接続を明示的に閉じることを忘れないでください。

于 2012-11-27T13:46:20.717 に答える