Trwa konkurs "Ogól naczelnego", w którym codziennie możecie wygrać najnowsze maszynki systemowe Hydro Connect 5 marki Wilkinson Sword.

Więcej informacji
Strona używa cookies (ciasteczek). Dowiedz się więcej o celu ich używania i zmianach ustawień. Korzystając ze strony wyrażasz zgodę na używanie cookies, zgodnie z aktualnymi ustawieniami przeglądarki.    X

ASP.NET — C# z JavaScript'em w pokojowym współistnieniu

Tło

Pierwszy raz z problemem wywołania funkcji bądź przekazania zmiennych z kodu pisanego w C# do kody JavaScript’owego spotkałem się przy okazji generowania wykresów z użyciem biblioteki Google Charts. Moja aplikacja napisana w ASP.NET MVC korzystała z bazy danych stworzonej przy użyciu Entity Framework. Model przekazywany do widoku z kontrolera nie posiadał w sobie żadnych danych. Były one pobierane z bazy dopiero w momencie wywołania odpowiednich funkcji. I tu pojawił się problem. W jaki sposób dane uzyskane w ten sposób „wstrzyknąć” do tablicy w JS, na podstawie której tworzony był wykres?

Struktura

Dla ułatwienia przybliżę tylko tę część struktury projektu, która jest istotna:

Models

  • /BrandC.cs – klasa modelu
Views/Brand
  • /Index.cshtml – widok
  • /ChartsView.cshtml – widok częściowy renderowany wewnątrz index.cshtml
Views/Shared
  • /_Layout.cshtml – layout strony, zawiera sekcję head oraz body, wewnątrz body w <div id=”content”> </div> renderowane są widoki.

Problem 1. – dodawanie kodu do sekcji head z poziomu widoków

Ideą było zadeklarowanie wszystkich opcji wykresów z poziomu sekcji head strony. Jako, że dane zależne były od modelu przekazanego do widoku wypełnienie tablicy z danymi musiało nastąpić w pliku Index.cshtml. Całkiem eleganckim rozwiązaniem okazało się dodanie do pliku _Layout następującego kodu: @if (IsSectionDefined("AddToHead")) { @RenderSection("AddToHead", required: false) } A następnie w samym Indexie wstawiona została sekcja z kodem JS: @section AddToHead{ <script type="text/javascript> //Tutaj kod JavaScript </script> }

Po tych operacjach w widoku ChartsView można było już wstawić znacznik <div> odpowiadający za wyświetlanie wykresu.

Problem 2. – przekazanie danych z listy C# do listy w JavaScript

Funkcja przygotowująca dane do wykresu zwracała je w postaci List<int>. Najbardziej naturalnym sposobem przekazania ich do zmiennej z danymi do wykresu wydał się być JSON. I słusznie. Serializację danych w ASP.NET możemy przeprowadzić na dwa sposoby – za pomocą wbudowanej klasy System.Web.Helpers.Json lub frameworka Json.NET. Twórcy frameworka chwalą się, że jest to rozwiązanie szybsze od serializacji wbudowanej. Jak jest naprawdę postanowiłem przekonać się osobiście i test ten znajdzie się w kolejnym wpisie.
Samo przygotowanie danych odbywa się bardzo podobnie, a można zrobić je w dwóch miejscach. W przypadku rozwiązania systemowego funkcja wciąż zwracała List<int>. W kodzie JS pojawił się następujący zapis:

var inData = @Html.Raw(Json.Encode(Model.prepareChartDataV2()));Kolejno:
Html.Raw odpowiada za prawidłowe kodowanie – bez tego zapisu zamiast znaku „ pojawia się &quote.
Json.Encode jest wywołaniem metody serializującej z systemowej klasy Json. Jako argument przyjmuje obiekt, zwraca rzecz jasna string
Model.prepareChartDataV2() jest funkcją zwracającą wspomnianą wcześniej tablicę int’ów.

Korzystając z frameworka w kodzie funkcji zmieniłem typ zwracanych danych na string, a funkcję serializującą wywołałem w momencie zwracania wyniku: return JsonConvert.SerializeObject(listaInt);

Sam kod w pliku index uprościł się rzecz jasna o wywołanie metody serializującej: var inData = @Html.Raw(Model.prepareChartDataV2());

Serializacja obiektów

Nie tylko listy podlegają serializacji. Równie dobrze można serializować całe obiekty pobrane z bazy danych nawet, jeżeli są typu anonimowego. Załóżmy proste tabele bazy danych:

Wpis:WpisID|Autor|TagID12|Anon|2Tag:TagID|Tagi|2|Personal

W wypadku pobrania tego zestawu danych za pomocą najprostszego zapytanie LINQ do zmiennej var obj, po wykonaniu serializacji na obiekcie obj otrzymamy następującego json'a: using (var db = new _base()) { var pz = (from p in db.Wpis select new { p }).ToList(); return JsonConvert.SerializeObject(pz); }

{ „WpisID” : „12”, „Autor” : „Anon”, „Tag” : { „TagID” : „2”, „Tagi” : „Personal” } }

Adnotacja

Powyższy wpis to mój debiut blogerski. Motywacją do napisania tego tekstu był czas poświęcony na poszukiwanie rozwiązań omówionych tu zagadnień. Jako osoba nie będąca ekspertem w .NET uznałem, że warto podzielić się tym rozwiązaniem z innymi stającymi przed koniecznością rozwiązania podobnego problemu.

 

internet porady programowanie

Komentarze

0 nowych
DjLeo MODERATOR BLOGA  18 #1 18.05.2017 07:02

Witaj wiec na blogu i czekamy na następne wpisy ;)

