Reputation: 11266
My asp.net MVC app has an area "Company" and an area "Admin".
A company can do CRUD on its users in the company area. I've created a UsersController for this in the Company area. An admin can do CRUD on a company's users in the Admin area. I've created a CompanyUsersControllers for this in the Admin area.
Both controllers have extremely similar code and I was wondering what the cleanest way is to reuse most of the code.
While writing this question, I figured I could create an abstract UsersControllerBase class with virtual ActionResults. I did this and it works for the Company area. I define attributes on the overriding methods in the UsersController class and call the corresponding abstract method in every overriding method.
Here is an example from the base class:
[UsersControllerBase.cs]
public virtual ActionResult Edit(string slug)
{
var user = UserRepository.GetBySlug(slug);
if (user.CompanyId != CurrentUser.CompanyId)
{
throw new SecurityException(CurrentUser.Id + " attempted to edit a user that does not belong to his company");
}
var model = user.ToViewModel();
AddListsTo(model);
return View(model);
}
And the corresponding override:
[Company/UsersController.cs]
[HttpGet, GET("/company/users/{slug}/edit")]
public override ActionResult Edit(string slug)
{
return base.Edit(slug);
}
The problem is that the Edit in Admin/CompanyUsersController.cs has an extra parameter "companySlug" which is used to find the company for which we are currently editing users. As you can see in the code above, in Company/Userscontroller.cs we simply derive the company from the CurrentUser.
What would be the best approach to handle this problem?
td;dr I have 2 controllers with identically named actions that have near-identical method bodies but different parameters. I want to reuse the code as much as possible. pls how do I c#.
Upvotes: 2
Views: 164
Reputation: 11266
It is not worth implementing a basecontroller because the similar methods have different parameters. Even if they would have the same signature, the code is cleaner, more readable, understandable and maintainable when focusing on keeping the controllers as lightweight as possible instead of adding so much complexity to save a few duplicate lines of code.
Upvotes: 0
Reputation: 5751
If the two methods have different signatures, I don't think it's really worth implementing it as a base class method, though it's not impossible. I would create a protected helper method on the base class and put the shared code in that. Like this (making a few assumptions about your Repository API):
[UsersControllerBase.cs]
protected virtual ActionResult Edit(User user)
{
var model = user.ToViewModel();
AddListsTo(model);
return View(model);
}
[Admin/CompanyUsersController.cs]
[HttpGet, GET("/admin/users/{companySlug}/{slug}/edit")]
public ActionResult Edit(string companySlug, string slug)
{
var user = UserRepository.GetBySlug(companySlug, slug);
return base.Edit(user);
}
[Company/UsersController.cs]
[HttpGet, GET("/company/users/{slug}/edit")]
public ActionResult Edit(string slug)
{
var user = UserRepository.GetBySlug(slug);
if (user.CompanyId != CurrentUser.CompanyId)
{
throw new SecurityException(CurrentUser.Id + " attempted to edit a user that does not belong to his company");
}
return base.Edit(user);
}
Upvotes: 3
Reputation: 9155
If the Edit action in the other controller has an extra parameter, then it shouldn't be an override of the base Edit action, in my opinion. I would create a separate Edit action in the derived controller with two parameters, and make the override Edit action return 404.
[HttpGet]
public override ActionResult Edit(string slug)
{
return HttpNotFound();
}
[HttpGet]
public ActionResult Edit(string slug, string companySlug)
{
// some code...
}
Upvotes: 1