ASP.NET Core Nested / Tiered Controllers - asp.net-mvc

Hi there fellow Overflowing Stackers! Looking for your help in regards to having tiered or nested controllers in asp.net core
So far from what I can see, the default boilerplate code, and its default route {controller=Home}/{action=Index}/{id?} only allows for controllers to be in the default Controllers directory, which doesn't allow nesting at all.
From what I have seen thus far there are a few ways to get around this, neither which are ideal in my opinion.
Razor View Pages
Out of the box, it would appear that Razor Pages, automatically circumvent this issue as the .net core automatically attempts to traverse the corresponding folder structure from the associated URL structure to attempt to find a .cshtml file that matches the route.
The problem? This is more of an MVVM pattern than an MVC one. Which is the lesser of the 3 evils, in my opinion, (Open to debate ofc)
Route Attributes
The other alternative I see is that controllers can be associated with routes using the Route Attribute on Controllers and Actions [Route("parent/route/path")]
The problem? Same namespace (folder) means no reuse of Controller names and given the nature of our app, we need to namespace our Controllers. Not to mention that it's going to make the Controller Folder Massive, with 100's of Controller Files.
Adding More Routes
Adding more routes manually is going to be painful, as I have to add a new route for every possible permutation of parent and child within the folder structure.
Whilst I understand that this may be the intended way of doing things. Adding every possible nested folder in a new route is bad design in my opinion. As this is something that can automatically be inferred from the route to the folder structure. And is automatically done in other Languages and Frameworks automatically. (One excellent example C# Class Libraries)
Salt in the Wound
Most importantly it is apparently not possible to have the same named controller in two completely separate folders / routes:
How to use same controller name in different namespaces. When this happens you get greeted with an Exception AmbiguousActionException: Multiple actions matched.
The biggest pain point for me is that Namespaces are supported within the normal version of the .NET MVC Framework. For some wonderful reason, the namespace parameter has been removed from the MapRoute() method by someone at Microsoft. Scratching my head as to why that was done?
Not 'Just' a Rant
Before I continue, this post is not me whining or ranting, I am genuinely looking for a better solution and am looking for other ideas and alternatives. Please keep reading for my ideal solution below.
Ideal Solution
Since I have come from a PHP background I have found that simply using the default spl_register_autoloader() gave me exactly what I wanted. The capacity for me to register a specific namespace of my choosing and for PHP to look at any and all parts of the subsequent namespace in the local directory folder structure for the Controller I wanted.
i.e. the PHP controller Controllers\NestingLevel1\NestingLevel2\HomeController would look for the associated controller in Controllers\NestingLevel1\NestingLevel2\HomeController.php
Simple, Beautiful and Did I mention Simple?
Wrap Up
Is there any way I can get Nested Controllers in ASP.NET core without:
Razor View Pages (MVVM)
Route Attributes on Every Single Nested Controller
Manually Adding Routes for Every Possible Nested Parent / Child Combination

Related

Battle-hardened strategy for naming files and folders in asp.net mvc projects

In French, a "donkey bridge" is some apparent difficulty in a subject to be learnt that throws off newcomers - the donkeys. The expression is used with patronizing assurance by educators who know the difficulty is apparent, not real, and the donkeys just have to cross the bridge.
Well I'm the donkey, and I'm having real trouble settling down with the folder structure and "virtual" urls of asp.net mvc projects. Urls are now a blend of pseudo-path information, encoded in routes, and arguments, that resolve to controller classes that, being classes, have no notion of their directory. So, it seems, there is no simple way of using relative paths/urls to reference static resources associated with a dynamic page: script file, stylesheet, razor view, images. .Net helpfully gives me default search locations for views, and default folders for "Content", "Scripts", "Images". I get the feeling they want me to file things by type. But this obliges me to invent file and subfolder names in each of these locations, then to hardcode the resulting paths in the controller and the view. Since a given controller generally has only a handful of tightly coupled views, and 99.9% of views have 1 script file and 1 stylesheet, all this name invention, and categorization by type, introduces needless brittleness and complexity, and masks any expression of what the project actually does.
Is anyone else fighting this? Is their a tried-and-tested strategy for naming in large mvc projects that
Expresses what the project does at the top level of the folder structure (or any level of the folder structure!).
Provides a default location or generated names for .cshtml, .js and .css, such that I don't need to search through code to find the names of associated resources.
Preserves the flexibility and decoupling of naming/indirection where this has proved useful.
I'm aware of areas as a way subdividing an mvc project into functional groupings, but this just seems to recreate the problem inside each area. I've looked at this method for customizing the search location for views, but there's no dynamic element. I've implemented a view engine to have fine-grained run-time control over the view path, which is fine if you're brave but I'm still unsure how best to use it, and I'm put off by the potential caching issues. For all the dissing of opinions, I'm particularly interested in answers addressing what I should do.
Thanks to all the downvoters, intolerant village folk. The donkeys that refused to cross the bridge are right, and they're all hanging out in a green field, munching happily on Nancy and building fabulous Owin pipelines. Feature folders are the future.
I agree with you that trying to arrange elements by type is usually problematic. For example putting C# interfaces for a customer and a product in the same "Interfaces" folder is not something I am keen on personally, I'd rather have a Customers folder and a Products folder, each with an Interfaces folder inside.
However, with MVC, there is a lot of enforced and unenforced convention in place which you will probably have to live with. As an example, if you have a controller called ProductContoller, it will automatically look for views in the Views\Product folder. So your product index.aspx/cshtml view is nicely segmented from your other index views.
For things like scripts and CSS, these are not enforced and technically you could put them anywhere, but it's a convention across many web frameworks to keep them in the same root folder. In some frameworks you would be explicitly allowing public access to certain folders to read files, so you'd want to do this for all scripts or CSS files together.
It's not an answer but I hope it helps.
then to hardcode the resulting paths in the controller and the view
No.
Use UrlHelper (Url property in controllers and views). Extends it with ad-hoc functions for resolving your specific urls, as this blog post do.
For resolving views, stick to MVC conventions as explained in Dorian's answer.

Asp.Net MVC5, structuring large projects. Areas?

I come from an Asp.Net background and I'm evaluating Asp.Net MVC for a new project. I can't see how to structure a large project adequately.
I'm happy with the Model/View/Controller architecture and I'm presently trying to get Areas to work (which seems quite complicated for what it is).
Can you have Areas within Areas?
Can you put Views in dlls?
I really need a starting point here, are there are resources which show how to structure large MVC projects, assume that eventually there will be 100+ views in the project, I don't want them all in the same folder and ideally I'd like sub folders
thanks for any help
Edit:
I can see that each controller maps to a View folder, what I want is something more like this
Areas
Mail
Absence
SimpleAbsenceController.cs
ComplexAbsenceController.cs
Overtime
SimpleOvertimeController.cs
ComplexOvertimeController.cs
Etc
Edit2: Perhaps this is more of a routing question, can I map from:
http://www.mystuff.com/SimpleAbsence/Index
to Mail/Absence/SimpleAbsenceController
Fundamentally I want a way of structuring my project into folders
I hate answering my own question as I feel it undermines the work of others who try to help, at the same time others may look at this later and these really are newbie questions, so...
(this is all from reading Pro ASP.Net MVC5, good book)
I wanted to know how much flexibility there is in Asp.Net MVC with regard to using subfolders or dlls. This answer address the subfolders question.
Answers
You can put controllers where-ever you like in terms of folders on the disk, these are compiled, but...
When you use areas the MapRoute in the AreaRegistration.cs file automatically limits
the routes to the namespace for the area. So if for example you move a controller to an area you -must- change the namespace or methods like Url.Action will fail
Views must stay where they are, so for a controller called Fred there must be this structure:
View
- Fred
- Action1
- Action2
- etc
You can work around all of this using your own routing system, you could probably work around the namespace issue with a custom route, but my view is as a newbie you should work with the system until you know enough to fully understand the consequences of breaking the rules
So this means you could have a large project with a few hundred Views all lumped together in one folder. It's not quite as bad as it seems as the controllers can be in sub folders and you can directly map from them to the Views.
You also have flexibility in the routing system, so regardless where controller are on disk you can have any urls you like!
e.g. this route maps from
http://www.example.com/App/DoSomething to
http://www.example.com/Home/Something with no changes necessary
routes.MapRoute("NewRoute", "App/Do{action}", new { controller = "Home" });
NB If you do this make sure to use Html.ActionLink or Url.Action (or equivilents) as opposed to direct links, these are clever enough to generate the correct urls based on the routing.
As I say, complete newbie issues but I'm sure others will have the same questions, thanks to MiniRagnarok for his example of a real life project
What we're talking about here is very opinion based. I've seen people that prefer to have lots of Controllers with a mapping of every object to a Controller. I've also seen people that prefer to have tons of Views. So my example is what our team has decided to do and not necessarily the same as you would see in sample tutorials.
Take a project we did that has 200+ Views for example. The site is an auction and retail site.
Controllers
AccountController.cs
AdminController.cs
AuctionController.cs
HomeController.cs
PhotoController.cs
StoreController.cs
SupportController.cs
Views
Account
DisplayTemplates
EditorTemplates
ChangePassword.cshtml
_Favorites.cshtml
Settings.cshtml
Admin
Auction
Home
Photo
Shared
Store
Support
For us, we name all partial views with an underscore first. We also utilize DisplayTemplates and EditorTemplates. All of this really helps us keep things separate. You'll notice that our controllers are split by role or function. We were never bothered by the fact that there are many ActionResults within our controller since all of our logic is really in the models.

ASP.NET MVC Conventions

ASP.NET MVC is heavily convention-based, "convention over configuration" as they say. So, this means there's a lot of significance to what name things are given and where in the project structure they are created.
As a newcomer to ASP.NET MVC, I appreciate the power and simplicity of this approach, but I do find it a bit confusing to keep track of what conventions are in play. For example, when using UpdateModel controller method, that relies on HTML form fields having the same names as the properties of the model class. That's the obvious thing to do and most of the time it's probably what most people would do instinctively, but I can see that it would get really confusing if one were to rename something in one place and forget to rename it in the other. The linkage is somewhat 'brittle'.
So, I thought it would be useful to have a list of all the ASP.NET MVC conventions here in one place, as short statements of best practice. things like:
"HTML Form fields should have the same name as Model Properties".
Anyone have anything like that? Will you help me create a list here?
Use the virtual path from your deployment server and enter it in the project configuration in Visual Studio. This way the visual studio development server will use the same path structure as the deployment server. This will save you countless hours of work when deploying.
Controllers should always end with the Controller sufix.
Note that convention over configuration is not required, but is how things work out-of-the-box. If you find a convention confusing or not helpful you can change it (eg. how controllers are picked, how views are located, etc.), or do configuration.
Controller and action names specified in routes should have corresponding classes and action methods named exactly this way (plus "-Controller" suffix for controllers). You can override this behavior using [ControllerName] and [ActionName] attributes.

Naming conventions - One rule for Controllers, no rules for Models and Views

In ASP.NET MVC controllers exist in a folder called Controllers. Their names must end Controller otherwise things just don't work (you get an HTTP 404 error).
However, Model names don't have to end Model and View names don't have to end with View.
This seems inconsistent...why (from an MVC or design standpoint) do controller names have to end Controller?
Do other MVC frameworks have this requirement?
Edit
Since this appears to be the convention I am not advocating going against it (see Convention over Configuration!), but I want to understand the reasons behind it.
The controller convention is so routing can easily find the controller without additional configuration. Adding the required Controller ending makes it less likely that you would accidentally expose an object through MVC routing.
There is a built in convention for Views as well. By default views should be in a folder named for your controller and be named the same as the action calling them, this is what enables the method call View() in your action to work without specifying the view. I often find myself specifying the view anyway, but if you are looking for a convention this is definitely the one encouraged by the framework.
From a model standpoint you are correct, there is no standard convention. The reason for this is because the ASP.NET MVC framework never directly touches the models. It needs a convention for the controllers to find them from routing, and it needs a convention for views to find them from the controllers... but models are only accessed from logic in the controller so the framework doesn't need to know about them.
That being said I have seen most people build their Models just like they built their entities or Domain model before MVC. If you are using an active record pattern then name the models to correspond with the tables they are mapped to, if you are focusing more on a domain then name the models to correspond with the part of the domain they are modeling. Also, I have seen more and more people creating a set of view models that are just used for presenting data to the UI and are created by pulling in parts from various models in your domain. Models are definitely the least opinionated part of ASP.NET MVC, but that is a good thing imo since people have very different ways they like to work in this area.
That is just a convention not a requirement! You can change this behavor by customizing the DefaultControllerFactory or creating your own controller factory.
see here for more info. Also there are some examples in MvcContrib project which inject the controller from a Dependency Injection engine. check it out here.

asp.net mvc - subfolders

How does the new Microsoft asp.net mvc implementation handle partitioning your application - for example:
--index.aspx
--about.aspx
--contact.aspx
--/feature1
--/feature1/subfeature/action
--/feature2/subfeature/action
I guess what I am trying to say is that it seems everything has to go into the root of the views/controllers folders which could get unwieldy when working on a project that if built with web forms might have lots and lots of folders and sub-folders to partition the application.
I think I get the MVC model and I like the look of it compared to web forms but still getting my head round how you would build a large project in practice.
There isn't any issues with organizing your controllers. You just need to setup the routes to take the organization into consideration. The problem you will run into is finding the view for the controller, since you changed the convention. There isn't any built in functionality for it yet, but it is easy to create a work around yourself with a ActionFilterAttribute and a custom view locator that inherits off ViewLocator. Then when creating your controller, you just specify what ViewLocator to use, so the controller knows how to find the view. I can post some code if needed.
This method kind of goes along with some advice I gave another person for separating their views out for a portal using ASP.NET MVC. Here is the link to the question as a reference.
In terms of how you arrange your views, you can put your views in subfolders if you'd like and create your own view structure. All views can always be referenced by their full path using the ~syntax. So if you put Index.aspx in \Views\Feature1\Home then you could reference that view using ~/Views/Feature1/Home/Index.aspx.
Here's two good blog posts that I found that may help other readers:
http://stephenwalther.com/blog/archive/2008/07/23/asp-net-mvc-tip-24-retrieve-views-from-different-folders.aspx
This one talks a little more in-depth about what Haacked described above.
http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx
This is a nice alternative for grouping your site into "areas."

Resources