Rozwiązywanie problemów i debugowanie aplikacji jest normalnym procesem w czasie tworzenia i modyfikacji aplikacji. Na szczęście Visual Studio posiada wiele narzędzi do śledzenia kodu w czasie uruchomienia aplikacji. Możliwość przechwycenia i zrozumienia błędów w środowisku produkcyjnym i programistycznym jest potężnym narzędziem, które pomaga upewnić się, że ASP.NET MVC poprawnie zarządza aplikacją.

Zapobiegania i rozwiązywania problemów w czasie wykonywania

Performance Wizard

  • Rozwiązywanie problemów z wydajnością ma kluczowe znaczenie dla tworzenia solidnych aplikacji. Narzędzie Performance Wizard w Visual Studio pozwala na skonfigurowanie profilowania aplikacji, które umożliwia przechwycenie informacji o użyciu CPU, pamięci i zasobach. Profiler wykonuje kompletne śledzenie wszystkich wywołań w aplikacji. Pozwala to śledzić logiczny przepływ w aplikacji. Performance Wizard posiada kilka różnych metod monitorowania. Należą do nich: CPU sampling (rekomendowana), Instrumentation, .NET memory allocation (sampling) i Resource contention data (concurrency).
  • CPU sampling dostarcza informacji o pracy wykonywanej przez aplikację oraz jej wpływie na CPU. Próbkowanie jest lekkie i nie obciąża znacząco aplikacji. Polega na zbieraniu informacji co pewien okres cykli CPU. CPU sampling jest bardziej jak sprawdzanie początkowe mówiące o tym gdzie powinniśmy zbadać naszą aplikację dokładniej.
  • Instrumentation - instrumentacja jest bardziej inwazyjnym procesem. Narzędzie monitorujące dodaje kod do monitorowanych assembly (programista nie musi nic robić). ten kod pozwala zbadać dokładnie informacje w assembly, takie jak czasy wykonywania metod oraz wywoływaniawejściowe i wyjściowe w assembly. Monitorowane są również czasy spędzone na wykonywaniu poszczególnych metod w assembly niezależnie od zewnętrznych wywołań assembly. Taka analiza pozwala lepiej poznać problemy wydajnościowe.
  • .NET memory allocation jest sposobem na sprawdzenie problemów wydajnościowych zależnych od pamięci. Analiza obejmuje zarządzanie pamięciom aplikacji dla każdego obiektu w pamięci od momentu tworzenia do zbierania śmieci. Monitor może pracować w dwóch trybach. Pierwszy jest mniej inwazyjny i polega na próbkowaniu. Drugi korzysta z instrumentacji i daje dużo głębsze spojrzenie na pracę pamięci.
  • Resource contention data (concurrency) jest to monitor wydajności użyteczny przy monitorowaniu aplikacji wielowątkowych. Monitor ten daje informacje o interakcjach pomiędzy wątkami i systemem, wykorzystaniem procesora, zajętości I/O i wiele innych użytecznych metryk.
  • Po wybraniu metody profilowania należy wybrać aplikację która ma być analizowana. Wy zakończeniu Performance Wizard aplikacja zostaje uruchomiona i należy zacząć jej używać, szczególnie miejsca które chcemy zbadać. Po zamknięciu aplikacji zostanie wygenerowany raport. Poprzez wybór Analyze | Start Performance Analysis można generować ten sam raport wielokrotnie.

Visual Studio Profiler

