DisposableDbObject
(IDisposable
の実装)を使用するクラスMyService
を含むライブラリを作成しています。私はAutofac ContainerBuilder
拡張を公開しています(オブジェクトの作成には非常にコストがかかります)。問題は、しばらくの間、DisposableDbObject
インスタンスをリフレッシュする必要があることです(ファイルから新しいバージョンのデータベースをロードする必要のあるメモリ内のDBのラッパーです)。私が知る限り、SingletonInstance
(そしてContainerBuilder.Update
は廃止された)コンポーネントの参照を置き換える安全な方法はないので、私はDisposableDbObject
をDisposableDbObjectProvider
クラスにラップしてシングルトンとして登録し、何でも更新することができます下に横たわっている。だから私の設定はこれのように行く。Autofacでシングルトンとして登録された使い捨てオブジェクトを置き換える
// DisposableDbObjectProvider.cs
public interface IDisposableDbObjectProvider
{
DisposableDbObject GetDb();
}
public class DisposableDbObjectProvider : IDisposableDbObjectProvider
{
private DisposableDbObject _obj;
public DisposableDbObjectProvider()
{
_obj = new DisposableDbObject("D:\\path\to\file");
}
public DisposableDbObject GetDb()
{
return _obj;
}
public void UpdateDb()
{
_obj = new DisposableDbObject("D:\\path\to\new\file");
}
}
// MyService.cs
interface IMyService
{
string GetStuffFromDb();
}
class MyService
{
private DisposableDbObjectProvider _provider;
class MyService(IDisposableDbObjectProvider provider)
{
_provider = provider;
}
public string GetStuffFromDb()
{
return _provider.GetDb().Read(...);
}
}
// AutofacExtensions.cs
static class AutofacExtensions
{
public static ContainerBuilder WithMyService(this ContainerBuilder builder)
{
builder.RegisterType<DisposableDbObjectProvider >().As<IDisposableDbObjectProvider>().SingleInstance();
builder.RegisterType<MyService>().As<IMyService>();
}
}
この設定には少なくとも3つの問題があります。
(ASP.NET WebApi2など)、マルチスレッドクライアントアプリは
MyService
と1つのスレッドを登録する(これはASP.NETリクエストハンドラである)スレッドがある間に更新が行われた場合には、オブジェクトの2つの異なるバージョンにアクセスすることができますDisposableDbObject
参照を交換した後は(私の非常に特定の場合には、これは、私はそれを避けることを好むだろうけれどもイベント十分かもしれません)を実行し、古いものはそれに
Dispose
と呼ばれている必要があります。今度はN> = 1のスレッドがそのオブジェクトへの参照を保持し、Dispose
をDisposableDbObjectProvider
に呼び出している間に、それらのスレッドがObjectDisposedException
で終了することがあります(多くの場合)。クライアントが使用するオブジェクトの廃棄に責任を負うべきルールが破られます。私が考えていた
一つのアプローチは、IsAlive
経由(WeakReference
追跡リストとして古い参照保存DisposableDbObject
static
などのフィールドで、各アップデートに過渡、ガベージコレクトされている参照のためにそれをスキャンするDisposableDbObjectProvider
の登録を変更することです(もしDisposableDbObjectProvider.Dispose
意志behaを言うことができない性質)など
public class DisposableDbObjectProvider : IDisposableDbObjectProvider, IDisposable
{
private static DisposableDbObject _obj = new DisposableDbObject("D:\\path\to\file");
private static List<WeakReference> _oldRefs;
public DisposableDbObject GetDb()
{
return _obj;
}
public void UpdateDb()
{
_oldRefs.Add(_obj);
_obj = new DisposableDbObject("D:\\path\to\new\file");
}
public void Dispose()
{
var deadRefs = _oldRefs.Where(x => !x.IsAlive);
oldRefs = oldRefs.Exclude(deadRefs);
foreach(var deadRef in deadRefs)
{
((IDisposable) deadRef.Target).Dispose();
}
}
}
の下に、それらの上Dispose
を呼び出すしかし、それだけで問題に何の2を解決していない可能性があり、まだ私はこのsoultionについて非常に安全に感じることはありませんいくつかのスレッドで同時に呼び出されています。
これらの問題を解決するにはどうすればよいでしょうか?もちろん、シングルトン登録の問題を回避するための私の解決策には欠陥があるかもしれません。もっと良いアプローチがあれば、それについて聞いてみたいと思います。
DisposableDbObjectの更新時期はどのように決定されますか?パターンがある場合は、シングルトンとしての登録をやめ、適切な数のインスタンスを渡すことができます。 –
'DisposableDbObject'のソースコードを表示してください。 _そうでなければ明白でない機会を開くかもしれません。 – mjwills