Ich erstelle eine Bibliothek, die eine Klasse MyService
enthält, die ein Objekt 3rd Party DisposableDbObject
(Implementierung IDisposable
) verwendet. Ich exponieren Autofac ContainerBuilder
Erweiterung, die es als eine einzelne Instanz registriert (Erstellung von Objekt ist sehr teuer). Die Sache ist, dass hin und wieder die DisposableDbObject
Instanz aktualisiert werden muss (es ist ein Wrapper um einige In-Memory-DB, die eine neue Version der Datenbank aus der Datei laden muss). Da, soweit ich weiß, gibt es keine sichere Möglichkeit, die Referenz einer Komponente von SingletonInstance
(und ContainerBuilder.Update
ist veraltet) zu ersetzen Ich wickelte meine DisposableDbObject
mit DisposableDbObjectProvider
Klasse und registrieren Sie es als ein Singleton, mit einer freien Hand zu aktualisieren, was auch immer liegt darunter. So läuft mein Setup so.Ersetzen von als Singleton registriertem Einwegobjekt in 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>();
}
}
Jetzt gibt es mindestens drei Probleme mit diesem Setup.
die multithreading-fähige Client-Anwendung (wie ASP.NET WebApi2) registriert
MyService
und ein ein Gewinde (sei es ASP.NET Request-Handler) es zwei verschiedene Versionen des Objekts zugreifen kann, wenn die Aktualisierung durchgeführt wurde, während Threads Laufen (in meinem ganz speziellen Fall könnte das gut genug sein, Event obwohl ich es lieber vermeiden würde)Nach dem Ersetzen
DisposableDbObject
Referenz, die alte mussDispose
aufgerufen haben. Jetzt gibt es möglicherweise N> = 1 Threads, die Verweis auf das Objekt behält, und während ichDispose
inDisposableDbObjectProvider
aufrufen kann diese Thread (und in vielen Fällen wird) am Ende mitObjectDisposedException
enden.Es bricht die Regel, dass der Client verantwortlich sein sollte für die Entsorgung des Objekts, das es verwendet.
Ein Ansatz, den ich darüber nachdachte, ist die Registrierung von DisposableDbObjectProvider
sie ändern mit DisposableDbObject
als static
Feld und bei jeder Aktualisierung speichert die alte Referenz als WeakReference
Tracking-Liste und scannen sie nach Referenzen auf transiente, den Müll gesammelt werden (via IsAlive
Eigentum) und Dispose
auf diejenigen nennen, wie unter
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();
}
}
}
Aber das nur vielleicht nicht 2 lösen Problem und ich über diese soultion sehr sicher fühlen, immer noch nicht (kann nicht sagen, ob DisposableDbObjectProvider.Dispose
wird Beha wie beabsichtigt, während gleichzeitig mehrere Threads aufgerufen werden.
Was wäre der beste Weg, um diese Probleme zu überwinden? Natürlich könnte meine Lösung, das Singleton-Registrierungsproblem zu umgehen, fehlerhaft sein, wenn es einen besseren Ansatz gibt, bin ich gespannt darauf, davon zu hören.
Wie entscheidet das Programm, wann das DisposableDbObject aktualisiert werden soll? Wenn es ein Muster gibt, könnten Sie aufhören, es als Singleton zu registrieren und die richtige (Anzahl von) Instanzen herumreichen. –
Bitte zeigen Sie uns den Quellcode für 'DisposableDbObject' an. _Sieht man das, können sich Möglichkeiten eröffnen, die sonst nicht offensichtlich sind. – mjwills