Visual Studio Profiler wykonuje kompletne śledzenie wywołań występujących w aplikacji. Również używa próbkowania. Domyślne ustawienia dają w wyniku duży zestaw danych profilowania, które dostarczają informacji na temat mechanizmów działania aplikacji. Profiler wykrywa wszystkie wywołane metody i całą pamięć używaną do przetwarzania tych wywołań. Narzędzie zawiera szczegółowe informacje, takie jak ilość pamięci przeznaczonej dla różnych typów oraz ilość czasu spędzonego na tworzenie i usuwanie tych typów. Podczas gdy performance monitoring skupia się na wydajności to profiler monitoruje całą aktywność i dokumentuje ją. Uruchomienie profilera odbywa się w oknie Analyze | Profiler. Sekcja Hot Path określa najdroższe ścieżki kodu aplikacji i podąża tymi ścieżkami, aż wykryje wyższy poziom przetwarzania przeprowadzanego (a nie delegowanego) przez jedną funkcję. Sekcja Functions Doing Most Individual Work pomaga określić, gdzie dodatkowy czas może być wyeliminowany z wykonywania aplikacji, poprawiając tym samym wydajność aplikacji. Więcej informacji można znaleźć na stronie MSDN: Configuring Performance Sessions.

Windows Performance Monitor

Narzędzie systemu Windows Performance Monitor pozwala śledzić wiele charakterystyk uruchomionych aplikacji. Posiada ono setki indywidualnych monitorów z których niektóre są przeznaczone do śledzenia ASP.NET. Pojedyncze monitory są albo licznikami wydajności systemu albo licznikami wydajności aplikacji. Liczniki wydajności systemu są skupione na aplikacji i jej przebiegu uruchamiania, zatrzymywania i trwania. Liczniki wydajności aplikacji są skupione na detalach które dzieją się w aplikacji takich jak błędy, żądania i pamięć podręczna. Narzędzie to można uruchomić z menu RUN wpisując perfmon. Po uruchomieniu monitora można uruchomić Performance Monitor klikając jego nazwę w lewym panelu. Pojawi się okno w którym za pomocą guzika plus można dodać liczniki.

Tracing, Logging i Debugging

Śledzenie (ang. tracing) jest funkcjonalnością pozwalającą na analizowanie aplikacji w czasie uruchomienia. Wyrażenia śledzące są dostępne w przestrzeni nazw System.Diagnostic i pozwalają zapisywać informacje do jednej lub wielu klas nasłuchu TraceListener. Zaimplementowane klasy nasłuchu to TextWriterTraceListener, EventLogTraceListener, DelimitedListTraceListener i XmlWriterTraceListener. Klasa nasłuchu może zapisywać informacje do pliku tekstowego lub innego formatu. Aby zapisać informacje z dowolnego miejsca w kodzie należy użyć obiektu klasy Trace i jednej z metod Write, WriteIf, WriteLine lub WriteLineIf. Jeżeli istnieje taka potrzeba to można stworzyć własną klasę nasłuchu TraceListener. Śledzenie można włączyć lub wyłączyć w każdej chwili. Aby uruchomić śledzenie należy wykonać kilka kroków konfiguracyjnych. Najpierw trzeba utworzyć co najmniej jedną klasę nasłuchu Systems.Diagnostics.TraceListeners. Najprostszą metodą jest dodanie wpisu w pliku konfiguracyjnym:

<configuration>
    <system.diagnostics>
        <trace autoflush="false" indentsize="4">
            <listeners>
                <add name="myListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="TracingInfo.log" />
                <remove name="Default" />
            </listeners>
        </trace>
    </system.diagnostics>
</configuration>

Przykład zapisu informacji do śledzenia:

Trace.WriteLine(“Message”)

Logowanie (ang. logging) jest procesem przechwytywania informacji o aplikacji i zapisywania ich. Generalnie jest dodawane do metod które wykonują jakąś pracę i o których wykonaniu chcemy mieć informacje takie jak czas wykonania, start, ilość danych itp. Logowanie można wykonać za pomocą narzędzi zewnętrznych jak NLog i Log4net lub użyć przestrzeni nazw System.Diagnostics do przechwycenia tych informacji. Większość narzędzi logujących pozwala na zapisywanie informacji wg poziomów krytyczności jak np Error, Info i Debug. Pozwala to konfigurować poziom krytyczności który ma być zapisywany dla danego środowiska.

