2011-01-13 9 views
6

Czy są jakieś powody, dla których nie używałbyś umów Code Contracts w celu egzekwowania reguł biznesowych?Czy umowy kodowe należy stosować w celu zapewnienia bezpieczeństwa?

Wyobraź sobie, że masz klasę User, która reprezentuje pojedynczego użytkownika systemu i definiuje akcje, które można wykonać względem innych użytkowników. Można napisać ChangePassword metody takie jak to ...

public void ChangePassword(User requestingUser, string newPassword) 
{ 
    Contract.Requires<ArgumentNullException>(requestingUser); 
    Contract.Requires<ArgumentNullException>(newPassword); 

    // Users can always change their own password, but they must be an 
    // administrator to change someone else's. 
    if (requestingUser.UserId != this.UserId && 
     !requestingUser.IsInRole("Administrator")) 
     throw new SecurityException("You don't have permission to do that."); 

    // Change the password. 
    ... 
} 

Albo można wdrożyć kontroli bezpieczeństwa jako warunek z Contract.Requires ...

public void ChangePassword(User requestingUser, string newPassword) 
{ 
    Contract.Requires<ArgumentNullException>(requestingUser != null); 
    Contract.Requires<ArgumentNullException>(newPassword != null); 

    // Users can always change their own password, but they must be an 
    // administrator to change someone else's. 
    Contract.Requires<SecurityException>(
     requestingUser.UserId == this.UserId || 
     !requestingUser.IsInRole("Administrator"), 
     "You don't have permission to do that."); 

    // Change the password. 
    ... 
} 

Jakie są zalety i wady tych dwóch metod ?

Odpowiedz

2

Myślę, że odpowiedź brzmi nie. Umowy dotyczące kodu są zaprojektowane dla scenariuszy, w których ich niepowodzenie wskazuje na poważny błąd w kodzie w kodzie. Powinny one być , a nie czymś, co można odzyskać z powodu nieprawidłowego wprowadzenia danych przez użytkownika.

Requires<T> jest przeznaczony do użytku wyłącznie na publicznych metodach biblioteki, które będą używane przez inne osoby, które nie korzystają z umów Code Contract, lub jeśli posiadasz starszy kod, który musi pozostać kompatybilny pod względem wyjątków, które może wyrzucić.

Dla nowego kodu powinieneś używać tylko Requires, a nie Requires<T>. Zwykły Requires domyślnie wyrzuca wyjątek nieprzyłączalny, aby zmusić cię do rozwiązania problemu.

Co więcej, jeśli ktoś wyłączy sprawdzenie czasu wykonywania kodu, wszystkie zabezpieczenia znikną!

+0

Można również wysunąć argument, że w niektórych przypadkach podany przykład * jest * poważnym błędem w kodzie. Na przykład, jeśli metoda, którą piszesz, jest pochowana kilka warstw w dół i cała weryfikacja ma się odbyć na zewnętrznej warstwie aplikacji, może to zostać uznane za część umowy tej metody. Wszystko zależy :) – porges

+0

Dobra odpowiedź! Nie zdawałem sobie sprawy z niemożliwej do wyłapania natury 'ContractException', ale twoja odpowiedź wskazała mi właściwy kierunek: http://www.infoq.com/articles/code-contracts-csharp - thanks! :) –