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.
Related
I currently have all my common utility function methods in a base controller, which all of my controllers inherits from. These are methods for functionality like uploading files, resizing pictures, deleting files, sending e-mails, generating random passwords, hashing passwords, etc.
What is the recommended structure for these kinds of things?
In that case you shouldn't put all these utility functions inside your base controller. You will face a lot of problems if your project grows. Changes and testing of these methods can become difficult, all your inherited classes need to use the same utility methods, etc. Have a look at Composition over inheritance to see another approach.
Somethimes I tend to organize my projects in the following manner if that might help you:
Simple helper methods: Create a folder and a namespace (e.g. namespace [...].Common") inside your web project and put one or more public static classes inside it (e.g. class "FileHelper.cs", "StringHelper.cs", etc). If you need one of these methods in a controller action simply put a "using ...Common" statement at the top of your controller class and call e.g. FileHelper.MethodName.
If I can define a closed subject area with a group of methods I try to encapsulate these methods in a service class (maybe even outside the web project if I have a feeling that I might need this functionality in other projects too), define an interface for that class and plug that functionality into controller classes by using dependency injection. If you don't know about that concept you should definitely read Dependency injection in ASP.NET Core. Dependency injection is a vastly used major concept in ASP.NET Core projects that brings you a lot of advantages and - if used correctly - stears your work into well-organized projects.
More complex organizations are always possible depending on your needs. Have a look at multitier, hexagonal or onion architecture if your projects grow.
We have a REST API which already uses "/v1/" in the controller routes and we're planning to create a "/v2/" path and also take advantage Web API 2. I was able to find a lot of information about versioning your controllers (attribute routing, custom resolvers, etc.) but one thing I have not been able to find any articles about is versioning your Model objects (a.k.a. data transfer objects). How are people versioning their Model objects?
In our codebase and problem domain, the controllers are "simple" (CRUD, really) and it's the Model objects which encode our domain expertise and upon which our core business logic operates. (I suspect this is true for many applications, so it's strange that most of the web articles about Web API 2 and versioning focus on controllers and elide concerns about the Model objects as if they'll take care of themselves.)
In a perfect world, I'd like to be able to just use the same classes for both API versions, and put attributes on properties to include or exclude them, things like "version 1 only", "version 2+ only", "deprecated in version 2", etc. I think I could implement this with a custom serializer that looks for attribute classes I create, but I want to know if there's built-in support for this or an open source library for it before I roll my own.
Another possible approach would be to derive the version 2 model classes from the version 1 model classes, but I could only add that way and not be able to remove anything. I could derive both the version 1 and the version 2 classes from a base class, but any of these inheritance-based approaches will require A) refactoring where classes are plus B) a factory pattern so that the internals can create the correct derived type. I'd like to avoid this, but would still prefer it over code duplication.
I suppose another approach is we could hide our real Model objects and copy their values into "dumb" data transfer objects at the interface. This approach is simple and would have maximum flexibility, but would also maximize the work.
Is there an option I've missed? What approach are other people using?
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 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.
I've got a few controllers here at work that contain methods I can use in other controllers.
I considered moving out some of the common functionality to a base controller which these could then inherit from. The problem with this is that I’d have methods I need in multiple base controls which I’d not be able to access. (Because we can't inherit from multiple base controllers).
My other idea is to move out the common functionality into their own classes, outside of the Controller folder.
What would you do? Is there a great way in ASP.NET MVC to share code like this that I don't yet know about?
There's a rule of thumb about object-oriented programming that you should favor composition over inheritance, and it fits very well into this scenario.
I would make one or more services that encapsulate the methods in question, and then consume those services from the Controllers.
For extra points, extract an interface from the service(s) in question, and inject the interface into the Controllers for maximum Separation of Concerns.
I'd factor out in to a helper class or something. From what you have described the functionality helps the controllers/
The choices seem to be base controller or helper class. You could take control of controller creation and inject the helper into whichever controllers need it.