proper way of designing controller for an MVC 4 application - asp.net-mvc

I have a simple model with menu and menuItem which both inherit from an abstract class.
I have created an adminController which can do CRUD operations.
which I've stuck here is that should create controller for menu and menuItem?
because both menu and menuItem are both inherit from a same type.
meanwhile their corresonding views for a method like Edit() can have different appearance.
I mean I have to check in views to know I'm trying to Edit Menu or MenuItem
but if I implement controller for each entity, I have duplicate code.
so what is the best approach for designing controller for this kind of operations?

For what it's worth, controllers are just classes, which means they can be inherited from. So, you can simply do:
public class MenuController : Controller
{
// all the actions here
}
public class MenuItemController : MenuController
{
}
Based on the naming conventions, then, you can apply different views to the actions per controller simply by putting them in their respective view directories: "Menu" and "MenuItem", respectively.
If you need to change a particular action method in the subclassed controller, just make the action virtual in MenuController and then override it in MenuItemController:
public class MenuController : Controller
{
public virtual ActionResult SomeActionToOverride() { ... }
}
public class MenuItemController : MenuController
{
public override ActionResult SomeActionToOverride() { ... }
}
This is all just basic OOP.

The answer, unfortunately, is "It Depends".
You could dispatch to different views based on the object type, from the same Menu controller, with the common operations on the controller, with the views calling the same HttpPost actions with a type-discriminating property. This is a design which exposes the OO architecture to the public API surface.
Or, as these are separate domain entities, you could expose two controllers with their own suite of CRUD operations and have a more REST like API surface.
Duplicate code to provide independent endpoints or security policy differentiation at what amounts to a public API surface is less of a smell than elsewhere.

Related

Multiple BaseControllers with IoC

I read this question, and the answer helps me but not completely. What if I have 20 repositories with different responsibilities, like for example:
ICountryRepository
ICityRepository
and
IUserRepository
IPersonRepository
I can have all the methods of this repositories in the BaseController, but I would prefer something like having a TerritoriesBaseController, whit the ICoutnryRepository and ICityRepository and PersonsBaseController IUserRepository and IPersonRepository, than inherits from BaseController.7
My problem is that, if I have a controller that wants to use the TerritoryBaseController and PersonBaseController, I can't make it inherit from both controllers.
The reason why I want to separate the base controllers, is for structure, order and for not having a controller with 200 methods, but 20 controllers with 10 methods, and with separated responsibilities.
Some ideas how can it be organized?
EDIT:
I think I didn't explain the question properly.
Let's take this example:
I have a project with IoC, and let's say I have 4 repositories.
ICountryRepository, ICityRepository, IUserRepository, IPersonRepository.
I have a controller that needs methods of the 4 repositories, for example, UserController, it will use IUserRepository and IPersonRepository to save the user, and ICountryRepository and ICityRepository to show a list of countries and cities that the user has to select.
I also have a BaseController, where i have the generic methods of the controllers, and UserController inherits of BaseController, so:
UerController : BaseController
What I would like to do is, have a TerritoriesBaseController, where i would have all the methods that are repeated in my controlers of ICouuntrRepository and ICityRepository, like:
public JsonResult GetCountriesSelectList()
{
List<Country> listCountryLanguage = _applicationCountry.GetAll().ToList();
return Json(new SelectList(listCountryLanguage, "IdCountry", "Name"), JsonRequestBehavior.AllowGet);
}
And the same with IPersonRepository and IUserRepository, with a UserBaseController.
But I Can't use:
Usercontroler : BaseController, TerritoriesBaseController, UserBaseController
Because in c# you can only inherit from one class.
How can i reorganize it or what solution can I use?
What if I have 20 repositories with different responsibilities,
If you have a controller that needs to use 20 repositories, there is something wrong with your design. That controller will violate the Single Responsibility Principle.
There are a few solutions to this problem:
Split the logic in the controller up into multiple smaller, more focused controllers that each have just a few dependencies.
Move part of the logic to an aggregate service. In your case your controller probably has a lots of business logic in it. You should extract that business logic to a different class. The command/handler pattern is very suited for implementing business logic.
If you have code that uses multiple repositories, there's a special well-known pattern that for this: the Unit of Work pattern. What you can do is make those repositories accessible as properties on a Unit of Work class and inject only that unit of work.
UPDATE
UserController, it will use IUserRepository and IPersonRepository to
save the user, and ICountryRepository and ICityRepository to show a
list of countries and cities that the user has to select.
In that case you should extract the logic of saving the user into a new class and you should do the same with the logic for getting the list of countries. In that case your UserController will only depend on two more specific dependencies and the code inside the UserController will be minimized.
Don't use base controllers. Using base classes is often a sign of a glitch in your design. Your code becomes much harder to test when using base classes, and those base classes will often grow into god classes. Besides, you already noticed that multiple inheritance is not possible in .NET.
So what you can do is the following:
public class UserController : Controller
{
private ICommandHandler<SaveUser> saveUserHandler;
private IQueryProcessor queryProcessor;
public UserController(ICommandHandler<SaveUser> saveUserHandler,
IQueryProcessor queryProcessor)
{
this.saveUserHandler = saveUserHandler;
this.queryProcessor = queryProcessor;
}
public ActionResult Save(SaveUserViewModel model)
{
this.saveUserHandler.Handle(new SaveUser
{
UserId = model.UserId,
Name = model.UserName,
});
Redirect("/Success");
}
public JsonResult Countries()
{
var listCountryLanguage = queryProcessor.Execute(new GetAllCountries());
return Json(new SelectList(listCountryLanguage, "IdCountry", "Name"),
JsonRequestBehavior.AllowGet);
}
}
Do note that for this example I use the query/handler and command/handler patterns, but that's optional.

