Jak zmienić generowanie kodu w ASP.NET MVC?

Wprowadzenie

Dodając nowy kontroler lub widok do aplikacji ASP.NET MVC wybieramy jeden z szablonów, które wykorzysta Visual Studio do ich wygenerowania. Jest to bardzo przydatne, gdy na przykład formularz edycji zawiera wiele pól. Visual Studio wygeneruje kontrolkę dla każdej właściwości z klasy, którą ustawimy jako model widoku. Podobnie jest z generowaniem kontrolerów. Jest to bardzo fajne, ale niestety na dłuższą metę tak wygenerowany kod, nie jest tym, co potrzebujemy i nanosimy do niego wiele zmian.

Zauważyłem, że dużo osób nie wie, że Visual Studio wykorzystuje szablony T4 (podobne do szablonów jakie użyłem do generowania repozytoriów) do generowania widoków oraz kontrolerów. W tym wszystkim najfajniejsze jest to, że możemy te szablony dowolnie modyfikować i dostosowywać do swoich potrzeb. Wszystko po to, aby jeszcze szybciej i efektywniej dodać nowe kontrolery oraz widoki do aplikacji.

CodeTemplates – generowanie kodu w ASP.NET MVC

W zależności od wersji Visual Studio szablony znajdują się w różnej lokalizacji. Na przykład u mnie na komputerze, gdzie mam zainstalowane Visual Studio 2017 Enterprise szablony znajdują się w katalogu C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates.

Możemy zmienić szablony w tej lokalizacji, ale takie rozwiązanie nie jest zbyt dobre. Po pierwsze będzie dotyczyło to wszystkich projektów, które robiły w danym Visual Studio. Jak robisz tylko jeden projekt to może to się sprawdzić, ale bardzo często rozwijamy wiele projektów na raz, gdzie możemy chcieć mieć różne szablony dla każdego z projektu. Dodatkowo nie jesteśmy w stanie łatwo współdzielić takich szablonów w zespole. Warto, aby każdy programista wykorzystywał te same szablony.

Innym rozwiązaniem jest dodanie szablonów do projektu ASP.NET MVC. Gdy utworzymy katalog CodeTemplates w głównym folderze projektu i tam wrzucimy szablony, Visual Studio skorzysta z nim, a nie z szablonów z Program Files. Dzięki takiemu rozwiązaniu możemy modyfikować szablony dla poszczególnych projektów oraz przy okazji są one w repozytorium dostępne dla wszystkich osób w zespole i będą automatycznie wykorzystywane przez Visual Studio.

