Was ich versuche zu erreichen, ist meine Website löst eine Nachricht und legt es auf den Bus, ein Service nimmt es auf und schreibt in die Datenbank mit Auditing, die das AddedBy/UpdatedBy Feld automatisch füllt der Reihe.NServiceBus und NHibernate EventListeners laufen auf verschiedenen Threads
Ich mache dies mithilfe der NServiceBus IMessageMutator-Komponente, die die Benutzer-ID in die Nachrichtenheader von Thread.CurrentPrincipal schreibt, die von dem angemeldeten Benutzer in meiner ASP.Net-Anwendung stammt. In meinem Dienst verwende ich ein IMessageModule, um diesen Header zu extrahieren und an das Thread.CurrentPrincipal zu binden. Das funktioniert großartig und während meines Message-Handlers kann ich sehen, dass Thread.CurrentPrincipal.Identity.Name korrekt an die Benutzer-ID gebunden ist, die die Nachricht in der Webanwendung ausgelöst hat.
Mit dem IPreUpdateEventListener/IPreInsertEventListener von NHibernate setze ich die AddedBy/UpdatedBy jeder Entity, bevor es in die DB geschrieben wird. Das funktioniert auf der Website perfekt, aber in meinem NServiceBus-Dienst unterscheidet sich der Thread, auf dem der Listener ausgeführt wird, von dem Thread, auf dem der Handler ausgeführt wurde, was bedeutet, dass das CurrentPrincipal des Threads nicht mehr die in meinem IMessageModul gebundene ID ist.
Ich kann sehen, NHibernate verwendet eine DistributedTransactionFactory in der Aufrufliste, die ich vermute, ist die Ursache für mein Problem. Ich möchte keine Transaktionalität verlieren, so dass bei fehlgeschlagenem Commit die Nachricht nicht erneut versucht oder in die Fehlerwarteschlange eingereiht wird und wenn das Entfernen der Nachricht aus der Warteschlange fehlschlägt und das Update nicht zur DB zurückwechselt.
Ich habe mich im Internet umgesehen und alle Beispiele verwenden das CurrentPrincipal des Threads, um die ID des Benutzers zu binden, der die Zeilen geändert hat. Was ich suche, ist eine Möglichkeit, den NHibernate-Listener entweder im selben Thread wie den Nachrichtenhandler zu belassen oder die Benutzer-ID an den Listener zu übergeben, damit er an die Entität gebunden werden kann, bevor sie in die Datenbank geschrieben wird.
Hier meine Zuhörer ist, habe ich die Set-Methode darin
public class EntityPersistenceListener : IPreUpdateEventListener, IPreInsertEventListener
{
public bool OnPreUpdate(PreUpdateEvent @event)
{
var audit = @event.Entity as EntityBase;
if (audit == null)
return false;
var time = DateTimeFactory.GetDateTime();
var name = Thread.CurrentPrincipal.Identity.Name;
Set(@event.Persister, @event.State, "AddedDate", audit.AddedDate);
Set(@event.Persister, @event.State, "AddedBy", audit.AddedBy);
Set(@event.Persister, @event.State, "UpdatedDate", time);
Set(@event.Persister, @event.State, "UpdatedBy", name);
audit.AddedDate = audit.AddedDate;
audit.AddedBy = audit.AddedBy;
audit.UpdatedDate= time;
audit.UpdatedBy = name;
return false;
}
}
gefunden weggelassen Und hier ist das NServiceBus Nachrichtenmodul, das die ID extrahiert und bindet es an die Identität des aktuellen Thread
public class TenantAndInstanceInfoExtractor : IMessageModule
{
private readonly IBus _bus;
public TenantAndInstanceInfoExtractor(IBus bus)
{
_bus = bus;
}
public void HandleBeginMessage()
{
var headers = _bus.CurrentMessageContext.Headers;
if (headers.ContainsKey("TriggeredById"))
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(headers["TriggeredById"]), null);
else
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(string.Empty), null);
}
public void HandleEndMessage()
{
}
public void HandleError() { }
}
Morgan. Ich habe Probleme, Ihre Anforderung vollständig zu verstehen. Hast du nächste Woche Zeit für einen Skype-Anruf? ich bin "simon.cropp" auf Skype – Simon
Hallo Simon, ja bitte. Ich werde Ihnen eine E-Mail schicken, um eine Zeit zu vereinbaren. – Morgan