Change the Location of the Controller inside the Project structure - c#

I found this Post (How to extend where MVC looks for views) about changing the location of the View.
I was wondering if there's something similar for changing the location of the controller.
I just want to change the location of the class inside project and don't want to affect the url.
For example Instead of placing the Controller into
MyMvcProject\Controllers\
MyController1.cs
MyController2.cs
MyController3.cs
I want to achieve something like
MyMvcProject\MyGroup1\
MyController1.cs
MyController2.cs
MyMvcProject\MyGroup2\
MyController3.cs
and also support Areas:
MyMvcProject\Areas\MyGroup3\
MyController4.cs
Is it possible to achieve this? And if yes, where can I find documentation about it?

You can do what you want, and it doesn't require any special configuration, because ASP.NET MVC does not care about where you put your controllers. First, controllers are located using reflection, so the name of the folder where you put your controllers is irrelevant. Controllers are searched by type name and optionally by namespace (for disambiguation). You can even have controllers in separate projects/assemblies. As long as the controller ends up in an assembly in the bin folder then it's searchable by the framework.

As mentioned above, you'll need to create a controller factory to support your custom resolution. Here's an example:
http://develoq.net/2010/custom-controller-factory-in-asp-net-mvc/

As others have already stated you need to do one of the following:
Derive from IControllerFactory interface and provide an implementation of the CreateController and ReleaseController methods.
Derive from DefaultControllerFactory and override the default behaviours.
Here are some links to get you started:
Custom controller factory in ASP.Net
Inside the ASP.NET MVC Controller factory
Dive deep into MVC - IControllerFactory
Also, if you're willing to spend a bit of money I would also recommend the book Pro ASP.NET MVC 3 Framework as this explains almost every aspect of how the MVC framework can be customised (including an example on how to create a custom controller factory - the source code for which can be freely downloaded from the publishers website).

I think it is impossible to do this. ASP.NET MVC have defined the convention that we have to follow.
Controllers are in Controllers folder, views are in Views{ControllerName}\

I believe you cannot change the convention unless you create your own ControllerFactory.
If you really want to do that, just implement IControllerFactory interface (or try to derive from DefaultControllerFactory).
Then your Application_Start register your controller factory using ControllerBuilder.Current.SetControllerFactory method.
Look at the ControllerFactory documentation and to the MVC source code for details.

What you're asking and what your example shows are two different things; depending on which one you want to achieve, you may or may not need to do any work.
There are two requirements for a class to be a controller in the MVC Framework:
It has to have a class name of Name + "Controller"
It has to have a parameterless public constructor.
Your sample "normal" MVC layout is actually not valid:
MyMvcProject\Controllers\
MyController1.cs
MyController2.cs
MyController3.cs
Those classes wouldn't be found by MVC because they don't have the correct name, regardless of which folder they are in.
If all you want to do is change the namespace/folder names, that "just works", assuming you name them the same as the appropriate route segment(s):
MyMvcProject\MyGroup1\
Page1Controller.cs
Page2Controller.cs
MyMvcProject\MyGroup2\
Page3Controller.cs
MyMvcProject\Areas\Area1\
Area1Page1Controller.cs
This walkthrough (written for MVC 2 but works just as well in MVC3) shows you how to support Areas with the default controller behavior.
If you actually want to name them SomethingController1 or SomethingElseController5, or otherwise change the route -> classname mappings, then you do need to implement a custom ControllerFactory, and inject it into the MVC pipeline.
There are plenty of examples on the web on how to do this, including the one posted earlier.

Related

What does the attribute "[ApiExplorerSettings(IgnoreApi = true)]" do?