Logowanie błędów może być obsługiwane automatycznie poprzez użycie atrybutu HandleErrorAttribute, przez nadpisanie metody kontrolera OnException lub przez użycie własnego filtru obsługującego błędy. Przykład użycia HandleErrorAttribute:

[HandleError(ExceptionType=typeof(System.IOException), View="FileError")]

Przykład użycia metody OnException:

protected override void OnException(ExceptionContext exceptionContext)
{
    if (exceptionContext.IsChildAction)
    {
        //we don't want to display the error screen if it is a child action,
        base.OnException(exceptionContext);
        return;
    }

    // log the exception in your configured logger
    Logger.Log(exceptionContext.Exception);

    //handle when the app is not configured to use the custom error path
    if (!exceptionContext.HttpContext.IsCustomErrorEnabled)
    {
        exceptionContext.ExceptionHandled = true;
        this.View("ErrorManager").ExecuteResult(this.ControllerContext);
    }
}

Zarządzanie wyjątkami może również odbywać się globalnie w metodzie Application_Error pliku Global.asax.

Code contracts

Kontrakty kodu (ang. code contracts) zostały dodane z .NET Framework 4.0 i są sposobem aby metoda była odpowiedzialna za definiowanie i publikowanie własnych warunków wewnętrznych. te warunki zawierają warunki wstępne (ang. preconditions), które definiują akceptowane parametry metody; warunki niezmienne (ang. invariant conditions) które określają definicję rzeczy które nie mogą być zmienione w czasie życia klasy; oraz warunki oczekiwane (ang. postconditions) które definiują oczekiwania co do zwracanego wyniku. Kontrakty kodu zgłaszają wyjątki jeżeli warunki nie zostaną spełnione i dają instrukcje w czasie programowania o tym jakie są oczekiwania w czasie wywoływania metod kontraktowych. Narzędziem ułatwiającym pracę z kontraktami jest Code Contracts Editor Extensions i można je pobrać z Visual Studio Gallery. Po dodaniu tego narzędzia we właściwościach projektu pojawia się dodatkowa zakładka. Używanie kontraktów wymaga od programisty innego podejścia do zarządzania przepływem wyjątków w aplikacji. Kontrakty są sposobem na zakodowanie zależności i udostępnienie ich dla klienta metody. Stary sposób sprawdzania parametru:

internal Article GetArticle(int id)
{
    if (id <= 0)
    {
        throw new ArgumentException("id");
    }
    // some work here
}

Dzięki kontraktom można go zastąpić w poniższy sposób:

internal Article GetArticle(int id)
{
    System.Diagnostics.Contracts.Contract.Requires(id > 0);
    // some work here
}

Jeżeli kontrakt nie zostanie spełniony to kod zgłosi wyjątek ContractException.

Invariant conditions sprawdza czy klasa nie znajduje się w niedozwolonym stanie, np:

[ContractInvariantMethod]
protected void ManageInvariant()
{
    System.Diagnostics.Contract.Invariant(this.Id < 0);
}

Aplikacja może naruszyć tę zasadę tylko w czasie wykonywania prywatnych metod.

Kontrakt postconditions można dodać poprzez użycie metody Ensures, np:

internal Article GetArticle(int id)
{
    System.Diagnostics.Contracts.Contract.Requires(id > 0);
    System.Diagnostics.Contracts.Contract.Ensures(
        Contract.Results<Article>() != null);
    // some work here
}

Więcej informacji dostępnych na stronie MSDN Code Contracts

Niepowodzenie kontraktu może być zarządzane na różne sposoby poprzez zarejestrowanie obsługi zdarzenia Contract.ContractFailed.

Health monitoring

Monitorowanie stanu (ang. Health monitoring) jest systemem wbudowanym w ASP.NET, który śledzi różne zdarzenia zachodzące wewnątrz aplikacji web. Zdarzenia cyklu życia aplikacji są zgłaszane kiedy aplikacja startuje i jest zatrzymywana, w czasie procesu startu i zatrzymania i podczas regularnych kontroli. Zdarzenia bezpieczeństwa są zgłaszane kiedy próba logowania się nie powiedzie lub kiedy nieautoryzowany użytkownik próbuje otrzymać dostęp do zabezpieczonego zasobu. Błędy aplikacji pokrywają wszystkie błędy które mogą być zgłoszone. Monitorowanie jest dodawane w konfiguracji. Istnieją specjalne mapowania dla specyficznych błędów, błędów infrastruktury, błędów przetwarzania, awarii i innych zdarzeń. Każde zdarzenie może być obsługiwane inaczej poprzez odpowiednia konfigurację. >NET Framework posiada przykładową kompletną konfigurację Web.config w której można podejrzeć wszystkie możliwe zdarzenia, dostawców i inne opcje monitorowania. Przykładowy plik można znaleźć w %WINDIR%\Microsoft.NET\Framework\version\CONFIG. Przykład konfiguracji:

<healthMonitoring>
    <bufferModes>
        <add name="Critical Notification" maxBufferSize="100" maxFlushSize="20" urgentFlushThreshold="1" regularFlushInterval="Infinite" urgentFlushInterval="00:01:00" maxBufferThreads="1" />
        <add name="Logging" maxBufferSize="1000" maxFlushSize="200" urgentFlushThreshold="800" regularFlushInterval="00:30:00" urgentFlushInterval="00:05:00" maxBufferThreads="1" />
    </bufferModes>
    <providers>
        <add name="EventLogProvider" type="System.Web.Management.EventLogWebEventProvider, System.Web" />
    </providers>
    <profiles>
        <add name="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00" custom="" />
        <add name="Critical" minInstances="1" maxLimit="Infinite" minInterval="00:00:00" custom="" />
    </profiles>
    <rules>
        <add name="All Errors Default" eventName="All Events" provider="EventLogProvider" profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00" custom="" />
        <add name="Failure Audits Default" eventName="App Lifetime Events" provider="EventLogProvider" profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00" custom="" />
    </rules>
    <eventMappings>
        <add name="All Events" type="System.Web.Management.WebBaseEvent,System.Web" startEventCode="0" endEventCode="2147483647" />
        <add name="Heartbeats" startEventCode="0" endEventCode="2147483647" type="System.Web.Management.WebHeartbeatEvent,System.Web" />
        <add name="App Lifetime Events" startEventCode="0" endEventCode="2147483647" type="System.Web.Management.WebApplicationLifetimeEvent" />
    </eventMappings>
</healthMonitoring>

Sekcja definiuje okres oczekiwania przed zapisem do dostawcy. Sekcja definiuje dostawców używanych do zapisywania zdarzeń. Sekcja pozwala zdefiniować zestawy parametrów używanych przy konfiguracji zdarzeń. Sekcja tworzy powiązanie pomiędzy dostawcami i zdarzeniami. Sekcja pokazuje, że aplikacja jest mapowana do logowania zdarzeń, heartbeats i zdarzeń cyklu życia aplikacji. Więcej na ten temat można przeczytać na stronie MSDN Logging Error Details with ASP.NET Health Monitoring

Projektowanie strategii obsługi wyjątków

Wyjątki są standardową częścią aplikacji. Nawet jeżeli aplikacja jest wolna od błędów to może zgłaszać wyjątki lub mogą występować inne problemy zależne od czynników zewnętrznych jak np problemy z siecią. Projektując aplikację ASP.NET MVC należy rozważyć potencjalne punkty w których mogą pojawić się problemy jak np wywołania serwisu sieciowego lub dostęp do plików. należy zastanowić się co zrobić w sytuacji występowania błędu, czy powiadomić o tym fakcie użytkownika a jeżeli tak to jaką informację wyświetlić. Należy również pomyśleć o opcjach odzyskiwania aby utrzymać aplikację w stanie ciągłego działania oraz o tym jakie informacje diagnostyczne należy przechwycić.