ApiController and Controll inherit from same base class

I have multiple controllers and apicontrollers in my project.
How to make both types of controllers inherit a base class, as there is more than some methods, that I need in both?
Composition might be a better option.
Basically instead of inheriting to gain the functionality stick it in a common class, that can be included as a property in both the Api and standard controller.
You can then inject the dependancy into both.
For example:
public class CommonControllerLogic : ICommonControllerLogic
{
public ActionResult SomeSortOfMethod()
{
// etc..
}
}
public class MobileApiController: ApiController
{
public ICommonControllerLogic CommonControllerLogic {get;set;}
// etc..
}
public class HomeController: Controller
{
public ICommonControllerLogic CommonControllerLogic {get;set;}
// etc..
}
Composition is often favoured over inheritence, there are loads of articles on it, just do a quick google search, have a read of this article.
MVC controllers inherit from Controller, whereas API controllers inherit from ApiController. C# does not support multiple inheritance easily. I would recommend moving the shared logic into a static class that both can call. Otherwise you could provide more detail about what is shared; in some cases other design patterns may be more appropriate.

Different controllers for views on the same folder on asp.net MVC4

I've been researching about this. I found "MVCs areas" but I still couldn't do what I'm looking for.
MY VIEWS:
Views/
Student/Course
Student/Information
Student/Status
Student/GeneralSituation
etc, etc...
CONTROLLERS:
Controllers/Student
What I want to do is:
I don't want to have All the code from a lot of views in just one "Student" controller.
Any tip regarding how I can "split" my controllers in several files?
I'm just looking at the simplest approach, I don't want to make big modifications to my project.
I'm using MVC4.
Thanks in advance!..
PnP
Why not just make partial Controller classes and thus split one controller over a bunch of physical files?
Also, what do you mean by "the code from a lot of views"? Are you using a separate service layer and doing the business logic in there, because that's best practice. Controllers are meant to be very lightweight with code along the lines of this:
public ActionMethod DoSomething()
{
StudentViewModel vm = _studentService.GetSomeData();
return View(vm);
}
you can do a partial class StudentController:
your folder/files would look like this:
Controllers
StudentController
StudentController.Status.cs
StudentController.GeneralSituation.cs
StudentController.Course.cs
The code would be:
StudentController.Status.cs:
public partial class StudentController
{
[Actions relevant for Status of a student]
}
StudentController.GeneralSituation.cs:
public partial class StudentController
{
[Actions relevant for General Situation of a student]
}
Any reason why Area's don't work? From what you described, I don't really see why they wouldn't.
- Areas
- Students
- Controllers
HomeController Handles base /Students/ route
InformationController ~/Students/Information/{action}/{id}
StatusController ~/Students/Status/{action}/{id}
...
- Models
- Views
Home/
Information/
Status/
...
Shared/ Stick common views in here
If you're set on one monster controller (or partials), your controller should have very little actual 'View code' in it. Leave all that to view models - the controller just passes in the needed resources to build view data, keeping controllers thin.
Ie,
public class StudentController
{
...
// Actually I prefer to bind the id to a model and handle 404
// checking there, vs pushing that boiler plate code further down
// into the controller, but this is just a quick example.
public ActionResult Information(int id)
{
return View(new InformationPage(this.StudentService, id));
}
}
Then, InformationPage is one of your models that will handle building out all information applicable to that view.
public class InformationPage
{
public Student Student { get; set; }
public InformationPage(StudentService service, int studentId)
{
Student = service.FindStudent(studentId);
... Other view data ...
}
}