EDIT: I'm aware of what attributes in general do, the question is for this specific attribute alone. Sorry for the confusion!
I've read the following question, along with this one, which point to how the attribute is used to ignore the generated swagger/swashbuckle documentation for specific methods or whole controllers. (documentation is the swagger page with all the api's listed I believe?)
But other than swagger/swashbuckle (which is a NuGet package), what other function does this attribute possess in ASP.NET?
When applied to a public method on a controller, it prevents that method from appearing in the swagger ui.
First of all, to clarify, an attribute in C# does not trigger anything by itself. External code searches for classes, methods or properties marked with a specific attribute, and act accordingly.
Of course, there are many building blocks in ASP.NET MVC, it can be confusing sometimes.
This attribute is used by Swagger to hide the endpoint.
Also usedd (in .NET core at least) by the given implementations of IApiDescriptionProvider and other related interfaces, but that would be effective only if you actually use them (by configuring them up in Startup.cs)
(for some more details and example, see https://andrewlock.net/introduction-to-the-apiexplorer-in-asp-net-core/)
This attribute helps to control the visibility. We can use this on the controller class or an action method when we want to hide that specific controller or action from showing in the swagger UI.

Surface Controller or Custom Controller in Umbraco 7?

History
I'm a Web Forms developer with some .NET MVC experience, new to Umbraco and learning as I go.
So far I've been following the Umbraco documentation and videos to get set up which means all my controllers inherit from a "Controller Base" with common functions included, which in itself inherits from SurfaceController.
Recently however, I have noticed some bloggers and external reference material referencing RenderMvcController in the base class instead of SurfaceController - now the Umbraco documentation is unclear on the real differences between the two, nor which situations you should use them in.
The Question
Is there a clear and distinct difference between the imagined usage scenarios for a Surface Controller - inheriting from Umbraco.Web.Mvc.SurfaceController, and a Custom Controller - inheriting from Umbraco.Web.Mvc.RenderMvcController?
Thanks!
The documentation for the SurfaceController is here: http://our.umbraco.org/documentation/Reference/Templating/Mvc/surface-controllers
In a nutshell, the SurfaceController is used for helping to interact with views. So for example you could post a form to a surface controller. Or you could write a child action to a view with a SurfaceController
RenderMvcController is used purely for routing to published pages. So you could sub-class RenderMvcController in order to 'hijack' requests to published pages of a specific Document Type. See here http://our.umbraco.org/documentation/Reference/Templating/Mvc/custom-controllers.
To further clarify based on Digbyswift's answer:
SurfaceController = APIs or form targets (that then redirect)
RenderMvcController = custom logic to build a model or select a view for a content item (based on Document Type and, optionally, template)

Split controllers into 2 separate DLLs

I have an idea I'd like to implement which basically involves separating the controllers in an MVC4 Project to 2 different projects. The reason being I'd like to be able to have different controllers for an internal admin section of my site and for the external client section. I'd like to make changes to each of them individually and add a new DLL to the website as I make changes...the changes to the internal admin section of the site thus not affecting the controllers DLL for the external client section for example.
Does anyone know if this is possible/advisable or of a better way to accomplish what I'm trying to achieve?
taken from an artical :
"The MVC framework provides a default controller factory (aptly named DefaultControllerFactory) that will search through all the assemblies in an appdomain looking for all types that implement IController and whose name ends with "Controller." Thus, if you tell the factory to look for a "Home" controller, the factory can return a newly instantiated instance of a HomeController class regardless of the namespace or assembly it lives in—as long as it implements IController...."
by adding a reference to another project in you'r solution you can achieve what you are looking for, in that referenced project add you'r controllers. like written above the MVC Routing will find all controllers that been referenced in that solution.

Curious about MVC Controllers?

Just a quick question, when you create a new controller for a new MVC ASP.Net app how does it know which controller to use. More specifically, given you create a new controller and you call it SockController in order to use said controller I would navigate to http://mywebapp/sock. How did the web app know that /Sock/ is linked to SockController? Is there a mapping somewhere ? Or if not what happens when if you call omit controller from the name when creating it, ie call it SockCont.
Note: I am not a Web Dev im just curious so please don't post links to page with tons of text, im looking for a short simple answer.
ASP.NET Routing extracts the name of the controller from the URL by getting the Route Value and then appending "Controller" to the end. So "/home/" returns "HomeController".
ASP.NET then uses reflection to go through every class in the project's assembly (or referenced assemblies) to find a class that inherits from System.Web.Mvc.Controller and is called "HomeController". It then uses the default, parameterless constructor to create an instance of it.
It then matches the Route action to a method of the controller.
This process is called "Dispatch" and similar patterns are seen in PHP, Ruby-on-Rails, etc, except that dynamic languages like those have different ways of resolving class names to actual objects (CakePHP uses Class auto-loading bindings to locate the class definition, for example).

Partial class for controller

Is it possible to create a Partial class for the controller in MVC?
Reason : I have a controller which contains too many code. This controller contains the code for different reports and due to too many code it reduces the readability of the code. I want to keep controller name same for all reports so I want to distribute code for the different reports.
If i can do any other way than do let me know.
Thanks
Alok Shah
Yes you can use a partial class - the compiler just merges them all up a compile-time to produce one.
However, you mention you want to 'distribute' code - if the code is to go into multiple projects then partials are not going to help.
You can instead create base controller classes (that inherit from System.Web.Mvc.Controller in a class library project, with the necessary action methods, and then simply use routing to route similar urls to different controllers. Here's a link to the Asp.Net Tutorial 'Creating Custom Routes' which might be useful for that. I hightly recommend looking through the rest of the tutorial if there are other core aspects of MVC you're not sure about. It doesn't cover everything, but it does the basics.
A web application that needs to use those then simply has its own controllers inherit from those redistributable ones. Even better, you can now create extensibility points through virtual methods etc if there are elements of these reports which different web apps might need to customise.
So "Reports/Customers" could route to a CustomerReportsController and "Reports/Orders" could route to an OrdersReportsController:
routes.MapRoute("CustReports",
"Reports/Customers/{action}",
new { controller = "CustomerReports", action = "Index", id = "" } );
routes.MapRoute("OrderReports",
"Reports/Orders/{action}",
new { controller = "OrdersReports", action = "Index", id = "" } );
This is the most simplistic approach to this problem - but I think using Areas (link is to MSDN walkthrough) would most likely also be applicable, in which case you might not need to use routing at all because the default route would probably do it all.
Of course!
Partial classes are a feature of the C# language and bare no relation to MVC or any other framework you may be using.
Yes. Partial classes are really just a feature of the language, and the compiled class is a regular .NET class like any other.
I would suggest though that you split the controller into multiple controllers, to ensure proper separation of concerns (having a class that is so big you need to split it up into multiple files will surely smell bad.)
"If I can do any other way than do let me know"
How about:
Abstract away the "doing" parts to various report generators for the discrete report types, all of which conform to an Interface. These report generators will be classes sat outside of the MVC tier of the application.
Clean up the controller so that the dependencies (Report generators) are injected in the constructor, using Ninject, StructureMap or Castle Windsor
Clean up all of the report generation code out of the controller and into concrete implementations of the Report generator abstractions
You will then not need to split up your controllers into separate classes. The downside is that this will take a reasonable amount of time to conceptualize and implement, but you'll end up with a better codebase.

Categories

Resources