I have decided that my controllers are getting a little to cluttered, and decided to adopt a pipeline-style system as I have used in a WebAPI project. The pipeline consists of actions, that get more and more general, i.e: ViewAccountDetailsAction > AccountAction > AuthenticatedAction > EmptyAction. The Actions both add to the pipleline in order of inheritance, and expose members, or abstract methods for different scenarios.
My problem lies in how to return views from pipeline elements. In the WebAPI example, it was as easy as returning an IHttpActionResult which didn't have to perform any view rendering, however, MVC is required to render its responses differently, with the additional step of Razor.
As Controllers expose internal protected helper methods like View() or RedirectToAction, I cant use these outside the controllers themselves.
Is there an elegant way to render these out? I have seen a few ways to do this, each being either cumbersome, or giving me uncomfortable feelings.
My most favoured way at the moment is to make an internal base class hiding the protected methods, and making them internal, whilst calling the base methods. The controller instance will then be provided to the instantiated action. Is there anything overly wrong with this? I can't think of any abusable cases, but wanted to see if there was any community consensus on the matter.
I would recommend taking your approach a step further.
This took a little bit of research, but I based it on an approach I did for a client with Web API 2. Basically the idea was we created a custom ControllerSelector, ActionSelector and ActionDescriptors and a controller base class that exposed a strongly typed business layer. Then through reflection/custom attributes, we marshalled the call to the business layer, handling transformations to an HttpResponseResponse message generically, including errors.
Controller: http://pastebin.com/iK8ieBKD
ControllerSelector: http://pastebin.com/qvEbggrP
ActionSelector: http://pastebin.com/CEFNeKZZ
The first thing you'll need to do is look at:
http://www.dotnet-tricks.com/Tutorial/mvc/LYHK270114-Detailed-ASP.NET-MVC-Pipeline.html
Unfortunately ASP.NET MVC5's pipeline is much less flexible than Web API 2's. However you can do three things:
Custom Controller Factory: https://msdn.microsoft.com/en-us/library/system.web.mvc.icontrollerfactory(v=vs.118).aspx
Custom ControllerDescriptor
Custom ActionInvoker that interprets the ControllerDescriptor: https://msdn.microsoft.com/en-us/library/system.web.mvc.iactioninvoker(v=vs.118).aspx
This way you leave your controller to do what controllers do best, and create a contract for your controller to generically interpret using your new pipeline. This is really the right way to do it.
High jacking/bastardizing the controller as you suggested I don't think is a great plan, this is a much more robust solution, however it would take significant effort. Best of luck!
Related
I'm looking to define an ApiController that has an [Authorize(Role="something")] attribute on it so that by default any methods added to the controller will require the "something" role, but I want to make a couple of the methods on the controller less restrictive than this, but not anonymous. I've tried the following (separately, not all at once):
[Authorize(Role="*")]
[Authorize(Role="Any")]
[Authorize(Role="")]
[Authorize]
[Authorize(Users="*", Roles="")]
But none of these seem to work, still requiring the logged in user to have the more restrictive "something" role. I don't want to change the class level Authorize attribute as that will make methods added in the future prone to not be secured properly.
This is, as far as I know, not possible; I've hit the same issue and agree it's lousy for security. There are a lot of patterns unfortunately in ASP.Net which make it actually quite hard to follow good security practice - all one can do is be vigilant.
You could consider perhaps moving your less-secure method into an entirely different API controller just for the sake of allowing class-wide security declarations of most-restrictive strength at all times.
I would look at the redesign of the controllers if I were you. What you are saying is basically here are some rules which need to be applied to all the methods, but here are some methods which should not have this default behavior. This doesn't sound right at all to me and is prone to errors due to complex rules.
It is normal in such cases to have multiple controllers, each controlled by less and less restrictive behaviours going down to even anonymous access level. An example of an anonymous method would be a Register method, or Request Access method.
Doing it this way makes it clear what kind of rules should be followed for each controller and others don't have to wonder what's going on and try to work out complex rules, by having to look at every single method.
You can still adhere to some sort of design patterns, assuming your API is RESTful for example, you can still stick to that, just have some exceptions along the lines of what I am showing here.
I have an MVC ASP.NET project and I currently use a static ViewModelHelper class which has several methods (1 for each view model) that take in certain parameters and model objects and generate the view model objects for me to return to my views from my controllers. They are currently all static and the class as a whole is stateless, I just use it when I want to instantiate an instance of the view models because some of the data requires rather complex logic.
Would these methods be better off as constructors in the View Model classes? My understanding was it is better not to have any logic in the View Models, but I could be wrong. Or is there perhaps a design pattern I should be using here to help me create these View Models?
It's a question of your project's architecture and design how your ViewModels should look like and where/how they should be initialized. It seems that right now your ViewModels are DTOs and you initialize them with a factory approach. That is fine, but I'd suggest to actually embrace the abstract factory pattern then and make sure that the factory implementation doesn't get overloaded with unrelated responsibilities. That is an inherit problem of "utility" classes that should make every developer wary.
On the other hand, view-related initialization logic, e.g. populating select lists, can very well be located in the ViewModels themselves. In that case you should be wary of duplication.
Another possible approach would be to utilize a builder pattern.
Either way can be a clean solution if you use it exclusively and not mix and match. And as long as you keep it clean, of course. ;)
Without having seen that rather complex logic, I'd suggest you check why the initialization logic is that complex to begin with, though. And if it really has to be. Maybe some business logic snuck in there?
Your ViewModels should be just DTOs, classes with properties only. No logic. Put logic in other classes (services or full business logic, depends) and have them populate the ViewModel.
I'm aware to the fact that this answer seems very short relative to the substantial design consideration, but that's the core of it. For reasoning etc. please have a look at some full-fledge ASP.NET MVC solutions that demonstrate it, like https://prodinner.codeplex.com/.
We have an MVC app that injects our content into a HTML wrapper which supplied by the client.
There are multiple wrappers, such as fund.html, share.html, factsheet.html, and home.html
The wrapper is stored on our webserver. We need to load the wrapper into Site.Master and inject our content into the wrapper's content area, and then render the page.
Basically, I need some advice on how to determine which wrapper to use.
At first, I was thinking that we could map a wrapper to a Controller. So, if we're rendering a View on FundController we could use the wrapper Fund.html, and if it's ShareController, we could use Share.html. In BaseController, which is implemented by both FundController and ShareController I was getting the name of the Controller and using that to load the file, and all was good.
But as requirements changed, it became apparent that this won't work because sometimes we need a controller to render different Views which use different wrappers. So FundController might now have to render Fund.html & Factsheet.html. Now, the Controller doesn't map directly to a wrapper file.
I then thought that I could use the Action name instead of the Controller name to determine the wrapper I should use.. such as public ViewResult Fund() would correspond to Fund.html, and public ViewResult Factsheet() would correspond to Facthseet.html, but this is not ideal because the method that fires in BaseController will fire for all action methods that I execute, including those that return PartialViews and other Action Results, for which I don't want to load wrappers. I only want wrappers for ViewResults.
So, this being the case, I was wondering how best to determine which wrapper to use for which ViewResult I'm executing. One option is using a 'magic string' which, whenever a given Action Method is executing it sets a property in BaseController which can be used to determine the wrapper to use.. but I don't like magic strings. I'd prefer to avoid a hacky approach.
I was also thinking of using an Action Filter which could do the work of loading the wrapper associated with whichever Action Method the filter is associated with. But before doing this, I'd like to get the opinion of other people who may have had to deal with an issue similar to this before. Or if anyone could advise on a better approach to take? What is the best way for me to go about doing this? Thanks.
It sounds like you've already spent a good amount of time thinking about the best way to handle this. Perhaps just combining your existing ideas:
By default, controllers & actions will retrieve their wrappers based on convention. FundController uses the Fund.html wrapper, and ShareController uses the Share.html wrapper.
But also allow for the override of wrappers on a per-action basis, using an ActionFilter.
Barring additional requirements changes (multiple wrappers in multiple content areas within your Masterpage, for exampl), this should cover your needs, no?
I think your Action Filter is one option, or you might want to Extend your very own ViewEngine that is responsible for deciding when to use the wrapper, and when not to.
http://www.singingeels.com/Articles/Creating_a_Custom_View_Engine_in_ASPNET_MVC.aspx
Hope this helps...
I think it might be nice to mimic the rules of views. There is a rule where to look for views, but you can also state the viewname in the action.
The nice thing would be that developers had the same set of rules.
I dont know how you can implement this but I guess its possible.
I usually write use cases for all the software that I develop. For each use case I generally write a controller which directs the flow (implements a use case).
I have recently started developing web apps using Asp.net MVC. One of the best practices of Asp.net MVC is to keep very less logic in the controllers. I am not able to figure out how will I change my design to reflect this.
I basically want a way to encapsulate my use cases.
I think having a fat model and skinny controller is generally a good practice in any language and not specifically .NET MVC. Checkout this nice article that goes through a sample scenario showing the advantages of a fat mode in Ruby on Rails (but the ideas apply to any language).
For representing the use-cases in your code, I think a much better place for them is in test-cases rather than the controller.
Push as much business logic to your models and helper classes as possible, and use controllers mainly for handling URL calls and instantiating the relevant models, retrieving data from them, and pushing data to the views. Views and controllers should have as few decisions to make as possible.
Create a business component to encapsulate use cases. For instance if you have a leave management system you would have use cases like apply for a leave, approve a leave request, reject a leave request, etc. For this you can create a business component (class) called Leave Manager with methods (functions/operations) like "Apply", "Approve", "Reject", etc. These methods will encapsulate your use cases. These methods would take your business entities and data store classes as input and execute the use case.
class LeaveManager{
int Apply(from, to);
bool Approve(leaveApplicationId, approverId);
bool Reject(leaveApplicationId, approverId);
}
You can then use this business component in your controllers to execute the use case by supplying the required parameters.
I have an winforms application that was built using MVC. The controller is subscribing to all of the events from the view (button clicks, etc) and connects multiple views with the model.
The problem is that the controller is now about 3000 lines of (hard to unit test) code.
What is the best practice to avoid getting controllers to do everything and become so big?
One obvious thing to point out might be that one controller does not have to be implemented as one class. The MVC design pattern simply states that M, V and C are separate components, but not that each must be one, and only one, class.
Sub controller
Controller can be split in various sub-controller without broking the MVC pattern.
At 3k lines, it's for sure that the cohesion is broken somewhere. Try to group together same behavior and create new controller. This way, you will have a "main" controller that will invoke "sub" controller.
Method without sub:
For my own experience, I do not have 1 controller for the whole WinForm application. How I created it is that I have mutiple module that are loaded from the menu. When those module are loaded (Form->View) it comes with its own Controller. This way, I only have 1 controller for each module. Those controller aren't over 500 lines of code usually.
Depends on the situation, but assuming you are not at a point where a new controller should be created there are several approaches.
Much depends on your setup. One common approach is to have a service layer or service agent which would do work for the controllers that is not specific. The use of interfaced helpers or even static ones should remove some of the repetition. 300 lines does not sound to bad at all assuming it is broken into testable methods.
I would be interested too to hear of other opinions other than the oft repeated mantra of creating more controllers. We use MVP and have experimented with sub controllers but this does rely on careful usage and is probably a bad idea.
It is common to have one controller per module in MVP, which would relate to a logical part of your application. There should be a few clear ones within your domain and a few that are maybe a bit more difficult to distinguish.