Obsługa wyjątków pomiędzy warstwami

Zazwyczaj warstwy w wielowarstwowych aplikacjach obsługują dwa zestawy wyjątków: własne wyjątki i wyjątki z warstwy położonej bezpośrednio pod nią w stosie. Przykładowo warstwa UI nie powinna obsługiwać wyjątku zgłoszonego w warstwie dostępu do danych. taki wyjątek powinien być obsłużony w warstwie biznesowej.

Własne strony błędów

Choć IIS posiada własne strony błędów to jest to raczej bardzo rzadkie żeby te strony były używane przez aplikacje oraz aby prowadziły odpowiedni poziom informacji wyświetlanych użytkownikowi. W ASP.NET MVC można tworzyć niestandardowe strony do wyświetlania błędów. Te strony mogą być zgodne ze stylem wyglądu zdefiniowanym dla aplikacji ale pokazywać dane specyficzne dla błędu. Strony błędów można tworzyć tak jak każdą inną kombinację kontrolera i widoków. Definiuje się kontroler obsługi błędów i tworzy się widoki do zarządzania różnymi typami błędów. Odnośniki do stron błędów mogą być dodane w kodzie jak i w konfiguracji. W aplikacji MVC można np stworzyć kontroler ErrorManagerController, który będzie posiadał różne akcje dla każdego możliwego statusu HTTP oraz domyślną akcję ServerError. Strona Global.asax jest jednym ze sposobów użycia własnych stron błędów. można użyć metody wspólnej dla ASP.NET i ASP.NET MVC którą jest Application_Start. Można również użyć metody Application_Error która jest globalną obsługą błędów która jest wywoływana kiedy nieobsłużony wyjątek trafia do stosu aplikacji. Przykład metody Application_Error:

public void Application_Error(Object sender, EventArgs e)
{
    if (Server != null)
    {
        //Get the context
        HttpContext appContext = ((MvcApplication)sender).Context;
        Exception ex = Server.GetLastError().GetBaseException();
        //Log the error using the logging framework
        Logger.Error(ex);
        //Clear the last error on the server so that custom errors are not fired
        Server.ClearError();
        //forward the user to the error manager controller.
        IController errorController = new ErrorManagerController();
        RouteData routeData = new RouteData();
        routeData.Values["controller"] = "ErrorManagerController";
        routeData.Values["action"] = "ServerError";
        errorController.Execute(
            new RequestContext(new HttpContextWrapper(appContext), routeData));
    }
}

Obsługę błędów można również dodać poprzez konfigurację dodając sekcję do , np:

<customErrors mode="RemoteOnly" defaultRedirect="ErrorManager/ServerError">
    <error statusCode="400" redirect="ErrorManager/Status400" />
    <error statusCode="403" redirect="ErrorManager/Status403" />
    <error statusCode="404" redirect="ErrorManager/Status404" />
</customErrors>

Element customErrors posiada dwa interesujące atrybuty: mode i defaultRedirection. Atrybut mode może mieć trzy wartości: On, Off i RemoteOnly. RemoteOnly oznacza, że strona ma być wyświetlana dla zdalnych użytkowników a dla lokalnych będzie wyświetlana standardowa strona błędu. Atrybut defaultRedirection jest adresem strony która będzie wyświetlona jeżeli błąd nie będzie obsługiwany przez bardziej specyficzną stronę. Błędy HTTP 500 są obsługiwane przez inne rodzaje obsługi niż konfiguracja, np przez filtry lub zdarzenie OnException. Aby błędy były wyświetlane należy również ustawić właściwość w .

First chance exceptions

