In trying to reduce the size of my MVC controllers, I am refactoring a lot of logic out into services (though this same issue would apply if it was being factored into models). I'm often finding that I was directly setting ViewData
and/or TempData
with information I wanted to be displayed to the user, like:
var repoUser = new UserRepository();
var foundUser = repoUser.GetUser(userId);
if (foundUser == null) {
ViewData["ErrorMessage"] = "Could not find user with ID {0}.".FormatWith(userId);
return View("UsersRegister");
}
Of course, as soon as you move into a service class, you lose direct access to ViewData
, TempData
, and methods like View()
or RedirectToAction()
, so I'm trying to figure out the best practice for dealing with it. Two solutions come to mind:
Create a class containing various pieces of information about what the controller should do, to be passed back from the services, like:
public class ResponseInfo { public string Name { get; set; } public bool DoRedirect { get; set; } public object RedirectRouteValues { get; set; } public string InfoMessage { get; set; } public string ErrorMessage { get; set; } }
Try and allow the service methods to have direct access to things like
ViewData
andTempData
, eg.:public ActionResult ToggleUserAttended(int eventId, int userId, HttpRequestBase request, TempDataDictionary tempData, ViewDataDictionary viewData, Func<string, object, ActionResult> redirectAction) { //... var repoUser = new UserRepository(); var foundUser = repoUser.GetUser(userId); if (foundUser == null) { tempData["ErrorMessage"] = "Could not find user with ID {0}.".FormatWith(userId); return redirectAction("UsersRegister", new { id = eventId, returnUrl = request.QueryString["returnUrl"] }); } //... }
... and then in the controller:
return _svcEvent.ToggleUserAttended(123, 234, Request, TempData, ViewData, (name, routeVals) => RedirectToAction(name, routeVals));
For number 1, the controller would have more logic to do in looking at the ResponseInfo
object and determining whether to redirect, display a view, plugging the error or info message into TempData
or ViewData
, etc. Number 2 would pretty much allow a one-liner controller, but you're making the service very aware of controller-specific stuff. However, the service is always going to be closely tied in with the controller anyway so is this a problem? Would 1 or 2 be best practice, or something else I haven't listed?