AJAX w ASP.NET

21 Marca 2016
DevMuster + AJAX

Niedawno brałem udział w hackathonie DevMuster organizowanym w PJATK. Tematyka obejmowała tworzenie rozwiązań w dwóch kategoriach: dla studentów i dla seniorów. Mój team postawił na aplikację łączącą seniorów chcących dzielić się wiedzą z juniorami szukających jakichś informacji.

Początkowo chcieliśmy pracować w Django, ale moja znajomość Pythona jest znikoma, więc po 3 godzinach wywaliliśmy cały projekt i zaczęliśmy od nowa w ASP.NET MVC. Trochę się pomęczyliśmy, ja zdobyłem nowe doświadczenia z Entity Framework, no i wyszło coś takiego.

A gdzie AJAX?

Postanowiłem pobawić się w częściowe widoki (Partial Views) i za pomocą AJAXa pobierałem markup z kontrolera, a następnie wszczepiałem w odpowiedni <div> na stronie przy pomocy jQuery. Robiłem to dość manualnie. Dopiero potem odkryłem wbudowane rozwiązanie w ASP.NET.

Przy czym trochę się napracowałem, żeby działało. Istnieje paczka NuGetowa Microsoft jQuery Unobtrusive Ajax, która zapewnia niezbędne pliki JavaScript. Niestety z nie znanych mi powodów Visual Studio nie przekopiowało ich do folderu ~/Scripts, więc musiałem zrobić to ręcznie. Tak samo musiałem ręcznie dodać je do widoku.

Jak to wygląda od strony klas?

Jeszcze nie rozgryzłem struktury klas w ASP.NET, ale większość rzeczy związanych z widokami opiera się o ,,Helpery”. Do nich należy AjaxHelper, który został rozszerzony w klasie AjaxExtensions o następujące metody:

  • ActionLink() - wypisuje <a> z odnośnikiem to podanej akcji. Po kliknięciu zapytanie zostanie obsłużone asynchronicznie przez JavaScript.
  • RouteLink() - jak wyżej, ale zamiast podawać akcji podajemy wirtualny URL.
  • BeginForm() - wypisuje <form> z odpowiednimi parametrami. Po kliknięciu w przycisk typu "submit" wysyła asynchroniczne zapytanie z parametrami z formularza.
  • BeginRouteForm() - jak wyżej, ale zamiast podawać akcji podajemy wirtualny URL.
  • GlobalizationScript() - wypisuje <script> zawierający odnośnik do skryptu z informacjami o globalizacji.

Prawie każdy z powyższych (oprócz ostatniego) zawiera parametr typu AjaxOptions, który definiuje następujące parametry:

 public class AjaxOptions
  {
    public AjaxOptions();
    public IDictionary<string, object> ToUnobtrusiveHtmlAttributes();
    public string Confirm { get; set; }
    public string HttpMethod { get; set; }
    public InsertionMode InsertionMode { get; set; }
    public int LoadingElementDuration { get; set; }
    public string LoadingElementId { get; set; }
    public string OnBegin { get; set; }
    public string OnComplete { get; set; }
    public string OnFailure { get; set; }
    public string OnSuccess { get; set; }
    public string UpdateTargetId { get; set; }
    public string Url { get; set; }
    public bool AllowCache { get; set; }
}

Parametry z przedrostkiem On to nazwy funkcji JavaScriptowych, które mają zostać wywołane w odpowiedzi na dany event.

Confirm określa wiadomość jaką dostanie użytkownik do potwierdzenia przed wysłaniem żądania.

InsertionMode to enum, który określa co zrobić z odpowiedzią. Możliwe jest Replace, InsertBefore oraz InsertAfter (jest też opcja ReplaceWith, które jest bardziej zgodna z jQuery mimo, że Microsoft domyślnie używa Replace). Dotyczy to obiektu, którego ID możemy zdefiniować w UpdateTargetId (domyślnie jest to wstawiony element).

A LoadingElementDuration określa czas animacji chowania/pokazywania obiektu ładowania, na który wskazuje LoadingElementId.

Przykład
<div id="messages"></div>

@using (Ajax.BeginForm("AjaxTest",
    new AjaxOptions
    {
        Confirm = "Czy napewno chcesz wysłać wiadomość?",
        HttpMethod = "Post",
        InsertionMode = InsertionMode.InsertAfter,
        UpdateTargetId = "messages",
        OnComplete = "ajaxComplete"
    }))
{
    @Html.Label("message", "Wiadomość");
    @Html.TextArea("message");
    <button type="submit">Wyslij</button>
}

W powyższym przykładzie wysyłamy message w zapytaniu POST do akcji "AjaxTest", a to co otrzymamy dopisujemy na końcu do DIVa ,,messages”.

Cały przykładowy projekt możesz pobrać z mojego Githuba.