Aplikacja podzielona na warstwy - kilka pytań

0

Aktualna architektura aplikacji:
Domain (Modele domeny, EFDbContext)
Contracts (ViewModele i interfejsy Serwisów)
Application (implementacje Serwisów, w których korzystam z ORMa)
WebUI - projekt MVC

Nie korzystam ze wzorca repozytorium. Serwisy operują na EFDbContext.

WebUI ma w referencjach Contracts.

Powiedzmy, że w Contracts mam taki ViewModel:

public class RestaurantFormViewModel
{
     // coś tam...
     public SelectList AvailableCities { get; set; }
     public IEnumerable<HttpPostedFileBase> FilesToUpload { get; set; }
}

SelectList wymaga referencji do System.Web.Mvc
HttpPostedFileBase wymaga referencji do System.Web

1. Czy projekty Contracts oraz Application powinny zawierać wyżej wymienione referencje?

2. Kolejne pytanie odnośnie Ninject, którego klasy znajdują się w projekcie WebUI.

kernel.Bind<IRestaurantService>().To<RestaurantService>(); 

wymaga referencji z WebUI do Application, czy ta referencja powinna mieć miejsce?
Jeżeli nie, to jak powinienem poradzić sobie z tym problemem?
Stworzyć oddzielny projekt dla DI?

3. Czy aktualna architektura aplikacji jest w porządku?
Czytając sobie inne tematy na forum, natknąłem się na informacje, że w Domain (o ile tak powinien nazywać się projekt zawierający klasy mapowane przez ORM na tabele bazy danych), nie powinno być DbContextu.
Powinienem zatem stworzyć nowy projekt DataAccess i tam wrzucić DbContext?

4. W projekcie korzystam z ASP.NET Identity, czy powinienem stworzyć dla tego oddzielny projekt Infrastructure,
i wrzucić do niego model ApplicationUser dziedziczący po IdentityUser (aktualnie znajduje się on w projekcie Domain)?

5. Powiedzmy, że mam ViewModel z następującą właściwością "Action":

public class RestaurantFormViewModel
{
     public int RestaurantID { get; set; }

     public string Action
     {
         get
         {
             Expression<Func<RestaurantController, ActionResult>> update = (c => c.UpdateRestaurant(this));
             Expression<Func<RestaurantController, ActionResult>> create = (c => c.CreateRestaurant(this));

             var action = (RestaurandID != 0) ? update : create;
             return (action.Body as MethodCallExpression).Method.Name;
         }
     }
}

RestaurantForm.cshtml

@model Solution.Contracts.ViewModels.Restaurant.RestaurantFormViewModel

@using (Html.BeginForm(Model.Action, "Restaurant", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
}

dzięki której, widok RestaurantForm.cshtml może wywołać odpowiednią akcję z kontrolera Restaurant, a ja nie muszę robić dwóch widoków.
Wymaga jednak referencji z Contracts do WebUI...

Czy to rozwiązanie jest w ogóle poprawne, czy zrezygnować z niego i stworzyć oddzielne widoki dla NewRestaurant oraz EditRestaurant?

3
enx napisał(a):

Powiedzmy, że w Contracts mam taki ViewModel:

public class RestaurantFormViewModel
{
     // coś tam...
     public SelectList AvailableCities { get; set; }
     public IEnumerable<HttpPostedFileBase> FilesToUpload { get; set; }
}

SelectList wymaga referencji do System.Web.Mvc
HttpPostedFileBase wymaga referencji do System.Web

1. Czy projekty Contracts oraz Application powinny zawierać wyżej wymienione referencje?

Moim zdaniem nie, tego typu viewmodeli nie wypuszczałbym z warstwy webowej. A DTO, których nie możesz użyć poza aplikacją webową nie są żadnymi kontraktami.
Poza tym, możesz spróbować przecież zrobić kontrakty, w których zamiast HttpPostedFileBase będziesz miał byte[], a zamiast SelectList jakąś klasę z id i nazwą.

2. Kolejne pytanie odnośnie Ninject, którego klasy znajdują się w projekcie WebUI.

kernel.Bind<IRestaurantService>().To<RestaurantService>(); 

wymaga referencji z WebUI do Application, czy ta referencja powinna mieć miejsce?

Nie widzę w tym nic złego, chociaż Ty chyba chciałbyś oddzielić jedno od drugiego przez Contracts.

Jeżeli nie, to jak powinienem poradzić sobie z tym problemem?
Stworzyć oddzielny projekt dla DI?

Generalnie konfigurację kontenera lepiej robić w taki sposób, aby każdy projekt rejestrował znane sobie implementacje. Sensowne kontenery wspierają podział konfiguracji na moduły.

3. Czy aktualna architektura aplikacji jest w porządku?
Czytając sobie inne tematy na forum, natknąłem się na informacje, że w Domain (o ile tak powinien nazywać się projekt zawierający klasy mapowane przez ORM na tabele bazy danych), nie powinno być DbContextu.
Powinienem zatem stworzyć nowy projekt DataAccess i tam wrzucić DbContext?

Klasy mapowane przez ORM i sam kontekst mogą być w jednym projekcie, bo to nic z Domain wspólnego nie ma. Domain to model biznesowy, nie składowania danych.

Czy to rozwiązanie jest w ogóle poprawne, czy zrezygnować z niego i stworzyć oddzielne widoki dla NewRestaurant oraz EditRestaurant?

Nie podoba mi się to, że ViewModel musi cokolwiek wiedzieć o jakimś kontrolerze. ViewModel powinien być głupi, i takie coś może przecież mieć przekazane z kontrolera. Albo można w widoku dopisać logikę wyciągającą nazwę akcji na podstawie URLa, routingu albo czegoś innego (dokładnie nie pamiętam, ale na pewno to siedzi w jakichś metadanych).
Albo też możesz mieć oddzielne widoki, ale ich część wspólną umieścić w jakimś partialu.

A poza tym, i tak za jakiś niedługi czas zrozumiesz, że to bez sensu, bo create od edit zazwyczaj się różnią i potrzebują różnych widoków. ;)

1 użytkowników online, w tym zalogowanych: 0, gości: 1