We have a series of ASP.NET MVC controllers that all inherit from a single base controller (that inherits from the Controller class). We are now looking at creating some asynchronous actions, and was wondering if we'd run into any trouble if we just changed the base controller to inherit from AsyncController instead of Controller (meaning all of our controllers would inherit from AsyncController).
Jess,
In my opinion, you'll do no harm as the asynch functionality is only called into play when you follow the conventions of:
public class PortalController : AsyncController
{
public void NewsAsync(string city)
{
AsyncManager.OutstandingOperations.Increment();
NewsService newsService = new NewsService();
newsService.GetHeadlinesCompleted += (sender, e) =>
{
AsyncManager.Parameters["headlines"] = e.Value;
AsyncManager.OutstandingOperations.Decrement();
};
newsService.GetHeadlinesAsync(city);
}
public ActionResult NewsCompleted(string[] headlines)
{
return View("News", new ViewStringModel
{
NewsHeadlines = headlines
});
}
}
the convention being the addition of the News*Async* and the News*Completed* portions in the naming.
see:
async controllers in asp.net mvc 2
Observe that the controller class now derives from AsyncController rather than Controller. In addition, the News action method has been split into methods named NewsAsync and NewsCompleted, which are analagous to the Begin and End methods in asynchronous pages. Logically, the controller still exposes a single action method named News. But physically, the method implementation has been broken up using a variation on the async pattern used throughout the .NET framework.
If you don't change anything in your inherited controller code, then no async activty will be initiated. However, as stated by Robert above (or below maybe :-)), you could decorate the actions on a needs must basis to keep the intention clear, tho', i personally think the convention should show that up clearly.
certainly worthy of debate.
MVC 4 doesn't have an asynch controller - see the source:
namespace System.Web.Mvc
{
// Controller now supports asynchronous operations.
// This class only exists
// a) for backwards compat for callers that derive from it,
// b) ActionMethodSelector can detect it to bind to ActionAsync/ActionCompleted patterns.
public abstract class AsyncController : Controller
{
}
}
See my tutorial Using Asynchronous Methods in ASP.NET MVC 4
If you set a breakpoint in your Action method and observe the callstack (with Show External code enabled), you will see that there are several additional steps required to invoke a synchronous action residing in an AsyncController vs. in a standard Controller. Namely the AsyncControllerActionInvoker invokes Begin/End style methods ending with BeginInvokeSynchronousActionMethod. I don't know how much overhead these extra calls contribute, but it is something to be aware of before you blindly extend all your controllers from AsyncController even where no Async actions exist.
You should be fine doing that since AsyncController already inherits from Controller.
See here for more information
The remarks on that page are quite useful for determining whether you're doing the right thing by inheriting from AsyncController and offers a nice guide to keep you on track.
The use of an Async Controller depends on whether you want to wait for any particular task or step to complete before going on to the next task. The problem is akin to buying something from Amazon before the money from your paycheck hits your checking account.
For typical web applications, I would say this is not advisable. The web server is already very parallel, so the only advantage would be speeding up responsiveness to the user. For many operations this benefit would be negligible.
I would reserve the Async Controllers for long-running processes in the background, where it is impractical to wait for the task to complete before returning the web page back to the user's control.
NOTE: If you have a copy of a .NET disassembler (or the ASP.NET MVC source), you can open up the AsyncController class and have a look at the code. That should give you a pretty good idea whether or not you can use the AsyncController as an ordinary Controller.
The article I linked to below says this: "Controllers that derive from AsyncController enable ASP.NET to process asynchronous requests, and they can still service synchronous action methods."
http://msdn.microsoft.com/en-us/library/ee728598.aspx
Related
I have a Controller. "OrderController". Currently it's 1800 lines. I like to reduce the size. I'm using static helper methods which is fine but i'm using ninject to call my repositories so don't have access to the repositories in the static methods without passing the properties in.
What are some good approaches for reducing controller noise?
How to get a Thin Controller
Refactor reusable functionalities that can apply to multiple types of output to ActionFilters. Consequence: Less repetitive code, thinner Controller actions, quicker future development
Refactor reusable functionalities that apply to a specific type of output to a custom ActionResult. Consequence: Less repetitive code, thinner Controller actions, quicker future development
Leverage ModelBinders to bind your input values to complex objects that are injected into your Controller action. Consequence: You don't need to handle the actual HTTP input (RouteData, Form values, querystring parameters) at all in your controller. You can also handle data validation in your model binder.
Implement Dependency Injection via a custom ControllerFactory. Consequence: You don't need to construct services in your Controller.
Refactor single Controllers with an excessive amount of Controller actions into multiple Controllers. Consequences: Your code becomes more maintainable.
Move your static helper methods to static classes. Consequence: Your methods become reusable by multiple controllers and you have less bloated code in the Controller, so it is easier to maintain and make changes to your app.
Other Notes
Plenty of open source resources exist to help accomplish these tasks. I definitely suggest looking into the MvcContrib project. They have a FluentController base class that was designed with building thin Controllers in mind. Also, I upvoted Darin because the video he recommended is helpful, so check it out
No way should there be that much code in your controller. I suspect you haven't separated your concerns.
I would have a look and a think at the answer to this SO question:
ASP.NET MVC Patterns
In short:
Put the complexity into Service classes that perform a clear cut purpose, ie, to deliver what the controller needs.
The controller should just have the application logic, ie, it should just be acting as a kind of air traffic, uhmm, controller, sending requests this way and that based on app logic. That is pretty much its function in a nutshell. Other stuff doesn't belong in a controller.
My controllers look like:
[Authorize(Roles="Admin, Tutor, Pupil")]
public partial class CourseController : Controller
{
ICourseDisplayService service;
public CourseController(ICourseDisplayService service)
{
this.service = service;
}
public virtual ActionResult Browse(int CourseId, string PupilName, string TutorName)
{
service.Initialize(CourseId, 1, PupilName, TutorName, User);
service.CurrentStepOrder = service.ActiveStepIndex;
if (Request.IsAjaxRequest())
{
return PartialView(MVC.Courses.Course.Views._Display, service.ViewModel);
}
else
{
return View(MVC.Courses.Course.Views.Display, service.ViewModel);
}
}
note the service instantiation in the controller's constructor and the calls to service in the actions.
1800 lines!!!!!!!!! Holy mother of God. I would recommend you watching the following video about putting your controllers on a diet.
Those who have read about CQS principle know that:
CQS states that every method should
either be a command that performs an
action, or a query that returns data
to the caller, but not both.
Speaking of ASP.NET MVC Actions, does CQS indicate that we shouldn't have an Action like this?
public PartialView InsertOrder(Order order)
{
OrderService.InsertOrder(order);
return PartialView("OrderDetails", order);
}
This method is changing the state of the system and returning the current state. If CQS is applied here, we should have 2 separate Actions: one for inserting a new order and one for getting the system of the system (which should be called from the client if the first Action was completed successfully). However, this complicates programming.
I'd like to know your opinions on this.
Mosh
A common example of Command/Query Separation on the web is Post/Redirect/Get.
In ASP.NET MVC, this is usually implemented in the simplest way as
[HttpPost]
public ActionResult UpdateOrder(Order order){
UpdateOrder(order);
return RedirectToAction("ViewOrder", new { order.OrderId });
}
[HttpGet]
public ActionResult ViewOrder(int orderId){
return View(GetOrder(orderId));
}
For AJAX, and a partial view, this might not be the best strategy, since the problems that Post/Redirect/Get solves aren't really relevant, and the redirect can be tricky.
CQS is only concerned with command and queries to the same object. Since a OrderView the Order are not the same object (I guess from your implementation) the principle does not apply, so your code is not counter the principle neither in favor :)
I've never heard of CQS, but if you are doing ASP.NET MVC (MVC pattern) the action you wrote is perfectly fine (assuming this OrderService there is an abstraction to the real service). The controller manipulates the model and decides which view to render and passes this model to the view.
I had a vague recollection of this term from the eiffel days (which if followed all the way back, actually predates most current oop principles by a good decade or so (late 80's i think). I'd suggest that this term and/or principle may well be outmoded now and superceded by actionresults in mvc (be that asp or codeignitor etc, etc). I actually think that in terms of the definition (which i just looked up now), this separation is concerned with the logic that performs the action i.e. OrderService.InsertOrder(order) in your example. So, in a way, mvc as performed in your action is actually loosley following this pattern (InsertOrder doesn't attempt to present any stateful info, purely process the order object).
I'd suggest that you look at best practice for asp.net mvc which is fundementally based on returning an actionresult (or partial, contentresult etc, etc). this pattern was designed to simplify the paradigm to facilitate productivity in a uniform and universally accepted fashion.
of course, you could use your action return values to generate a success or fail for the insert/update/delete scenarios and then request partial views based on those return value. However, i personally don't think i'd leverage too much value from that approach bearing in mind the fact that the controller in MVC is concerned with stearing the logic of which view should be returned as the result of an action.
hope this helps
jim
Is it possible in ASP.NET MVC via some extension/override points to allow a "delegate field" to be used as an "action"?
Something like:
using System;
using System.Web.Mvc;
namespace Company.Web.Controllers
{
public class SwitchboardController : BaseController
{
public Func<ActionResult> Index, Admin, Data, Reports;
public SwitchboardController()
{
// Generic views
Index = Admin = Data = Reports =
() => View();
}
}
}
I know I'm a little hell-bent for this one but if this is possible it'd open up many new ways of making actions. You could, for example, have Django-style generic views in MVC with only a single line of code to define the action or have different ways to factor duplicate logic across multiple controllers.
I'm not quiet sure where would be the place to slap this logic into or how much work would be required to alter something so fundamental in the framework.
You will probably have to build your own Controller factory. This class builds controllers, and implements IControllerFactory. You can inherit from DefaultControllerFactory. Override CreateController() to return your own IController.
Register your controller factory in Application_Start() of MvcApplication using this line:
ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory));
In your implementation of IController, override the Execute method. You can use the RequestContext to decide which delegate to invoke. It would probably be easiest to inherit from ControllerBase, and override Execute in there if you don't want to fully implement IController.
The RequestContext passed into Execute carries a RouteData object. This is a dictionary populated by the routing engine that tells you what action should be invoked, and any parameters. You can get the action name like this:
//context is a RequestContext object passed to IController.Execute()
string actionName = requestContext.RouteData.Values["action"];
You could even define your action as a dictionary, and just pull them out once you get the action name.
One last thing, normal action methods return an ActionResult, which the framework uses to decide which view to render. Once you execute your delegates, I think you'll have to set some stuff manually in your special base controller. I'm not exactly sure what to set or how to get your View executed from here without cracking open the MVC source.
Good luck! This looks like an interesting idea.
As you seem to be implementing a BaseController in your code sample, if you override the Execute (from the IController) you'll be able to interpret the request => action however you like.
No, it isn't. The base controller is looking for methods and not for fields to dispatch an action.
EDIT:
Sorry, I was a bit fast and fixed to the standard classes provided.
You can do that but you have to overwrite the Execute Method in your controller or implement and provide your own IActionInvoker to dispatch the action to fields. Look into the post action processing in detail. It explains the dispatching in detail.
I think I'm beginning to be confused with the job of a controller in MVC.
I have a service that exposes five functions:
list packages in queue
get package
delete package
accept package
deny package
My ASP.NET MVC controller depends on this service, and can generally execute a service call on an Action. I'm happy so far.
The second part is then building the ViewModel result. If I do this inside of the controller, the controller now has an exploding dependency list -- each action added increases the dependencies in order to build the view model, and these are all inherited by the controller. I don't like this very much. I'm building this controller that depends on N different view model builders, but only using one of them per request.
So I was thinking of pulling all of this out and applying action filters specific to each view model. I haven't done this yet, but it seems okay.
The question this is raising for me is: what is the responsibility of the controller? If I end up pulling the view model building into filters, my controller is doing little more than having a route execute a service call (and providing a filter plugin). If I instead leave my controller responsible for building each view model, it becomes a mess.
It seems like I almost want to instantiate an action per request, not a controller, and I'm just abusing filters to get at that?
Do you have dedicated ViewModels and Poco-Models? If this is the case you can handle the data from the services inside the ViewModel.
I am quite happy with this uproach.
public class PackageViewModel()
{
public PackageDetail{get;set;}
public int PackageID{get;set;}
public List<Package>Packages{get;set;}
public string SomeFilterCriteria{get;set;}
publlic void FillPackageList(IPackageService packageService)
{
Packages = packageService.GetPackages(SomeFilterCriteria);
}
}
In Controller:
public ViewResult ListPackages(PackageViewModel model)
{
model.FillPackageList(PackageService);
return View("ListPackages",model);
}
I dont understand what you mean by "view model builders".
The controller is supposed to orchestrate all actions you want to occur in your view. If you pull this logic out into action filters, it's still doing the logic per route request, it's just going to be cleaner in your case.
We know that behind the scenes, the ASP.NET MVC framework will use reflection to determine what controllers/actions are available to be executed, based on which classes derive from System.Web.Mvc.Controller and, of those classes, which methods return an ActionResult object.
To my question - is it possible to access this list of controllers/actions from within my MVC application?
(I could do it myself, by using reflection on the current assembly, but if the list has already been built by ASP.NET MVC, I'd rather re-use that effort than re-invent the wheel myself.)
new ReflectedControllerDescriptor(typeof(TController)).GetCanonicalActions() will return a collection of ActionDescriptor objects showing all the actions on the controller. It's not smart enough to understand things like selection attributes or naming attributes, so not every action it returns is guaranteed to be web-callable. But if you need to execute the actions directly, you can call ActionDescriptor.Execute() on any action of interest to you.
This is done in an internal class in the System.Web.Mvc assembly called System.Web.Mvc.ControllerTypeCache.
By the way, action methods are not required to return ActionResult. They can return void happily, for instance.