Since making some projects on ASP.NET MVC, i got a question – why generic repositories is widespread, but generic controllers is not.
What is controller? In DDD Architecture it just dispatcher between other subsystems. And in similar scenarios ( like is CRUD ), way of dispatching will be identical. For example: typical Edit Action:
public ActionResult Edit(int id){Entity entity = _repository.Get(id);if (entity == null) return RedirectToAction("ObjectNotFound");if (!_security.CanView(entity, LoggedUser)) return RedirectToAction("ObjectNotFound");return View("Edit", "Personal", mapper.to<ViewModel>( entity ) );}[AcceptVerbs(HttpVerbs.Post)]public ActionResult Edit(ViewModel model){Entity entity = model.EntityId.HasValue ? _repository.Get(model.EntityId.Value) : null;if (entity == null) return RedirectToAction("ObjectNotFound");if (!_security.CanUpdate(entity, LoggedUser)) return RedirectToAction("NotEnoughPermissions");if ( !entity.IsValid )return View("Edit", "Personal", mapper.to<ViewModel>( entity ) );elseusing (ITransaction tr = NHibernateSession.Current.BeginTransaction()){entity = _service.Update(entity, model, LoggedUser);_repository.SaveOrUpdate(entity);tr.Commit();return RedirectToAction("View", new { id = entity.Id, username = LoggedUser.Login });}}
All lines is Generic for most controllers. All that is necessary - extract generic types in base class and specify it in concrete realization. Also we need some constrains:
public abstract class CrudController<TEntity, TRepository, TService, TViewModel> :PersonalPostController<TEntity, TRepository, TService, TViewModel>where TEntity : Entitywhere TRepository : IRepository<TEntity>where TService : IBaseEntityService<TEntity,TViewModel>where TViewModel: EntityViewModel<TEnity> - optional{protected CrudController(TRepository repository, TService service ){_repository = repository;_service = service;}..........public ActionResult Edit(int id){TEntity entity = _repository.Get(id);if (entity == null) return RedirectToAction("ObjectNotFound");if (!_security.CanView(entity, LoggedUser)) return RedirectToAction("ObjectNotFound");return View("Edit", "Personal", mapper.to<TViewModel>( entity ) );}[AcceptVerbs(HttpVerbs.Post)]public ActionResult Edit(TViewModel model){TEntity entity = model.EntityId.HasValue ? _repository.Get(model.EntityId.Value) : null;if (entity == null) return RedirectToAction("ObjectNotFound");if (!_security.CanUpdate(entity, LoggedUser)) return RedirectToAction("NotEnoughPermissions");if ( !entity.IsValid )return View("Edit", "Personal", mapper.to<TViewModel>( entity ) );elseusing (ITransaction tr = NHibernateSession.Current.BeginTransaction()){entity = _service.Update(entity, model, LoggedUser);_repository.SaveOrUpdate(entity);tr.Commit();return RedirectToAction("View", new { id = entity.Id, username = LoggedUser.Login });}}}
For each entity we have just follow:
public class UsersControlles:CrudConrtoller<User, IUserRepository, IUserService, UserViewModel>{public UsersControlles( IUserRepository repository, IUserService service ): base(repository, service){}}
in Next part i plan show how can do some strategies with different types of entities and go deep into TService implementation
Nice article.
ReplyDeleteHowever, you could do with Generic views too, so you should restrict your CRUD to always return to the View "Edit" in "Personal" controller .
Once again, congratulations.