Как сохранить контроллеры в ASP.NET MVC?
У меня довольно хорошо спроектированная архитектура, где контроллеры обращаются к службам, которые обращаются к репозиториям, которые обмениваются данными с базой данных.
Таким образом, логика в контроллерах хранится как минимум, но у меня все еще есть очень тонкие фрагменты кода, которые выполняют некоторые задачи, такие как
- проверить модель
- упорядочить аргументы метода действия
- вызывать некоторую службу с этими аргументами, возможно, проверить результат и вернуть представление, если модель теперь недействительна
- наконец-то создайте модель из результата службы и верните ее.
некоторые более длинные случаи делают разные вещи в зависимости от "статуса", возвращаемого службой.
вот несколько примеров:
[HttpPost]
[AjaxOnly]
[Authorize]
public JsonResult Preview(string input)
{
LinkResult parsed = linkService.ParseUserInput(input);
if (parsed.Result == LinkParseResult.Used)
{
long? postId = parsed.Link.PostId;
if (postId.HasValue)
{
Post post = postService.GetById(postId.Value, false);
return Json(new
{
faulted = "used",
link = DetailsRoute(post),
id = postId
});
}
else
{
return Json(new { faulted = "invalid" });
}
}
else if (parsed.Result == LinkParseResult.Invalid)
{
return Json(new { faulted = "invalid" });
}
else
{
Link link = parsed.Link;
if (link.Description != null && link.Description.Length > 200)
{
link.Description = link.Description.Substring(0, 200);
}
return AjaxView(link);
}
}
и (Post
поступает из домена, PostModel
- модель представления)
private PostModel PostModelConverter(Post post)
{
Link link = post.Link;
if (link == null)
{
throw new ArgumentException("post.Link can't be null");
}
if (link.Type == LinkType.Html)
{
return new PostedLinkModel
{
Description = link.Description,
PictureUrl = link.Picture,
PostId = post.Id,
PostSlug = postService.GetTitleSlug(post),
Timestamp = post.Created,
Title = link.Title,
UserMessage = post.UserMessage,
UserDisplayName = post.User.DisplayName
};
}
else if (link.Type == LinkType.Image)
{
return new PostedImageModel
{
PictureUrl = link.Picture,
PostId = post.Id,
PostSlug = postService.GetTitleSlug(post),
Timestamp = post.Created,
UserMessage = post.UserMessage,
UserDisplayName = post.User.DisplayName
};
}
return null;
}
возникает вопрос о том, действительно ли модели представления должны быть в веб-проекте, или они могут быть частью домена или каким-либо другим проектом.
Я не уверен, что могу много сделать для действия предварительного просмотра, кроме использования PreviewModel, который получает ссылку, и обрезает описание, но это сэкономит, как две строки.
Конвертер модели, вероятно, должен быть где-то в другом месте, но я не знаю, где это должно быть.
Еще один момент, который приходит на ум, - это то, что я должен расщепить этот контроллер либо с помощью ключевого слова partial
(плохо ли использовать его для чего-то другого, чем автогенерируемые классы?), либо добавлять маршруты, которые используют разные контроллеры в зависимости от о том, какое действие запрашивается или какой метод http используется, какой обычный способ справиться с этим?
Ответы
Ответ 1
Это задано несколько раз:
Бизнес-логика в контроллере
Где я должен поставить свою логическую логику контроллера в MVC3
Держать контроллеры тонкими
Также как и в других местах:
ASP MVC Best Practices - Skinny Controllers
Keep Controllers Thin
Сообщество, похоже, хорошо констатирует, что такая логика принадлежит вне контроллеров. Обычно в модели (или ViewModel), но где-то в бизнес-слое.
Как последнее замечание, использование partials
для неавтогенерированного кода не обескураживается. Если имеет смысл разделить вещи, сделайте это. Просто подумайте о том, каковы ваши причины его расщепления. Это будет в каждом отдельном случае.
Ответ 2
private PostModel PostModelConverter(Post post)
{
Link link = post.Link;
if (link == null)
{
throw new ArgumentException("post.Link can't be null");
}
if (link.Type == LinkType.Html)
{
var model = AutoMapper.Map<PostedLinkModel>(post);
model.PostSlug = postService.GetTitleSlug(post);
return model;
}
else if (link.Type == LinkType.Image)
{
var model = AutoMapper.Map<PostedImageModel>(post);
model.PostSlug = postService.GetTitleSlug(post);
return model;
}
return null;
}
http://www.viddler.com/v/b568679c
Ответ 3
Контроллер не будет содержать логики домена
Контроллер должен отвечать только за:
Проверка ввода
Вызов модели для подготовки представления
Вернуть представление или перенаправить на другое действие
Если вы делаете какую-либо другую вещь, вы делаете ее в неправильном месте, это скорее ответственность Модели, которую вы выполняете в контроллере.
Если вы выполните это правило, ваш метод действия не будет содержать более 20 - 25 строк кода. У Яна Купера отличный пост Skinny Controller Fat Model, прочитайте его.