MVC строго типизированный вид и настройки на стороне сервера перед отправкой на нижние уровни?
У меня есть многоуровневое приложение, которое отправляет команды на бизнес-уровень (на самом деле, приложение основано на фреймворке ncqrs, но я не думаю, что это важно здесь).
Команда выглядит так:
public class RegisterUserCommand : CommandBase
{
public string UserName { get; set; }
public string Email{ get; set; }
public DateTime RegistrationDate { get; set; }
public string ApiKey {get; set;} // edit
}
В этом классе нет логики, только данные.
Я хочу, чтобы пользователи вводили свое имя пользователя, адрес электронной почты, и я хочу, чтобы система использовала текущую дату для создания команды.
Что лучше между:
создать строго типизированное представление на основе RegisterUserCommand, а затем ввести дату и ключ APi непосредственно перед отправкой на бизнес-уровень?
создать класс RegisterUserViewModel, создать представление с этим классом и создать объект команды на основе ввода представления?
Я написал следующий код (для решения № 2):
public class RegisterController : Controller
{
//
// GET: /Register/
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(RegisterUserViewModel registrationData)
{
var service = NcqrsEnvironment.Get<ICommandService>();
service.Execute(
new RegisterUserCommand
{
RegistrationDate = DateTime.UtcNow,
Email= registrationData.Email,
UserName= registrationData.Name,
ApiKey = "KeyFromConfigSpecificToCaller" // edit
}
);
return View();
}
public class RegisterUserViewModel
{
[Required]
[StringLength(16)]
public string Name { get; set; }
[Required]
[StringLength(64)]
public string Email{ get; set; }
}
}
Этот код работает... но мне интересно, если я выберу правильный путь...
спасибо за советы
[Edit] Поскольку Datetime, похоже, вызывает недоразумение, я добавил еще одно свойство "ApiKey", которое также должно быть установлено на стороне сервера, из веб-слоя (не из командного уровня)
[Правка 2] попробуйте предложение Эрика и реализуйте первое решение, которое я себе представил:
[HttpPost]
public ActionResult Index(RegisterUserCommand registrationCommand)
{
var service = NcqrsEnvironment.Get<ICommandService>();
registrationCommand.RegistrationDate = DateTime.UtcNow;
registrationCommand.ApiKey = "KeyFromConfigSpecificToCaller";
service.Execute(
registrationCommand
);
return View();
}
... это приемлемо?
3 ответа
Я думаю, что вам будет лучше с вариантом № 2, где у вас будет отдельная ViewModel и команда. Хотя это может показаться избыточным (в некоторой степени), ваши команды на самом деле являются сообщениями от вашего веб-сервера вашему обработчику команд. Эти сообщения не могут быть отформатированы так же, как ваша ViewModel, и не должны. И если вы используете NCQRS как есть, вам придется сопоставить свои команды с вашими методами и конструкторами AR.
Хотя это может сэкономить вам немного времени, я думаю, что вы будете готовы к моделированию своего домена после моделей ViewModels, и это не должно иметь место. Ваши ViewModels должны быть отражением того, что ваш пользователь испытывает и видит; Ваш домен должен отражать ваши бизнес-правила и знания и не всегда отражаться в вашем представлении.
Сейчас это может показаться немного больше работы, но сделайте себе одолжение и держите ваши команды отдельно от ваших моделей представления. Вы поблагодарите себя позже.
Надеюсь, это поможет. Удачи!
Я бы использовал номер 1 и использовал http://msdn.microsoft.com/en-us/library/system.componentmodel.dataannotations.metadatatypeattribute.aspx для проверки.
Я создал пример (ответ) для еще одного вопроса здесь.
Это позволяет вам хранить вашу модель в другой библиотеке, проверять поля и показывать поля, как если бы вы использовали внутренние / частные классы с DataAnnotations. Я не большой поклонник создания совершенно отдельного класса для представления, которое не имеет дополнительной ценности при необходимости возвращать данные в другой класс. (Если бы у вас были дополнительные значения, такие как значения выпадающего списка или значения по умолчанию, я думаю, что это имело бы смысл).
Вместо
[HttpPost]
public ActionResult Index(RegisterUserViewModel registrationData)
{
var service = NcqrsEnvironment.Get<ICommandService>();
service.Execute(
new RegisterUserCommand
{
RegistrationDate = DateTime.UtcNow,
Email= registrationData.Email,
UserName= registrationData.Name,
ApiKey = "KeyFromConfigSpecificToCaller" // edit
}
);
return View();
}
Вы можете иметь
[HttpPost]
public ActionResult Index(RegisterUserCommand registrationData)
{
var service = NcqrsEnvironment.Get<ICommandService>();
registrationData.ApiKey = "KeyFromConfigSpecificToCaller";
service.Execute(registrationData);
return View();
}
Я бы порекомендовал поместить это в конструктор класса RegisterUserCommand. Таким образом, по умолчанию всегда устанавливается значение DateTime.UtcNow, и, если вам нужно явно установить что-либо, вы можете просто добавить его в инициализатор объекта. Это также поможет в тех случаях, когда вы используете этот класс в других частях вашего проекта, и вы забыли явно указать RegistrationDate.
public class RegisterUserCommand : CommandBase
{
public string UserName { get; set; }
public string Email{ get; set; }
public DateTime RegistrationDate { get; set; }
public RegisterUserCommand()
{
RegistrationDate = DateTime.UtcNow;
}
}
И контроллер
public class RegisterController : Controller
{
//
// GET: /Register/
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(RegisterUserViewModel registrationData)
{
var service = NcqrsEnvironment.Get<ICommandService>();
service.Execute(
new RegisterUserCommand
{
Email= registrationData.Email,
OpenIdIdentifier = registrationData.OpenIdIdentifier
}
);
return View();
}
public class RegisterUserViewModel
{
[Required]
[StringLength(16)]
public string Name { get; set; }
[Required]
[StringLength(64)]
public string Email{ get; set; }
}
}