Wyjątki First chance exceptions są wyjątkami które są bezpośrednio wyrzucane, zanim zostaną obsłużone przez error handler. Przykładem takiego wyjatku może być wyjątek zgłaszany w metodzie Application_Start pliku Global.asax. Można dodać obsługę takich wyjątków do aplikacji. Ta obsługa będzie wywoływana dla każdego wyjątku zgłoszonego w aplikacji. Można w niej dodać logowanie lub inną czynność diagnostyczną. Należy zwrócić szczególną uwagę aby obsługa tych wyjątków sama nie zgłaszała wyjątków ponieważ może to doprowadzić do kaskady wyjątków i spowodować przepełnienie stosu. Przykład przechwytywania FirstChanceExceptions w Global.asax:

protected void Application_Start()
{
    AppDomain.CurrentDomain.FirstChanceException +=
        CurrentDomain_FirstChanceException;

    AreaRegistration.RegisterAllAreas();
    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
    AuthConfig.RegisterAuth();
}
protected void CurrentDomain_FirstChanceException(object sender,
    System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs e)
{
    if (e.Exception is NotImplementedException)
    {
        // do something special when the functionality is not implemented
    }
}

Aby być pewnym, że Visual Studio przechwyci FirstChanceException,należy zaznaczyć w opcjach DEBUG Exceptions zgłaszanie i obsługę Common Language Runtime Exception.

Testowanie aplikacji web

Testowanie kodu jest jednym z podstawowych wymagań oprogramowania, ale nie jest to jeden z najbardziej powszechnie pomijanych lub minimalnie zarządzanych obszarów rozwoju oprogramowania. Jednym ze sposobów zarządzania nieoczekiwanych zdarzeń w kodzie jest pisanie i utrzymywanie testów jednostkowych. Testowanie jednostkowe to proces tworzenia testów wielokrotnego użycia które sprawdzają poprawność konkretnego podzbioru funkcjonalności. Istnieją dwa ważne aspekty wykonywania testu jednostkowego. Test powinien dokładnie pokrywać testowany obszar funkcjonalności. Testy powinny być napisane zarówno dla pozytywnego przepływu w stosie wywołań jak i negatywnego przepływu a w tym testować również przypadki wystąpienia błędu w niższej warstwie stosu.

Testy jednostkowe

W aplikacji ASP.NET MVC można tworzyć testy jednostkowe dla prostych metod, modeli, metod aplikacji i akcji w kontrolerach poprzez sprawdzanie zwracanego rezultatu. W Visual Studio można dodać projekt z testami jednostkowymi poprzez Add New Project | Unit Test Project. Dobrą praktyką jest pisanie testów dla każdej klasy osobno i nadawanie im nazw które jednoznacznie określają co jest testowane. Przykład metody do testowania:

public double Add(object initNumber, object additional)
{
    double baseNumber = Convert.ToDouble(initNumber);
    double addingNumber = Convert.ToDouble(additional);
    return baseNumber + addingNumber;
}

Gdy parametry wejściowe są nieodpowiedniego typu to zgłoszony zostanie wyjątek InvalidCastException. Przykład testu dla tej metody:

[TestMethod]
public void Add_Test()
{
    CalculationManager manager = new CalculationManager ();
    Assert.IsTrue(manager.Add(2, 2).Equals(4), "2 + 2 = 4");
    Assert.IsTrue(manager.Add(2, 2.5).Equals(4.5), "2 + 2.5 = 4.5");
    try { manager.Add(DateTime.Now, 2.5);}
    catch (Exception ex){ Assert.IsInstanceOfType(ex,
        typeof(InvalidCastException), "Today + 2 = oops");}
}

Przykład testu akcji kontrolera:

[TestMethod]
public void Index_Test()
{
    CalculationController controller = new CalculationController();
    Assert.IsInstanceOfType(controller.Index(), typeof(ExpectedViewResult));
}

Testy jednostkowe powinny być wykonywane bez żadnych zależności, tzn, że powinny być niezależne od bazy danych lub UI.

Tworzenie mock’ów

