Chciałbym powiedzieć, że ponownie używasz terminu ViewModel dla obu kierunków interakcji z klientem. Jeśli przeczytałeś wystarczająco dużo kodu ASP.NET MVC w środowisku naturalnym, prawdopodobnie zauważyłeś różnicę między ViewModel i EditModel. Myślę, że to ważne.
ViewModel reprezentuje wszystkie informacje wymagane do renderowania widoku. Może to obejmować dane renderowane w statycznych, nieinteraktywnych miejscach, a także dane wyłącznie w celu sprawdzenia, aby zdecydować, co dokładnie renderować. Akcja GET kontrolera jest ogólnie odpowiedzialna za pakowanie ViewModel dla jego widoku.
EditModel (lub może ActionModel) reprezentuje dane wymagane do wykonania akcji, którą użytkownik chciał wykonać dla tego testu POST. Więc EditModel naprawdę próbuje opisać akcję. To prawdopodobnie wykluczy niektóre dane z ViewModel i chociaż są powiązane, myślę, że ważne jest, aby zdać sobie sprawę, że rzeczywiście są różne.
Jeden pomysł
To powiedziawszy, możesz bardzo łatwo mieć konfigurację AutoMapper do przejścia z Model -> ViewModel i inną, aby przejść z EditModel -> Model. Następnie różne akcje kontrolera muszą po prostu używać AutoMapper. Do diabła, EditModel może mieć na sobie funkcje do walidacji jego właściwości względem modelu i zastosowania tych wartości do samego modelu. Nie robi nic innego i masz ModelBinders w MVC, aby mimo wszystko zamapować żądanie na EditModel.
Inny pomysł
Poza tym ostatnio zastanawiałem się nad tym, co działa na podstawie idei ActionModelu, ponieważ klient wysyła do Ciebie z powrotem opis kilku działań, które wykonał użytkownik, a nie tylko jedna duża porcja danych. Z pewnością wymagałoby to trochę Javascript po stronie klienta, ale myślę, że pomysł jest intrygujący.
Zasadniczo, gdy użytkownik wykonuje akcje na wyświetlonym ekranie, Javascript zaczyna tworzyć listę obiektów akcji. Przykładem może być to, że użytkownik jest na ekranie informacji o pracowniku. Aktualizują nazwisko i dodają nowy adres, ponieważ pracownik był niedawno żonaty. Pod osłonami daje to ChangeEmployeeName
a iAddEmployeeMailingAddress
obiekty do listy. Użytkownik klika „Zapisz”, aby zatwierdzić zmiany, a Ty przesyłasz listę dwóch obiektów, z których każdy zawiera tylko informacje potrzebne do wykonania każdej akcji.
Potrzebowałbyś bardziej inteligentnego ModelBinder niż domyślny, ale dobry serializator JSON powinien być w stanie zająć się mapowaniem obiektów akcji po stronie klienta na obiekty po stronie serwera. Te po stronie serwera (jeśli jesteś w środowisku dwuwarstwowym) mogą łatwo mieć metody, które zakończyłyby akcję na modelu, z którym pracują. Tak więc akcja kontrolera kończy się po prostu uzyskaniem identyfikatora instancji Model do ściągnięcia i listy działań do wykonania na niej. Albo akcje mają w sobie identyfikator, który je bardzo rozdziela.
Więc może coś takiego zostanie zrealizowane po stronie serwera:
public interface IUserAction<TModel>
{
long ModelId { get; set; }
IEnumerable<string> Validate(TModel model);
void Complete(TModel model);
}
[Transaction]
public ActionResult Save(IEnumerable<IUserAction<Employee>> actions)
{
var errors = new List<string>();
foreach( var action in actions )
{
var employee = _employeeRepository.Get(action.ModelId);
errors.AddRange(action.Validate(employee));
}
foreach( var action in editModel.UserActions )
{
var employee = _employeeRepository.Get(action.ModelId);
action.Complete(employee);
_employeeRepository.Update(employee);
}
}
To naprawdę sprawia, że akcja wysyłania zwrotnego jest dość ogólna, ponieważ opierasz się na swoim ModelBinder, aby uzyskać poprawną instancję IUserAction i instancję IUserAction w celu wykonania prawidłowej logiki lub (bardziej prawdopodobne) wywołania modelu z informacjami.
Jeśli pracujesz w środowisku 3-warstwowym, IUserAction może być po prostu prostym DTO do wykonania przez granicę i wykonania w podobnej metodzie w warstwie aplikacji. W zależności od tego, jak zrobisz tę warstwę, można ją bardzo łatwo podzielić i nadal pozostać w transakcji (przychodzi na myśl żądanie / odpowiedź Agathy i wykorzystanie mapy tożsamości DI i NHibernate).
W każdym razie jestem pewien, że nie jest to doskonały pomysł, wymagałoby to trochę JS po stronie klienta do zarządzania, a nie byłem jeszcze w stanie zrobić projektu, aby zobaczyć, jak się rozwija, ale post próbował pomyśleć o tym, jak dostać się tam iz powrotem, więc pomyślałem, że przedstawię swoje myśli. Mam nadzieję, że to pomoże i chciałbym usłyszeć o innych sposobach zarządzania interakcjami.