I've started a new MVC project, and this is my first where its pure MVC without CMS integrations or otherwise. I'm looking for advice on naming conventions, as I am aware there are going to be a lot of controls and forms that are re-used.
Is it sensible to create say a Controls Controller for these re-usable items and call them from my views as appropriate? Also, would there then be a way to stop someone navigating to that Controls/MyControl URL directly?
Thanks,
Mike.
To stop one from navigating to Controls/MyControl you just need to add ChildActionOnly attribute:
[ChildActionOnly]
ActionResult MyControl(...){...}
Naming/grouping is up to you - you can start with one controller and see if controls need to be split into groups later.
Note that you may not even need controller for most of the controls as long as they just show data - #Html.RenderPartial("MyControl", dataForControl) may be enough (assuming Razor and existence of "MyControl.cshtml")
Related
Coming from a long period of WebForms development, I recently began working with MVC. One thing that struck me, is that since controller methods are not called directly from code, Visual Studio won't pick up any references to them.
I understand the reason why there is no reference count, but it can be problematic sometimes. Let's say I rewrite a controller method to accomodate some new requirement, perhaps a certain call to the method needs additional data or a modified result. But perhaps that method, or endpoint if you will, is being called from several places, and the change I made breaks the result handling for those other calls. I would like to be able to easily find all the code in my solution, which is going to invoke the endpoint.
Currently I tend to copy the method name and perform a regular text search in the entire solution, which works rather well as long as the method name isn't too generic. If the method name is "Index", it can be a long day.
Are there any recommendations on how to simplify this, such as coding conventions, plugins or otherwise? I.E. how can I locate from where the endpoint will be invoked?
I currently use Visual Studio 2017 Enterprise, but solutions working in other versions as well are preferred - to make the answer useful for as many as possible.
Thanks in advance / Culme
UPDATE: I learned a lot based on the comments and replies I got. Apart from what is mentioned below, I also decided to try and keep my controller method names unique and identifiable, to simplify finding where they are being used. As an example, instead of just "Index", I'll try to use "Fidgets_IndexController" or something similar. That way, a simple text search will go a long way for locating calling code.
Controller methods are not directly referenced from any part of the code (therefore 0 references), but they are dynamically invoked based on RouteTable which maps controller methods on startup RouteConfig.RegisterRoutes(RouteTable.Routes); in global.asax "implicitly" which would map them as /controller_name/action_name or these can be changed by either editing
RouteConfig.RegisterRoutes(RouteCollection routes) or using attributes:
[Route("myAction")]
public ActionResult MyAction() {
...
}
which would bind it to /myAction (without controller name)
further reading:
MSDN - Understanding MVC Application Execution Process
Lifecycle of an ASP.NET MVC 5 Application
ASP.NET MVC Routing Overview
One of the options is Resharper - it more or less can determine where you use Html.ActionLink() or Html.BeginForm() that points to a controller action. But it won't detect any posts/redirects done from JS.
Also another thing you can do is use T4MVC to make the links from views statically typed, so you can search on references.
Text search through the solution can help, but not always good as you already discovered - how many references to string Index do you have in an average MVC project? So this will help with distinctive controller/action names, but not with common names.
Apart from that you are on your own. If you try doing something clever, like in JS concatenate strings to give you the right endpoint - you are in trouble.
Another option if you know the application fairly well. Put a breakpoint on the controller action and then run some tests of the application.
I have an ASP.NET application that was developed by "programmers". This application contains all things which you should not do:
Hardcoded settings
Copy/paste anywhere (code not re-used)
Make a lot of small SELECT requests to the DB for each row instead of doing JOIN
Model, view and controller in one function
Etc.
Now, my goal is not to throw everything away and start over, but I want to separate different aspects of the MVC of the application. I do not want to start a new MVC project, I would like to evolve the existing solution into something modular.
For the controller, there is no problem, I can create classes that will manage DB connections, send mails etc. On the other hand I do not know how to separate the view and the controller.
The problem that traditional ASP pages myPage.aspx have an associated file myPage.aspx.vb and in this vb file there are both view management part(page elements, like dropdowns) and also the Business part (controller) which is executed on the button click.
I thought about making a call to a myPageControl.vb class that will contain the business part from the file myPage.aspx.vb, which will call the Model (db, mail, other).
(View: myPage.aspx.vb) -> (Control: myPageControl.vb) -> (Model: Db.vb, Mail.vb)
The problem is: how should I do to modify the page content from the controller, for example change a list value or display a text on it. I have to make a call to the View (to the other direction) and pass by parameter the class MyPage (.asp.vb)
I have already tried to find an answer to my question, but I've found only answers taking about MVC projects.
Does anyone have any idea how I should do it?
Seperation of Concerns was one of the main problems with webforms, and one of the advantages of MVC. In my opinion the best you could probably do is seperate the business logic into classes like you are doing now so code could be reused throughout the application, but completely "seperating" everything may require rebuilding the application as an MVC app.
The only answer I've found to this is to have the controller send the "data to bind to" to the page as XML. then all the page has is its page_load of course, and then a method to receive the XML and update itself from it. You can use smart naming structures so that you can do reflection and autobind from the xml to page elements.
Then on an action, have the page generate an xml of all the elements on it and their values, and send that through a "ProcessAction" method that determines the correct controller and calls the right method on the controller.
But as suggested, doing it over as an MVC project probably makes the most sense if that's the pattern you are going for. What I suggested works, but it will be as much or more work than just starting from scratch with MVC. Besides, remember that "support" for web forms is disappearing soon. It's not in (and won't be in) .NetCore, so it's days are numbered.
Where is the best place in the project directory for the controllers for Shared partial views?
I have found similar question to: ASP.NET MVC: Correct place for Partial Views?
I can't decide if it is better to do something like /Controller/Shared/CONTROLLER_FOR_PARTIAL_VIEW or just create its separate folder like /Controller/CONTROLLER_FOR_PARTIAL_VIEW
The partial view is specifically for dropdownlistfor, and the model wont be used for anything other than to populate the dropdown. So if a site has many dropdown lists or just partial views in general, a shared folder seems to be the best option. If the preferred way it the Shared folder, do you use one controller for each partial view, or one controller for all partials? I appreciate any thoughts or feedback, thanks!
EDIT: To be clear, I m specifically asking about the directory for the CONTROLLERS not the VIEWS. Thanks!
In one sense, it doesn't matter. There is no true standard or convention for this, so you have the freedom to do it however it makes the most sense to you and your application.
Having it under something like Controllers/Shared could make sense, if there's enough of these that that is worthwhile and it adds value to keep them separate from regular controllers. However, in terms of a project, everything is essentially shared, so there's no true distinction here. Personally, simply having it named something distinctive is probably the best route. For example, I have a number of child actions in one of my projects that are used in various parts of my layout. As a result, I created a LayoutController to house these.
The one thing to keep in mind is that, if you're using standard routing, any controller will be available to the routing infrastructure, regardless of where it's located in your project tree. You'd have to pretty much just know how to get to it, but if you named your shared controller something like SharedController, then with standard routing, its actions would be available via /shared/action. For things like child actions, this is easily solved by using [ChildActionOnly]. By adding that attribute to your child action, it will be divorced from the routing infrastructure for URL requests. Internally, MVC will still be able to get to it for the purposes of rendering it for a view, though.
Projects I've been on it was at /Area/Controllers/SharedPartialController.cs and with that naming the view was at /Area/Views/SharedPartial/_MenuDropdown.cshtml
Hopefully you're using "areas" in your MVC project, in which case I would suggest doing one shared controller per Area.
I.e. /Order/Controllers/TabsPartialController.cs for one that relates to Order area, and then /User/Controllers/NavTabsPartialController.cs etc.
I'm recently doing a purchase order program using the MVC pattern in C# (not ASP.NET web app, just a desktop program). Now the problem is that in the UI there are lots of buttons that will link to another section, let's say from the order page I can click and go to the inventory page. Each section of course have their own set of MVC.
How can I connect the button to other controller while maintaining abstraction? That is each view does not have to understand how the other controller works, or what parameters it requires to work.
There are a couple of design possibilities that comes to mind but I have no idea which one is better / simpler:
The dirty way: just put the references to all the required controllers in one view, but this way reduce abstraction.
Shared view space: each button is a different view that has their own controller, but then I need to have view manager of some sort.
Routing: pretty much like ASP. NET RedirectToAction, make a custom router that use common type (like string) to determine which controller and which action to perform
Custom button for each action: for each controller and each action I make a button class just for it. Then I need a way for the view to supply the required parameters to each button.
Any suggestion on what should I do?
What i think that you should for the "shared view" i.e create on shared view containing all of that buttons and their calls if this is not working for you then you can create a saprate calls of WebAPI in their controller to get your date in return.
I decided to use a modification to my 4th option, a factory pattern that creates all my buttons. The factory is given the references to all the controllers and initializes all the buttons accordingly.
The view only need this factory during construction and ask for any of the button it can produce.
This way the view doesn't need to know anything about the controller during construction. The controller also doesn't need to know the view at all.
Thanks for everyone sharing their opinion.
So I am reading about building MVC3 projects and there is one thing that seriously bugs me. The folder structure of the project in no way corresponds to the path of the HTTP request. There is a bunch of things I like and would want to use, but having a flat folder structure is not one of them.
Why is this a problem? Well, I see it becoming a problem when building a site with a heavy mix of content pages and various forms/dynamic pages (most of our sites are like that), which would typically be done by different people. It seem it would be too complicated for client-side developers to follow routing rules of dynamic pages and/or creating new ones.
What I would like to understand is if there is way to configure MVC3 application in such a way that:
it follows directory structure for finding controllers without explicit route map for each one
views live in the same folder as corresponding controller
routing magic still works for actions and parameters
For instance I'd like to have a request /fus/ro/dah/ to try to find DahController in the \webroot\fus\ro\dah\ folder and execute its Index action. If not found it would look for RoController with Dah action in the \webroot\fus\ro\ folder, etc.
It is entirely possible that MVC was not meant to be working this way at all and I am just trying to force a square peg into a round hole.
UPDATE:
Looks like I can drop a view file into the desired folder structure, and it will be executed. However layout would not work apparently because it is expecting a controller. Does this mean I have to create a controller for pure content pages? That is a pretty crappy design...
UPDATE 2:
Main issue right now is that creating "fus" folder means that MVC will not even attempt to look for FusController... not under "fus" folder, nor anywhere else. Is it possible to get around that?
For instance I'd like to have a request /fus/ro/dah/ to try to find
DahController in the \webroot\fus\ro\dah\ folder and execute its Index
action. If not found it would look for RoController with Dah action in
the \webroot\fus\ro\ folder, etc.
MVC is not designed for a particular need like this, it is a general framework for building applications using model-view-controller pattern.
If you can't bend the application for the framework you can bend the framework for the application and honestly MVC is very customizable. [As a proof, in the current project (migration from ASP to MVC) that I'm working we have models as xml and no classes also we are using XSLTs for rendering. With a little work we have created custom components like custom view engine, custom validation provider, custom model binder... to make the framework best fit for the application and it does]
MVC is not designed and not forces to use it as it is and you can customize/extend as much you want. In your case you may have to create a
custom controller factory (because you want to customize the way in which the controller is seleced),
custom view engine (because you want to customize where the view is placed)
and may be others.
For custom controller factory you have to extend the DefaultControllerFactory class. There are lot of articles you can find through Google that explains about how to create custom controller factories.
Depending upon the view engine you are using you have to extend the respective one. For ex. if you are using web forms then you have to extend the WebFormsViewEngine and it razor then RazorViewEngine.
For more info. check this link
http://codeclimber.net.nz/archive/2009/04/08/13-asp.net-mvc-extensibility-points-you-have-to-know.aspx
you can mixup Asp.net and Asp.net MVC. as LukLed said, MVC is convention over configuration pattern. if you follow the convention. you dont need to configure. you can check this link for mixing up the asp.net content with MVC3
Mixing Asp.net and Razor
I believe ASP.NET MVC is not meant to be used that way. While you can configure MVC to do it, it is better to keep standard /controller/action/parameters URL format. If you have complex website with many different functionalities, areas may be helpful http://msdn.microsoft.com/en-us/library/ee671793.aspx. Every area get its own set of controllers, models and views, so teams working on different parts of website won't disturb each other.
While it may sound convenient, that framework first searches for DahController and executes Index action, then searches for another one, I find it bad idea. URLs should be clearly defined and Fus controller with Ro action shouldn't just stop working, because someone created RoController with Index action.
Look into using Areas as well. I think that helped me get over my folder structure issues with MVC honestly. So i could use the base folder as my Home details, then i could have a 'Admin' area which was a separate folder, things like that.
How "regular ASP.net" do you want it to be? If you want to do "legacy" ASP.Net Web Forms mixed in with MVC, you certainly can - re: mixing MVC with "file based aspx" - aka "hybrid". At the end of the day, it's all ASP.Net.
This is a standard MVC Application generated by Visual Studio. I've added a folder somedirectory where I want to use the legacy folder/file.ext paradigm and have a default.aspx Web Forms file:
Can I navigate to it via http://foo.com/somedirectory? Yes.
Can I use "pretty urls" too? Yes
Vanilla Global.asax generated by VS, just added MapPageRoute:
....
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//using "pretty urls" - ordering your routes matter.
routes.MapPageRoute("theWebForm", "legacy", "~/somedirectory/default.aspx");
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
so now I can navigate to it via http://foo.com/legacy
Just check the order of your routes, and perhaps plan on your naming conventions so you don't have "collisions"...
Hth....