Funkcja Fakes w VS 2012 oferuje wiele wsparcia podczas pisania testów jednostkowych. Funkcja Fakes wprowadza dwa sposoby na zarządzanie zależnościami w czasie tworzenia testów: shims i stubs. Shim jest fragmentem kodu który przechwytuje wywołanie do assembly w celu zwrócenia obiektu i zwraca jego makietę. Jest używany do zastępowania klas zewnętrznych. Stub jest kodem który zastępuje klasę przez ograniczony podzbiór klas makiet. jest używany do zastępowania innych klas w aplikacji. Przykład użycia shim do kontroli czasu zwracanego przez DateTime.Now:

using (ShimsContext.Create())
{
    // insert the delegate that returns call for DateTime.Now
    System.Fakes.ShimDateTime.NowGet = () => new DateTime(2010, 1, 1);
    MethodThatUsesDateTimeNow();
}

Przykład użycia stub:

public interface ICalculator
{
    double Add(double firstNumber, double lastNumber);
}

public class Mathematics
{
    private ICalculator calculator;
    public Mathematics (ICalculator calc)
    {
        calculator = calc;
    }
    public double AddNumbers()
    {
        return calculator.Add(1,1);
    }
}
// ...
[TestMethod]
public void TestAdd()
{
    // Create the fake calculator:
    ICalculator calculator = new Calculator.Fakes.StubICalculator()
    {
        // Define each method:
        Add = (a,b) => { return 25; }
    };

    // In the completed application, item would be a real one:
    var item = new Mathematics(calculator);

    // Act:
    double added = item.AddNumbers();
    Assert.AreEqual(25, added);
}

Visual Studio Web Tests

W edycji Visual Studio Ultimate 2012 można tworzyć i uruchamiać testy wydajności i obciążenia (web performance tests i load tests). Pierw tworzy się testy web które chcemy uruchomić podczas trwania testu obciążenia. Te testy mogą być skalowane od jednego do wielu użytkowników aby sprawdzić jak aplikacja zachowuje się w czasie obciążenia. Liczba użytkowników może zostać ustalona na stałe lub być inkrementowana. Można również ustawić progi oparte na systemie, który będzie monitorować gdy aplikacja osiągnie próg obciążenia procesora lub pamięci. Testowanie rozwiązania obejmują test dymu, testy warunków skrajnych oraz testy wydajności (smoke test, stress test i performance test). Test typu smoke używa małego obciążenia w krótkim czasie. Można użyć go od razu po wdrożeniu aplikacji na nowe środowisko aby mieć pewność, że aplikacja działa prawidłowo. Test typu stress uruchamia aplikację pod dużym obciążeniem przez długi okres czasu ujawniać zachowania aplikacji w warunkach dużego obciążenia. Test typu performance bada reagowania aplikacji.

Aby utworzyć testy należy dodać projekt Web Test and Load Project po czym należy skonfigurować przepływ testów które będą używane w teście. Najprostszym sposobem jest nagranie serii akcji w aplikacji web. W nowym projekcie powinien znajdować się plik .webtest który należy otworzyć i rozpocząć nagrywanie przepływu. Istnieją trzy podejścia przy wykonywaniu testów obciążeniowych: constant, step i goal-based. Typ constant pozwala na ustawienie stałej liczby użytkowników i użycie ich dla całego wykonania testu. Typ step dodaje użytkowników do testu stopniowo. Należy ustawić cztery wartości dla tego testu: Initial user count, Maximum user count, Step duration i Step user count. Typ goal-based ładuje test tak jak typ step jednakże różni się tym, że nie zlicza uruchomionych użytkowników jako kluczowej informacji tylko zlicza użytkowników jako sposób na dotarcie do innych celów, np obciążenie procentowe CPU i procentowe zużycie pamięci.

Debugowanie aplikacji Windows Azure

