2012-09-20 25 views
6

Odziedziczyliśmy nieco źle zaprojektowaną usługę WCF, którą chcemy poprawić. Jednym z problemów jest to, że ma ponad sto metod (na dwóch różnych interfejsach), z których większość podejrzewamy, nie są używane. Postanowiliśmy wprowadzić pewne rejestrowanie każdej metody śledzenia, kiedy i jak są wywoływane. Aby kod śledzenia Refactor w obsłudze i typo-dowód wdrożyliśmy go tak:Dlaczego funkcja Type.GetInterfaces() czasami nie zwraca poprawnej listy?

public void LogUsage() 
{ 
    try 
    { 
     MethodBase callingMethod = new StackTrace().GetFrame(1).GetMethod(); 
     string interfaceName = callingMethod.DeclaringType.GetInterfaces()[0].Name; 
     _loggingDao.LogUsage(interfaceName, callingMethod.Name, GetClientAddress(), GetCallingUrl()); 
    } 
    catch (Exception exception) 
    { 
     _legacyLogger.Error("Error in usage tracking", exception); 
    } 
} 

LogUsage() jest wówczas nazywano na początku każdej metody, którą chcemy śledzić.

Usługa jest bardzo dużym natężeniem ruchu, rzędu 500 000 połączeń dziennie. 99,95% czasu, ten kod jest pięknie wykonany. Ale inne 0,05% czasu, GetInterfaces() zwraca pustą (ale nie null) tablicę.

Dlaczego by GetInterfaces() czasami zwracać niespójne wyniki?

To może wydawać się tak banalne - współczynnik błędu 0,05% jest czymś, o czym zwykle możemy tylko pomarzyć. Chodzi jednak o to, aby zidentyfikować punkty kontaktu z usługami i jeśli ten błąd zawsze wychodzi z jednego (lub kilku) wywołań metod, nasze śledzenie jest niekompletne. Próbowałem odtworzyć ten błąd w moim środowisku programistycznym, wywołując każdą metodę w usłudze, ale bezskutecznie.

+0

Niekompletne ślad stosu spowodowane niewłaściwie rethrown wyjątkiem gdzieś? –

+1

Jeśli logujesz się również do 'callingMethod', możesz stwierdzić, że jego typ deklaracji w rzeczywistości nie ma żadnych interfejsów. –

+0

'LogUsage' jest wywoływane tylko z metod wewnątrz dwóch klas, a obie te klasy implementują przynajmniej jeden interfejs. – nateirvin

Odpowiedz

4

StackTrace jest nierzetelny, szczególnie w środowiskach wielowątkowych. Lub raczej jest wysoce niezawodny, ale czasami nie jest zbyt praktyczny. Pytanie o "ostatnią metodę, która została nazwana" może mieć nieoczekiwane rezultaty. Spróbuj zalogować DeclaringType. Możesz być zaskoczony tym, co tam znajdziesz. Zauważ, że chociaż współczynnik awaryjności wynosi teraz 0,05%, może łatwo wzrosnąć wraz ze złożonością aplikacji.

W celu prawidłowego wdrożenia wielokrotnego użytku kodu śledzenia, musisz polegać na .NET 4.5 cechą Caller Information, za pomocą dynamicznego proxy (np Castle Dynamic Proxy), lub za pomocą ramy AOP takich jak PostSharp. Alternatywnie możesz po prostu ręcznie skopiować śledzenie.

+0

"' StackFrame' nie jest bezpieczny dla wątków "to możliwość, którą rozważałem; jednak [dokumentacja MSDN] (http://msdn.microsoft.com/en-us/library/4ce0ktkk (v = vs.100) .aspx) mówi "The' StackTrace' jest tworzony z bieżącym wątkiem dzwoniącego ", więc pomyślałem, że mogę na nim polegać. Tak dobrze wiedzieć.(FYI z powodów politycznych nie będę mógł przez jakiś czas wprowadzać żadnych zmian w usłudze, więc wzmocnienie rejestrowania nie jest obecnie możliwe) [westchnienie]) – nateirvin

3

Od Erik Lippert (która pracuje w zespole kompilatora C# dla MS) w odpowiedzi na Getting Type T from a StackFrame:

Ramka stosu faktycznie nie powiedzieć, który nazwał swoją metodę. Ramka stosu informuje, do której kontroli ma wrócić. Ramka stosu jest potwierdzeniem kontynuacji. To, że ktoś, kto zadzwonił do metody i gdzie kontrola powraca, jest prawie zawsze tą samą przyczyną, jest źródłem twojego zamieszania, ale zapewniam, że nie musi być taka sama.

Cały post jest warta przeczytania ...

Powiązane problemy