I've got some things I do in the OnActionExecuting method in a BaseController, that all my other controllers are based off of.
I'm doing some simple things like putting a variable into ViewData that "nearly" all of my views will need, and populating a couple properties that my controllers use.
Thing that bugs me is, this work is being done even on actions that don't need it. Is there a better place to hook into to more efficiently perform this work? In case I ever need to something a little "heavier" than what I do now (i.e. DB access, etc...).
UPDATE: I'm more specifically referring to a typical controller scenario. Where there are several actions that simply show a view. And a few that take a form submission, do some work, and redirect to another action.
In this case, I want the actions that show views to use the work that is done in the OnActionExecuting method. But the actions that accept form submissions, the work being done in OnActionExecuting is not being used and therefor just adds unnecessary processing time.
Maybe I'm not explaining it very well... hope it's clearer now.
TIA!
If it's easier to blacklist actions (by attributing actions for which this logic shouldn't be performed) than whitelisting actions, you could create a [SuppressWhateverLogic] attribute and apply it to the methods you want to be blacklisted. Then modify your OnActionExecuting() method to look for this attribute (via ActionExecutingContext.ActionDescriptor.IsDefined()), and if the attribute exists then bail out of the logic.
If it's easier to whitelist actions, move the logic out of Controller.OnActionExecuting() and create a custom [MyLogic] filter by subclassing ActionFilterAttribute. Add the logic to MyLogicAttribute.OnActionExecuting(), then attribute the methods you want with [MyLogic] to associate the logic with those methods.
Create a second "AdvancedBaseController" which derives from BaseController?
Related
I got a webapi Authorize filter which does some security checks on the queryString for "Get" calls.
For post methods, since I need to peek at the payload to retrieve the object (moreover, that would make my filter dependent upon my dtos, which I'm not a huge fan either...), and since I didn't find an easy way to open the post payload in the filter, I ended the subject by making the check in a controller method.
Obviously, the logic is the same in both cases.
So I put the validation logic in an abstract controller and make it "public static" so they can be called from the filter and from all inheriting controllers. I've read the google results from the follwoing query (avoiding calling static methods), and truth be told, I also find this ugly and untestable.
But what would be an elegant alternative ?
I've considered creating a (static ?) helper class but I only find it's syntactic sugar around the same concept.
I also think that helpers should not be IOc'ed maybe I'm wrong here ?
Thanks for your input !
You should include the details of validations that you wanna do on the query string to help us understand the problem in more details. However based on the information provided I have following to say.
Creating a static method in Controllers and accessing it in Filters is more ugly than exposing DTOs to Authorize Filter. The controllers acts as service layer and Filters are (to some extent) part of it(service layer) too. So there is nothing wrong if you have to expose DTOs to Filters. It can simply be seen as "DTOs being exposed to service layer".
However, if you really wish to avoid it, put an abstraction as part of your service layers which can be exposed to the Filters. Like you can create a interface (and its implementations) that exposes a validation method for your purpose that can be consumed from within the Authorize Filter.
I am going to be purchasing an MVC theme from WrapBootstrap https://wrapbootstrap.com/theme/inspinia-responsive-admin-theme-WB0R5L90S for a personal project.
There are alot of things that I like about it design wise, but it has brought up a question about the best way to load notifications in the header (really any sort of dynamic data that needs to load into the common Layout view).
I know there are a great number of ways to do this, but I am at the point in my development experience where I am trying to break my bad design habits (hacking things together so they "just work"), and look for elegant solutions where I can.
The things that make the most sense so far is to either:
1) Create a global ActionFilter that will filter all requests and throw a "LayoutViewModel" into the ViewBag, and just use the ViewBag in the _Layout view.
I'd rather do something strongly typed, but I don't see a way.
This is nice because it is available, does not require my controllers to inherit any functionality from a base class that might be cludgy, or even know that it is happening.
2) Load the page and onLoad, just do an Ajax Calls to the server to load any dynamic data I need.
This may have some disadvantages if your layout needs to change based on the data. I dislike with things snap all over the page after loading.
Is there a design pattern or MVC feature that I may be missing top accomplish this?
I may in the future I may implement something liks SignalR(or a simple timed ajax call to look for updates) to get updated data/notifications, but for now I am just looking at the initial page load.
Thank you for any ideas that you may have.
Most likely, what you're looking for is a child action. These are pretty much just like normal actions, except they'll return partial views and generally are decorated with [ChildActionOnly] to prevent routing to them via the URL bar.
[ChildActionOnly]
public ActionResult Notifications()
{
var notifications = // get the notifications;
return PartialView("_Notifications", notifications);
}
Then, in your layout, you just add the following where you want it to appear:
#Html.Action("Notifications", "Foo")
Where "Foo" is the name of the controller you put this child action in. I have a post on my blog that gives a primer on the Razor templating system that may be of use to you as well.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 8 years ago.
Improve this question
I'm developing an app and I am pondering over something. So I figured I would ask here for people with experience to tell me what they think about it.
So I have this controller (Store controller) which is huge and has a lots of methods, Get and Post actions, and so on in it. It works fine, but I'm still in development stage.
I am wondering what would be the best practice: to have this controller which holds so many methods and actions, or splitting the methods to many controllers? Is it ideal to have one controller deal with almost all of the methods, or many controllers?
And before you ask, yes, everything in my store controller is "store related". But in my store I have items, packages, and so on.
Edit
Thanks everyone! Following your advice, I have broken my huge Store controller into smaller controllers: one for the Items, one for the Packs, and so on. This indeed made the code more readable. Also, a lot of comments provided will put me on track for upgrade, so thanks a lot!
It is definitely better to divide all your controller's actions into some logical packages - so to move them to separate controllers. Thanks to this it all becomes much more readable and intuitive for you also for other developers who will work on the project.
The question is: how to divide it?
There are in fact a few criterias that can influence such a decision for e.g.:
A controller should be connected with a certain set of logically connected pages. So for e.g. in case of an e-commerce platform you would probably have a CheckoutController, ProductController, UserAccountController etc.
You should also take into account which business concepts should be taken into account. In your case you have a concept Store, but as you are probably aware of this that it is a very broad concept in itself. So instead you should probably distinguish some more details in the business concepts.
A quite common approach is to divide controllers by CRUDs, although it is not always applicable.
On the other hand your controllers should not be too granulated - so you should not exaggerate with it.
Please remember that ASP.NET MVC uses CoC (Convention over Configuration) approach which is also applicable to controllers and views naming conventions and the way they are grouped and placed in appropriate directories. When dividing your controller you should take this into account.
You should have a controller per discrete unit you're working with. So, if your controller manages multiple entities, then yes, I'd say it's time to break it out. However, length of the controller, otherwise, makes no difference.
Now, the only problem you'll have using separate controllers is your routes, but that can be easily fixed by either of the following:
Use Areas. Areas allow you to sort of create a sub-MVC project. It'll give you Controller, Model, and View directories all under a new prefix. So, if you had a controller named ItemsController in your Store Area, the default route would end up being Store/Items. However, C# developers have very mixed feelings regarding Areas: some love them, some hate them with a burning passion.
Use Attribute Routing. MVC 5 has a new feature called attribute routing. This allows you to specify the route directly on your controller and its actions instead of relying on the default route or adding tons of custom routes to your route config. So, you could then easily have as many controllers as you want and specify that they should all be prefixed with "store" in the URL. As long as there's no conflict in the rest of the URL, you'll be fine. If you aren't working with an MVC 5 project and don't want to upgrade, there's also a Nuget package called AttributeRouting that offers these features (and actually more). For what it's worth, the author of that package is also the author of attribute routing in MVC 5.
I prefer multiple controllers than a single controller with many actions. I would do it this way - Let a BaseStoreController derive from Controller, this controller is going to have the common functionality and properties. Then have StorePackageController, StoreItemsController etc be derived from BaseStoreController.
And inside each controller I will have corresponding Actions related to packages, items etc. Inside each action I will make sure I will use Command Pattern and Facade pattern to ensure proper code separation.
The standard way I approach it is to have one controller per menu option
For example, say you have a site with the menu options
Home, Products, Blog, FAQ etc
I would have a HomeController, ProductContsController, BlogController and FAQController
You could also potentially create one or two generic controllers that handle shared actions used by several sections of your website and a base controller than handles generic tasks such as tracking and logging page visits.
One other thing to be aware of is SSL, especially if you decide to do some shared controllers actions or decorate an entire controller (For example shoppingcart etc) with SSL
If your methods are truly "Store" related and bind your model to the View, then that's one thing. But if some of your "Store" methods are essentially helper classes, that is, methods that don't directly interact with your view but do serve a purpose when working with your Store model, then create a separate "Store" helper class and place this in, for example, a "HelperClasses" folder in your root. In my opinion, and I'm sure opinions of others, you want to try to only keep methods in your controller that directly tie into the model (the Store model) that your View renders and works with. This encourages "separation of concerns". If your Store methods don't do that, send them to a helper class. Basically - your controller acts as the middle man when rendering your model to the view. It helps control the process, so every method in your Store controller should really have something to do with how your controller sends your model to the View. Hope that makes sense.
And as Chris Pratt mentioned, if your controller manages multiple objects, then yes separate them into separate controllers, OR, create a ViewModel to handle the multiple objects, but from what you said, I don't think this is the case because you mentioned everything in your Store controller is "Store" related.
you might consider using a partial controller and split methods by logical meanings.
public partial class StoreController: Controller
{
public ActionResult Index()
{
return View();
}
}
in in some other .cs or .vb file:
public partial class StoreController
{
public ActionResult Show()
{
return View();
}
}
take a look at: http://msdn.microsoft.com/en-us/library/wa80x488.aspx
I am working with a c# MVC website that has been developed over the course of several months by different people. The site is quite big and uses the .NET membership facilities regulate user access to various features.
I have now been tasked with a security audit, to list what users or roles have access to which features. I can do this by hand, but given the large number of controllers and their actions, it would be easier if I could do this with code. I am at a loss on how to even begin.
So, in short, how do I get a list of all the controllers on a site, their actions, and determine which, if any, users/roles have access to them?
You can use a little reflection to get controller methods. You can get your controllers:
var controllers = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsSubclassOf(Controller));
where Controller is the standard base class; if you've got your own custom base controller you can use that instead. This assumes you're running this code within the app; if that's not the case then replace Assembly.GetExecutingAssembly() with the appropriate logic to find your app's assembly. Assembly.GetExecutingAssembly() is easier, so I'd say to just add a function to do this somewhere in your admin-only area, if there is such a thing.
That line above will give you an array of System.Type objects for your controllers. From there, foreach (var TController in controllers) through them and get their methods:
var actions = new ReflectedControllerDescriptor(typeof(TController)).GetCanonicalActions();
This gets you an array of ActionDescriptor objects, from which you can use GetFilterAttributes() and GetCustomAttributes() to see what attributes are on that method - you're mostly looking for AuthorizeAttribute, AllowAnonymousAttribute, and your custom auth stuff. The ReflectedControllerDescriptor has these methods as well, for attributes applied to the entire controller instead of per-method.
Once you know which auth-related attributes are set, you can inspect the properties of those methods to see what they're set to. For example, AuthorizeAttribute exposes a Roles property, so for a method marked [Authorise("admin", "superuser")] you'll get a string containing those terms, so with a little logic you can split it up into the individual role names and use those for grouping/sorting/whatever. For any custom attributes... well, that depends on how you've implemented them, but if they don't expose what you need you can always edit them so they do.
If your methods use something like User.IsInRole internally... well, I'm not sure there's a way to find that programmatically. You might be stuck using Call Hierarchy view or Find All References to see where that sort of method is being accessed, so you can sift through manually.
Meanwhile, as part of this audit it's probably worth logging what's actually being accessed, if you don't already. In my projects, I tend to implement an action filter inheriting from ActionFilterAttribute, using some logic that inspects the attributes as described above, and using the ActionDescriptor and HttpContext.User that get passed in as part of the filter context to record what action is being accessed and who's accessing it.
I writing an MVC app and I'm really struggling to keep my controllers lean and limit the number of actions.
For example, here is a look at my ReportController actions:
OpenCall
ClosedCall
ServiceLevelAgreement
Barrier
Resolution
Repair
Failure
Inventory
CustomerLocation
These are all my different reports. Should I be making a controller for each one?
Here is a look at my ServiceCallController actions:
New
Create
Reopen
UpdateETA
UpdateOnsite
UpdateServiceTimes
UpdateEnroute
Close
Cancel
Reassign
Show
ModifyAfterClose
This are all different actions I need to take based on what the user wants to do. Can anyone help me out here with how to clean this up?
I think it's clean already. If an object of yours is capable of doing 7-8 actions, then your structure is the way to go. If you had one controller that is responsible for the actions of multiple business objects, then I'd have suggested you change it into the way your current design is in.
One thing though about your current design, it'd be a good idea to just have one update action on ServiceCallController and that action could take what to update as a parameter. After all, all those update actions do one thing : update your business object.
But if you are still not satisfied, then you can just have one action that's named "do" which takes the action as parameter and passes that to a service layer which returns what the request wanted. But IMO, that wouldn't be a good design, so I definitely don't suggest it.
If the file it self is getting to large to work with you could either use partial classes, Or back the logic off in to a separate class and leave your controller think and lean.