Debugowanie aplikacji web może być dużym wyzwaniem. Dodanie aplikacji w aspekcie zdalnym do Windows Azure może uczynić debugowanie jeszcze bardziej skomplikowanym. Dlatego na potrzeby Windows Azure dodano dodatkowe dedykowane narzędzia diagnostyczne Windows Azure–specific diagnostics API, Microsoft.WindowsAzure.Diagnostics. Uruchomienie diagnostyki w aplikacji wdrożonej na Windows Azure wymaga kilku kroków. Pierw należy dodać informacje do pliku ServiceDefinition.csdef aby można było zaimportować moduł Diagnostics. Należy także upewnić się, że informacja jest dodana do pliku ServiceConfiguration.cscfg aby moduł diagnostyki miał dostęp do bazy danych i innych usług biznesowych. Kiedy diagnostyka jest już dostępna w aplikacji to można ją wywołać z poziomu kodu lub użyć wbudowanego monitora zdarzeń. Aby skonfigurować nowy monitor należy utworzyć nowy plik Diagnostics.wadcfg, który zawiera wpisy konfiguracyjne ustawiające odpowiednie liczniki. Po zapisaniu informacji diagnostycznych można programistycznie pobrać te informacje z serwera lub dostać je na żądanie. Przykład pliku ServiceDefinition.csdef:

<ServiceDefinition name="WindowsAzure1" xmlns=http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition schemaVersion="2013-03.2.0">
    <WebRole name="WebRole1">
        <!-- Other configuration information here ->
        <Imports>
        <Import moduleName="Diagnostics" />
        </Imports>
    </WebRole>
</ServiceDefinition>

Przykład pliku ServiceConfiguration.cscfg:

<ServiceConfiguration serviceName="WindowsAzure2" xmlns="http://schemas.microsoft.com/ServiceHosting/
        2008/10/ServiceConfiguration" osFamily="3" osVersion="*" schemaVersion="2013-03.2.0">
    <Role name="WebRolePrimary">
        <Instances count="1" />
        <ConfigurationSettings>
            <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" />
            <!—- this version is for deployment on the azure server
            <Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics
                .ConnectionString" value="DefaultEndpointsProtocol
                =https;AccountName=demoapp;AccountKey=[your key]" /> -->
        </ConfigurationSettings>
    </Role>    
</ServiceConfiguration>

Przykład dodania dwóch liczników wydajności w pliku Diagnostics.wadcfg:

<DiagnosticMonitorConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration" configurationChangePollInterval="PT1M" overallQuotaInMB="4096">

    <PerformanceCounters bufferQuotaInMB="0" scheduledTransferPeriod="PT30M">
        <PerformanceCounterConfiguration counterSpecifier="\Process(WaWorkerHost)\Thread Count" sampleRate="PT30S" />
        <PerformanceCounterConfiguration counterSpecifier="\.NET CLR Interop(_Global_)\# of marshalling" sampleRate="PT30S" />
    </PerformanceCounters>

    <DiagnosticInfrastructureLogs bufferQuotaInMB="0" scheduledTransferLogLevelFilter="Verbose" scheduledTransferPeriod="PT30M" />

</DiagnosticMonitorConfiguration>

W Windows Azure można również skonfigurować IntelliTrace dla aplikacji. Aby tego dokonać należy wdrożyć aplikację używając Visual Studio Ultimate 2012 i dodać pewne zmiany w czasie konfiguracji wdrożenia. Informacje zbierane przez IntelliTrace mogą być pobrane za pomocą Visual Studio. Należy zaznaczyć pole wyboru Enable IntelliTrace i wybrać informacje które mają być zbierane. Do wyboru są dwie główne kategorie: tylko zdarzenia lub zdarzenia i informacje o wywołaniach. Wybranie tylko zdarzeń ma minimalny wpływ na wydajność aplikacji lecz zbieranie informacji o wywołaniach ze zdarzeniami może mieć duży wpływ na działanie aplikacji. Po pobraniu kopii dzienników można otworzyć je w oknie Server Explorer wybierając Windows Azure Compute.