How to authorize a set of controllers without placing the annotation on each one?

I have sets of controllers which are each used for each authorization type. For example, a class A authorization will have a set of controllers each which require class A authorization. Is there a way to place one [Authorize(Role="Class A")] attribute somewhere which will apply to each of those controllers without having to decorate each controller with the same attribute?
You can initialize those controllers derived from your base controller. namely put your attribute on a controller base class and to ensure that each controller within derived from base class.
[Authorize(Role="Class A")]
public class CustomBaseController : Controller{}
public class AController: CustomBaseController{}
public class BController: CustomBaseController{}
Yes there is a way, make all those A-class controller derived from one base controller and place on it the AuthorizeAttribute:
[Authorize(Role="Class A")]
public class AController : Controller
{
...
}
public class AFirstController : AController // Gets it's parent attribute
{
...
}
public class ASecondController : AController // Gets it's parent attribute
{
...
}
2 or 3 responses here explained how you can do it... but you can also use Fluent Security to handle all controllers + Actions setup in one file. Some of the benefits (from their website):
Code based configuration
No attributes or xml cluttering up your code.
Low imprint
Fluent Security won't spread like wildfire in your application. Your configuration can be kept in a single file.
You can inherit from a base controller, such as
[Authorize(Role = "Class A")]
public class ClassARequiredController : Controller {}
Otherwise you'd be looking at a global filter, and by your question I assume you have multiple roles and sets so I don't think global filters are for you.
Set the attribute on a Base Class and inherit, creating the hierarchy that best fits your scenario...

ASPNET MVC: Reusing Action Sequences

I'm building a site where I often have to go through the same sequence of steps as part of different operations. In simple terms, part of my data model is hierarchical, and I walk the hierarchy to locate a particular element, after which I do one of several different things (e.g., add a detail record to it, edit it).
Currently I do this by retrieving an object via my data layer which represents a node in the hierarchy, and which contains details about its child nodes. I use this same descriptor class in several different areas of my site.
What I'd like to be able to do is to package the various action methods that comprise walking the tree and selecting a node into a "subroutine" that I could "call" from the various controller classes which need to retrieve a node. But I can't think of a good way to do that within the ASPNET MVC structure. Suggestions?
p.s. one approach was presented here, but I'm interested to see if there are others.
Without seeing any code, what you're describing as "package the various action methods that comprise walking the tree" is simply creating a method. In other words, you shouldn't be looking to invoke the set of action methods that comprise walking the tree but calling the methods that are used by those action methods.
What does means is refactoring the action methods so that the logic is handled in service classes and creating a method that consists of the actions you're interested in.
So you're controllers would look something like this:
public class ControllerA {
public ActionResult DoSomething() {
serviceA.DoSomething();
}
}
public class ControllerB {
public ActionResult DoSomethingElse() {
serviceB.DoSomethingElse();
}
}
You'll define those services with the logic needed and can now create a SharedService class that calls the methods you need.
public class SharedService {
public void DoBoth() {
serviceA.DoSomething();
serviceB.DoSomethingElse();
}
}

Resources