Używam ASP.NET MVC 5 i Identity Framework. Po wywołaniu UserManager.UpdateAsync (...) uruchomione zostaną moje funkcje obsługi zdarzeń w ApplicationDbContext() SaveChanges. Tutaj używam HttpContext.Current do różnych celów (logowanie i audyt), więc muszę powiedzieć, aktualny użytkownik. Jednak cała metoda działa w wątku roboczym, a tutaj HttpContext.Current ma wartość null.HttpContext.Current ma wartość null w metodach Identity Framework
Największy problem związany z metodami "synchronizacji" UserManagera dotyczą tylko wersji asynchronicznej, więc wywołania są serializowane, ale metody (i sterowniki zdarzeń) nadal działają w innym wątku roboczym.
Uwaga: ten problem nie ma nic wspólnego z kontekstem async/await. W kontrolerze po oczekiwaniu (lub wywołaniu wersji "sync") zwróciłem poprawny HttpContext, nawet metoda kontrolera kontynuuje się w innym wątku. W porządku.
Problem tkwi w module async, który będzie działał zarówno w wersjach "synchronizacji", jak i asynchronizacji. Myślę, że rozumiem te zjawiska (ale nie jestem zadowolony z fałszywej wersji metody "synchronizacji", prawdziwe metody synchronizacji nie wykazałyby tego problemu.) Po prostu nie wiem, jak sobie z tym poradzić/obejść.
[btw: Czy nie byłoby bardziej naturalne wdrożenie operacji UserManager jako prostych wersji czystej synchronizacji, a następnie zawinięcie ich przez asynchroniczne wielowątkowe owijki ?. Jeśli będziemy kontynuować tę asynchroniczną modę bez zastanowienia, wkrótce wymyślimy operatora asynchronicznego przydziału. Kosztuje mnie to kilkadziesiąt godzin (tylko ten numer) i kosztuje miliard dolarów na całym świecie, jestem pewien, że w wielu przypadkach jest to mniejszy zwrot niż jego cena.]
Bonus: Mówimy o UserManager, który ma wpływ marginalny, ale taki sam zasady i problemy mogą dotyczyć każdej z bibliotek pudełkowych (czarna skrzynka dla ciebie), której autorzy nie implementują wersji synchronizacji i lub nie dbają o kontekst wątku kontrolera. A co z EF, to nie jest tak marginalne ... a co z infrastrukturą tworzenia instancji kontenerów DI, jak "zakres żądania" lub "zakres sesji". Z pewnością źle się zachowują, jeśli rozdzielanie odbywa się w wątku bez HttpContext.Current. Niedawno odświeżyłem SendGrid NuGet i (jako zmiana zerwania) metoda Deliver() odeszła, a teraz istnieje tylko DeliverAsync() ...
Chciałbym mieć bezpieczny i niezawodny sposób, w jaki sposób uzyskać dostęp do HttpContext wewnątrz tego pracownika do celów rejestrowania i audytu.
Przykładowy kod, sterownik 'sync' wersja:
[AcceptVerbs(HttpVerbs.Post)]
public virtual ActionResult Edit(ApplicationUser user)
{
// validation etc
// Update() seems to be only a poor wrapper around the async version, still uses a worker thread.
var result = UserManager.Update(user);
// Note: HttpContext is correct here so it is not an async/await problem
// error handling, creating ActionResult etc.
}
Przykładowy kod, wersja kontrolera asynchroniczny:
[AcceptVerbs(HttpVerbs.Post)]
public virtual async Task<ActionResult> Edit(ApplicationUser user)
{
// validation etc
var result = await UserManager.UpdateAsync(user);
// Note: HttpContext is correct here so it is not an async/await problem
// error handling, creating ActionResult etc.
}
i obsługi zdarzeń gdzie HttpContext jest zerowy:
public ApplicationDbContext() : base("DefaultConnection", false)
{
InitializeAudit();
}
private void InitializeAudit()
{
var octx = ((IObjectContextAdapter) this).ObjectContext;
octx.SavingChanges +=
(sender, args) =>
{
// HttpContext.Current is null here
};
}
Jakieś pomysły?
Rozważ wyświetlenie kodu ... –
Czy możesz wyświetlić konkretny kod, o który pytasz? – i3arnon
Jak o przechowywaniu 'HttpContext.Current' w zmiennej lokalnej przed utworzeniem jakichkolwiek zadań i przekazywanie go do zadań/wątków w jakiś sposób. – EZI