Best practice ASP.NET Controller for Common Actions - c#

I have a quick question,
In so many examples I saw controller Actions which does not return any View or Partialview are also added in the same controller - Now in my situation i have multiple controllers which i need to run same ACTIONS such as
Controller A will Run Action A
Controller B will run Action A
Adding Action A in both Controller A and B does not look right.
As I am making [HttpPost] calls for Action A using AJAX, therefore, i want this to be in a Controller for easy POST access, although I don't want to add the same Action in both Controllers
I can add action A in Controller A and let Controller B access the same action requesting from Controller A instead but what I was thinking
**How about if I create a new Controller called
commonActionContoller
and put "ACTION A" in it and let everything use commonActionContoller when Action A is required?**
Cheers
EDIT: Example added as following
An example application which has Person and Countries, So Person model is the same for all Countries but we have different Controller for each country so If an Admin wants to update Person's model with field IsEmpoyed from true to false then they go to for example {USA}/Index controller and switch true to false. Now, this is same for {AUS}/Index and {China}/Index so Action which changes IsEmpyed to true/false is the same across all controllers. To make this work i don't want to add Action IsEmplyed to all country controllers - (Couldn't think of a better example) –

You should write Action A in both Controller. Otherwise it will violate Single responsibility principle. Best practice is to move the implementation codes from Controller to a Service layer. For example, if you want to load Product Category for Products and Sub-Categories, then code will be like this:
public interface ICategoryService
{
List<Category> LoadCategory();
}
public class CategoryService : ICategoryService
{
public List<Category> LoadCategory()
{
//code here
}
}
public class ProductController : Controller
{
private readonly ICategoryService _categoryService;
public ProductController()
{
_categoryService = <inject dependency here>;
}
public ActionResult GetCategory()
{
var category = _categoryService.LoadCategory();
}
}
public class SubCategoryController : Controller
{
private readonly ICategoryService _categoryService;
public SubCategoryController()
{
_categoryService = <inject dependency here>;
}
public ActionResult GetCategory()
{
var category = _categoryService.LoadCategory();
}
}

The guiding principle here should be Separation Of Concerns.
If ControllerA and ControllerB have specific business logic, and adding a CommonActions controller give shared data a good isolated home this is a good practice.
Without a better illustration of your needs though it's difficult to answer.
A slightly better example might be the order application:
InventoryController
EmployeeController
You probably don't want a CommomController with methods like:
GetStoreClosingHours(int storeNumber);
GetTotalSales(int employeeId);
GetEmployeeComps(int employeeId);
IoC and dependency injection might pay off as well depending on the actions. Where any controller could call methods like:
GetLastLogonTime(thisEmployee);
It's really a set of principles designing your application after all, and best practices aren't always super neatly packaged. I'd say most importantly choose something flexible, scalable and then stick with it.

Related

Single responsibility principle in MVC

I have a MVC project with following pattern
View <-> Controller <-> Service <-> Repository/Entities <-> Database
For example, if I have 2 tables (Customer and Order) in my Database, then I have 2 classes in my Repository layer (this class map 1:1 with my database table because I'm using EF Code First) :
public class Customer
{
[Key]
public int CustomerID { get; set; }
public int Name { get; set; }
//rest of columns here
}
public class Order
{
[Key]
public int OrderId { get; set; }
//rest of columns here
}
Then I have services :
public class CustomerService : ICustomerService
{
void AddNewCustomer(Customer obj);
void GetCustomerOrders(Customer obj);
//rest of methods here
}
public class OrderService : IOrderService
{
void GetOrderById(int id);
void GetCustomerOrders(Customer obj);
//rest of methods here
}
you probably notice that I have GetCustomerOrders.
My question :
Without breaking Single responsibility principle rule, where do I put GetCustomerOrders? In CustomerService, OrderService, or both?
Did I break the Single responsibility principle rule by having more than one service in my controller? For example :
public class TransactionController : Controller
{
//more than 1 service inside this class
private ICustomerService _customerService;
private IOrderService _orderService;
public ProjectController()
{
this._customerService = new CustomerService();
this._orderService = new OrderService();
}
public ProjectController(CustomerService customerService, OrderService orderService)
{
this._customerService = customerService;
this._orderService = orderService;
}
public ActionResult Index()
{
Return View();
}
public ActionResult CreateCustomer()
{
//rest of code here
}
public ActionResult CreateOrder()
{
//rest of code here
}
}
I have bunch of controller with bloated Action method, for example my ProductController have :
Index
Add
Edit
Delete
Priority
AddPriority
EditPriority
DeletePriority
If the controller were split
ProductController
Index
Add
Edit
Delete
ProductPriorityController
Index
Add
Edit
Delete
I see that the template project from Microsoft doesn't have more than one CRUD operation inside their Controller (towards bottom example). Is it a bad design if I have more than one CRUD operation inside my controller (top example)? I was thinking of splitting my Controller but I don't want it to bite my ass later for having to maintain 50 controllers.
Any help will be appreciated and apologize for bad english.
I will put it in customerService because it depends on the customer you pass to the function.
I think that the maximum services for controller is about ~3/4 services in one controller. So in your case i think this is good.
The controller doesn't need to implement your business logic. They only should take data and post them to the right place. I think you should create a manager / service / class that will handle the business logic. About your CRUD operations, It should be all in one controller (get/post and etc).
1- You don't always need to go through a service to access the repository in the controller.
You can embrace an onion architecture for example where instead a 3 layers architecture. Personally I think important the concept of accessing layers in the right way, but adding a indirection level just to call a repository with no logic inside the service, makes me question the value of the service, because in that case, what is the service that the service is providing?
Since your repository knows the domain, you can return domain objects.
What about commands and queries?
You can read a little bit more and make your one of all this your preference or maybe adapt an idea. Just keep the idea of separation of concerns always in mind, you are on the good way.
About questions 2 and 3 I agree with #Rik, but I will paste his answer just to make my answer complete (credit on him)
2- No, that's fine. In fact, you're are dividing the different responsibilities over separate services, which is very "single responsibility"
3- I'd say keep them separate if they do separate things. Maintaining a number of controllers is easy if you know which controller is responsible for what.
I suggest making a CustomerOrdersController.
No, that's fine. In fact, you are dividing the different responsibilities over separate services, which is very "single responsibility".
I'd say keep them separate if they do separate things. Maintaining a number of controllers is easy if you know which controller is responsible for what.

Proper MVC Repository Instantiation

I apologize if this has been answered in a previous post; I just couldn't find the answer specific to my question.
I was watching a MVC tutorial video and in one of their controllers, they kept instantiating a repository in every method that they needed it for. I'm used to this from previous ASP.NET DAL, but they made this comment:
... I shouldn't be instantiating the repository in every method, I
should be making use of MVC's Services...
I'm curious to know what this means exactly and if instantiating a repository in my controller methods where I need it will be bad practice.
I'm not an expert, but I think you should instantiate your repository only once in the Controller's constructor like this:
public interface ISampleRepository { }
public class SampleRepository : ISampleRepository { }
public class HomeController : Controller
{
private ISampleRepository myRepository;
public HomeController()
{
myRepository = new SampleRepository();
}
}
You don't have to instance your repository in every Action Method. I'm not sure but I think every time you instantiate your repository a new Database Context is created.
So, instantiating the same repository multiple times seems overkilling to me.

Generic Web API controller

I'm using Web API v2 and I have a handful of models that I need to do CRUD operations for. For example, I have an Allergy model and a Prescription model. In the application itself I have viewmodels which can turned into their appropriate models, but for simplicity's sake let's just say I take the model straight in the Web API controller.
So something like this:
public class PrescriptionsController
{
public HttpResponseMessage Put(Prescription model)
{
// saved to the DB
}
... (other CRUD operations)
}
I also have the same for the Allergy model:
public class AllergiesController
{
public HttpResponseMessage Put(Allergy model)
{
// saved to the DB
}
... (other CRUD operations)
}
Both models have different properties but are handled exactly the same way - in fact I have about 3 other models which are handled exactly the same way for each CRUD operation. I hate to do have 5 different endpoints that are basically copied and pasted code.
So my question is this:
Can I make a generic controller to handle all of these models? Something like MyCommonController<T>? (but with a better name of course!) Can the Web API handle the routing in that scenario? Is that even a good idea?
In the end I didn't try a generic controller. It seemed like it might be possible via jumping through some hoops with routing.
However, the fact that routing modifications to get this to work were so complicated it kind of negated the benefit I would get. I wanted to keep things simple. So I just created a generic base class instead:
class MyBaseController<TModel> : ApiController
{
public TModel Get(int id) { ... }
}
and had each type inherit from it:
class PrescriptionsController : MyBaseController<Prescription> { }
And that worked like charm, didn't have to mess with routing or anything. It makes it clear what's happening and is pretty maintainable.

What is the purpose of ASP.NET MVC Generic Controller

I am newbie in asp.net mvc. I heard the word ASP.NET MVC generic controller, can anyone easily explain what it is? I have worked with the default controller before but now I want to able to visualize the kind of purpose ASP.NET MVC generic controller does. It will be very helpful if some one can explain the situations when a developer has to think about using ASP.NET MVC generic controller. Concepts and code about how to implement it will be greatly appreciated. Thanks
You usually create a generic class to abstract away operations you can perform on a range of types, for example Entity Framework models containing an ID. In that case you can move all duplicate code into a base class.
For an MVC controller, a generic base controller may look like this:
public abstract class GenericController<T>
where T : class
{
public virtual ActionResult Details(int id)
{
var model = _repository.Set<T>().Find(id);
return View(model);
}
}
And an implementation like this:
public class FooController : GenericController<Foo>
{
}
Now when someone requests /Foo/Details/42, the entitiy is pulled from the _repository's Set<Foo>(), without having to write anything for that in the FooController.
This way you can create a basic "CRUD" controller that lets you easily extend your application with Create, Read, Update and Delete operations for new models.

MVC 3 Call Controller method directly but also invoke the ActionFilterAttribute?

How would you go about invoking the ActionFilterAttribute when you are calling a controllers method directly? Imagine the following:
public class ApiController : Controller {
public ActionResult CallSomething() {
return IsCalled();
}
[MyAction]
public ActionResult IsCalled() {
return View();
}
}
So the request comes into /Api/CallSomething, the CallSomething() method internally calls another method (in this case IsCalled()) but when that method is called the ActionFilterAttribute is invoked and runs.
At the moment the ActionFilterAttribute will only be invoked if it's part of the original request, which makes sense because then it's part of the whole MVC lifecycle and all I'm doing is just calling a method directly, I'd need to do a RedirectToAction if I wanted it to get fired by MVC. RedirectToAction alters the URL so this isn't suitable for my purposes.
I've poked about the System.Web.Mvc code but I can't see how or when its being invoked. I figure that if it can do it then so can I potentially using reflection. In this event the Views aren't relevant as I am override the ExecuteResult() to write my own content into the http response.
Anyway I've resigned myself to this maybe not being possible but I'd just thought it would be worth a try.
There is no practically correct way to achieve that. So don't attempt to do it. Controller actions shouldn't be calling themselves as in your example. Use a redirect in this case. Or have the client send the request directly to the second action if you don't want the redirect.
Oh and if you have some common functionality between those controller actions that you want to reuse, simply externalize this functionality into some other layer. There are many ways to provide common functionality in ASP.NET MVC 3 depending on the exact scenario.
The simplest way to do what you're talking about is just to factor out the functionality that you want to execute as a filter and ad-hoc. It doesn't make sense to force a filter to execute where it shouldn't be executing. But it might make sense to want to call some part of the filter ad-hoc. The simplest way to do this is with a plain old static method:
public class ApiController : Controller {
public ActionResult CallSomething() {
MyActionFilter.CommonStaticMethodThatIsAlsoUsedInTheNormalFilter();
return IsCalled();
}
[MyActionFilter]
public ActionResult IsCalled() {
return View();
}
}
You should be more specific about what you're trying to achieve, there might be other features of the framework that are a better fit.

Categories