kowgli   9 #2 18.05.2017 09:47

Można tak, chociaż od jakiegoś czasu wolę "pseudo SPA", gdzie wszystkie dane do widoku przekazywane za pomocą web service'u. Czy to jako JsonResult w kontrolerze, czy Web.API. Sam widok (w sensie cshtml) nie zawiera żadnych danych. Zamiast Razora można użyć np. knockouta, o ile nie używamy większych frameworków typu Angular.

W powyższym podejściu w pliku cshtml nie wrzucamy żadnych danych, tylko definiujemy szablon.

Można by powiedzieć, że generuje to dwa zapytania do serwera zamiast jednego, ale:
1. Pobierana strona html będzie zawsze taka sama, więc można ją cache'ować.
2. W wywołaniu web service'u zwracamy tylko te dane, które są potrzebne, więc minimalizujemy obciążenia łącza.

Wcześniej miałem zawsze niesmak związany z tym, że część logiki UI kontroluję po stronie serwera (w pliku cshtml), a część dynamicznie w JS. Teraz jest wszystko w jednym miejscu. Oczywiście web service jest dedykowany do danej strony (single responsibility) i zwraca tylko te dane, których strona potrzebuje.

Takie podejście dodatkowo ułatwia stosowanie dobrych praktyk, typu CQRS oraz zapewnia całkowitą separację części klienckiej od serwerowej. Serwer tylko udostępnia dane, a klient sam decyduje co z nimi zrobić. Unikamy mieszania odpowiedzialności i "spaghetti code" w pliku cshtml.

Autor edytował komentarz w dniu: 18.05.2017 10:29
  #4 19.05.2017 19:44

Opłaca się kodować w środowisku o porównywalnej wydajności do rozwiązań w Pythonie, tylko droższym hostingu?

Gratulacje!

znalezione maszynki:

Twój czas:

Ogól Naczelnego!
Znalazłeś(aś) 10 maszynek Wilkinson Sword
oraz ogoliłaś naszego naczelnego!
Przejdź do rankingu
Podpowiedź: Przyciśnij lewy przycisk myszki i poruszaj nią, aby ogolić brodę.