Szablony możemy ręcznie skopiować z katalogu Viual Studio lub skorzystać z czegoś gotowego. W nugecie znajdują się pakiety z szablonami dla poszczególnych wersji ASP.NET MVC. W przykładzie skorzystałem z pakietu Mvc5CodeTemplatesCSharp (https://www.nuget.org/packages/Mvc5CodeTemplatesCSharp/). Dla innych wersji ASP.NET MVC po prostu wystarczy zmieć numerek w nazwie pakietu.

Po zainstalowaniu pakietu pojawi się nowy katalogu (CodeTemplates) w projekcie z wszystkimi szablonami:

code templates solution explorer

Pakiet ma jeden minus. Mimo, że w nazwie jest CSharp, to niestety dodaje również pliki szablonów dla Visual Basic, które trzeba usunąć, gdy nam to przeszkadza.

Darmowy kurs Visual Studio

Pracując z setkami programistów zauważyłem, że większość osób nie pracuje efektywnie w Visual Studio. W skrajnych przypadkach korzystali z kopiowania z wykorzystaniem menu Edit. Wiem, że to dziwne, ale naprawdę niektórzy tak pracują. Dlatego postanowiłem stworzyć kurs Visual Studio, aby pomóc koleżankom i kolegom w efektywniejszej pracy.

Przygotowałem 20 lekcji email, w których pokaże Ci w jaki sposób pracować efektywnej i szybciej w Visual Studio. Poznasz dodatkich, bez których nie wyobrażam sobie pracy w tym IDE.

Po więcej informacji zapraszam na dedykowaną stronę kursu: Darmowy Kurs Visual Studio.

Quiz C#

Ostatnio przygotowałem również quiz C#, w którym możesz sprawdzić swoją wiedzę. Podejmiesz wyzwanie?

Modyfikacja generowania widoku dodania (Create)

Modyfikowanie szablonów zaczniemy od widoku dodania obiektu. W katalogu MvcView znajdują się szablony, które Visual Studio używa podczas dodania widoku. Szablon możemy zmienić na dwa sposobu: zmienić istniejący lub dodać nowy (na przykład skopiować Create.cs.t4 pod inną nazwą i wtedy zmodyfikować). Visual Studio w oknie dodania nowego widoku wyświetla wszystkie szablony jakie znajdzie w katalogu MvcView. Poniżej zrzut ekranu z dodatkowym szablonem Create2:

create2 view template

Jedną z rzeczy, która denerwuje mnie w domyślnych szablonach jest tytuł widoku. Domyślnie tytuł jest ustawiany na nazwę widoku, przez co muszę go za każdym razem zmieniać po utworzeniu widoku.

W moich aplikacjach viewmodel dla widoków posiada właściwość PageTitle, której wartość jest ustawiana w samym viewmodelu lub kontrolerze. Dzięki temu dużo łatwiej można testować logikę ustawiania tytułu za pomocą testów jednostkowych niż dodanie tej logiki w widoku. Dlatego w pierwszej kolejności zmieniam sposób ustawiania tytułów w widokach.

Poniżej widać fragmenty widoku Create utworzone przez domyślny szablon Create.cs.t4 (link do szablonu) oraz zmodyfikowany Create2.cs.t4 (link):

default create view

modified create view

Sama modyfikacja szablonu nie była skomplikowana. Wystarczyło w trzech miejscach zamienić <#= ViewName#> na Model.PageTitle. Najlepiej widać na porównaniu tych dwóch plików:

create template diff

Jak widzisz prosta zmiana w szablonie powoduje, że przy każdym utworzeniu nowego widoku zaoszczędzam trochę czasu na modyfikowanie wygenerowanego pliku. Mogę przebudować cały szablon, aby od razu otrzymywać to co potrzebuje. Nic nie stoi na przeszkodzie, aby zmodyfikować strukturę generowanego htmla, czy inne rzeczy w widoku.

W swoich aplikacja na początku przygotowuje wszystkie szablony widoków i dopiero mają je gotowe zabieram się do tworzenie samych widoków. Później wystarczy tylko dodać jakieś specyficzne rzeczy do widoku – na przykład trochę javascript, który doda dynamiczne elementy.

Szablony kontrolerów

Poza szablonami widoków możemy też modyfikować szablony kontrolerów. Przygotowując szablon kontrolerów możemy później zaoszczędzić bardzo dużo czasu. Pracując z programistami zauważyłem, że większość tworzy pusty kontroler, a następnie dodaje do niego ręcznie kod, przez skopiowanie go z innego kontrolera i późniejszą jego modyfikację. Rzadko używają wbudowanych szablonów.

Jednym z powodów takiego podejścia jest to, że domyślne szablony generują kod daleki od ideału. Poniżej znajduje się kod kontrolera wygenerowany przez szablon „MVC 5 Controller with views, using Entity Framework” dla klasy Product:

Jak widać ten kod jest daleki od wszystkich dobrych praktyk. Aby pokazać Ci możliwość szablonów kontrolerów przygotowałem prostą modyfikację. Jest ona dużo lepsze od tej domyślnej, ale nie jest jeszcze docelowym rozwiązaniem, które wykorzystuje w swoich projektach – nie chciałem za bardzo rozbudowywać przykładu, aby się nie skomplikował.

W przykładzie wykorzystałem ideę viewmodeli przekazywanych do widoku, mapowanie obiektów z wykorzystaniem automappera, wstrzykiwanie zależności. Możesz użyć tego szablonu do dalszej modyfikacji i dostosowywania do swoich potrzeb. Poniżej znajduje się kod kontrolera wygenerowany przez zmodyfikowany szablon. Prawda, że jest dużo lepiej?

Nie będę już opisywał zmian w szablonie. Jest ich na tyle dużo, że byłoby to prawdopodobnie nudne. Zachęcam do przejrzenia zmian szablonu na githubie (https://github.com/danielplawgo/T4Repositories/commit/8a5ba567dee4614bf399793011aa4c4ef39be3b1#diff-c781b66a7951fb83054dc5d253c37285).

Wykorzystanie zmodyfikowanego szablonu kontrolera

Chciałbym jeszcze wspomnieć o kilku założeniach, które wykorzystałem podczas modyfikowania szablonu. Szablon wykorzystuje domyślne szablony widoki do tworzenia widoków. Dlatego trzeba je zmodyfikować, a nie dodać nowe. W przykładzie zmodyfikowałem kod szablonów, aby nie generowały pół dla właściwości PageTitle, która jest w viewmodelu, aby nie trzeba było jej usuwać.

Kontroler oraz widoki są generowane dla viewmodelu (ProductViewModel), a nie modelu. Jest to spowodowane tym, że viewmodel jest model dla widoków. W kodzie szablonu natomiast z nazwy viewmodelu usuwam „ViewModel” i mam nazwę modelu, którą wykorzystuje w kodzie kontrolera. Aby wszystko działało potrzebuje, aby klasy takie jak logika biznesowa miały schematyczne nazwy (np. IProductLogic). Podobnie jest z metodami wykorzystywanymi w kontrolerze z logiki biznesowej (tutaj przydaje się bazowy interfejs dla logiki).

Mając już taki szablon próżniejsza praca jest dużo łatwiejsza. Przed utworzeniem kontrolera tworzy wymagane viewmodele (viewmodel dla edytowanego obiektu np. ProductViewModel oraz dla akcji index IndexViewModel). Później generuje kontroler oraz widoki z wykorzystaniem szablonu i na koniec nanoszę ewentualnie jakieś modyfikacje (na ogół jest ich mało). Do tego dochodzą jakieś inne rzeczy jak na przykład mapowania automappera.

Jeszcze raz zachęcam do przejrzenia szczegółowo przykładu. Jak będziesz miał jakieś pytania, to pisz śmiało w komentarzu.

Przykład

Kod przykładu znajduje się na github (https://github.com/danielplawgo/T4Repositories). Jest to ten sam przykład, który użyłem w wpisie odnośnie generowania klas repozytoriów. Dodałem nowy projekt aplikacji ASP.NET MVC, w której są omawiane szablony. Aby uruchomić samą aplikację wystarczy w web.config ustawić connection stringa do bazy. Testuj, sprawdzaj, modyfikuj 🙂

Podsumowanie

Kolejny raz szablony T4 ułatwiają dodawanie kodu do aplikacji. Dzięki CodeTemplate w ASP.NET MVC możemy zmodyfikować domyślne szablony, aby generowane widoki oraz kontrolery były takie jak potrzebujemy. Zachęcam do ich wykorzystywania. U mnie w projektach bardzo się sprawdziły. Wystarczyło na początku poświęcić trochę czasu, aby później z dużą nawiązką go odzyskać podczas dodawanie kolejnych kontrolerów do aplikacji.

A Ty modyfikowałeś kiedyś domyślne szablony? Czy może w ogóle ich nie wykorzystujesz i dodajesz wszystko ręcznie? Daj znać w komentarzu.

1 thought on “Jak zmienić generowanie kodu w ASP.NET MVC?

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *