My question is similar to "ASP.NET 2 projects to share same files", but with an ASP.NET MVC slant.
Basically, we have two sites, one being based mostly on the other (roughly 90% views, controllers, images, in the second are identical to the first). However, in some cases, the views may be different, or a controller in the second site may be different to the first.
Are there any simple ways of achieving this in ASP.NET MVC?
So far, we've looked at using linked files to have two totally seperate projects where the second project shares the files it needs from the first.
One problem with this approach is that most pages in the second project don't literally exist in the virtual directory, it makes debugging a pain - you have to publish in order to generate the files so you can debug.
Does anyone have any better approaches, or ways this approach can be simplified?
This article might help: http://dotnetslackers.com/articles/aspnet/storing-asp-net-mvc-controllers-views-in-separate-assemblies.aspx
Essentially, it involves creating your own WebFormViewEngine which tells MVC where to look for the Views.
If they are 90% the same and you want to keep them in sync as functionality evolves I would consider making them into a single web application and using the host header to differentiate and to change the images/links/text/functionality/etc. between the two sites.
You can do this in your BaseController: look at the host header and create a Brand object that every page and view has access to, just like it might have aUser object. That Brand object can include the name of the site, the canonical Url for the site, the location of the image directory for that brand, boolean values to turn certain features on or off, ...
Now in a Controller you can just ask if (Brand.SupportsPageX) {...} to decide what to show next. And if you make the brand object part of your base view model or put it in the view collection you can have views that use the brand's name, image directory, ... to customize how they look.
Put as much as possible into a shared non-UI library project. I do that on every project that I work on this, increased testability, shared code with Windows Services, and a host of other reasons.
I've found that if you're aggressive with this then quite often over two-thirds of the project would be in the non-UI shared library.
After doing this, you can take things a step further and create a second library with some shared MVC/UI elements.
Depending on your opinion of it, RenderAction may help a bit here. As you know, RenderAction will allow you to group up those controller/view components and pass in variable arguments at runtime.
A project I'm working on currently has a similar requirement and we have started looking at using portable areas. I personally haven't delved very deeply into them at the moment, but it may be worth you taking a look.
I've been working with areas to create multiple websites that I can host with one hosting account. I would think you could use a similar approach. By implementing the common functionality in the base project, it will be available to each area. You can also override any of the base views or controllers by implementing them in the area. It may require some tweaking of the ViewEngine and Routing but I think it could be done.
Related
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've inherited a project in which I'm the fifth proverbial 'cook in the kitchen'. The project is too mature for extensive changes on my timeline, but I'm thinking I can at least get rid of some of the "where was that code again!?" issues I'm having.
All of the controllers are dumped in the same Controller folder, but there are enough with similiar names to be a bit cumbersome. Additionally some of these controllers are solely for partial views. The admin page for instance has its own controller, but each of the four tabs on its view have their own model/view/controller. What are some recommended approaches I should take to get this under control?
If you're looking to organize your MVC project, I find Areas an invaluable way to keep things from getting out of control.
It might mean changing some of your paths, but I'll leave it to you to determine the value to your particular project.
Have a read of this: http://msdn.microsoft.com/en-us/library/ee671793%28v=vs.100%29.aspx
I am building a hosted business SaaS application using MVC 4/C# 4. I'd need to have customer specific resource files, css, views, and business logic that leverage a base code layer as much as possible. How would each of these (resource files, css, views, logic) need to be structured to accomplish this?
I realize this is probably a very in depth answer...but I have no idea where to start or what to search for to begin to research this. Any pointers so I can research further?
Here are my initial thoughts on each:
Views
Use a Switch statement based on user to return different views.
CSS
Use switch statement in view to specify which css to load
Resource Files
I'm not using them now but need to implement, so not sure exactly how they work. From what I've seen you can specify a resource file at the class MetaData level, which is a compile time thing. Not sure how you would change this at the user level. I can see here, how to change it based on culture...but not by a user profile attribute (like the company they belong to).
This looks like a start...will review more.
Business Logic
In my services layer, I could implement switch statements...but that seems messy. Is there a way to create a new classes that override the base classes but only for certain users? Or putting these in a separate project/dll and only using that dll reference for a certain user?
I used to work on the IBM iSeries, and they had the concept of a library path that could be set by user at login. You'd have a custom code path that overrode the base code path libraries. Is there anything similar in MVC?
Data Localization
In my database, I have a table for Orders and another for OrderStatuses, which may be displayed in a drop down for the user to select a status. These statuses may be 'Open' and 'Closed'. But another customer may want that in Spanish...How would you handle this?
Any other considerations I am missing?
Use switch statement
Any time someone is writing object-oriented code and mentions a switch statement to control variable requirements, alarm lights begin to flash.
When you have similar but different requirements, polymorphism is your friend.
Without knowing full details of your requirements it is difficult to provide a specific answer, but consider using the factory pattern / dependency injection to provide objects appropriate to a specific user (or more probably, to the company associated with a specific user).
UI Layer
Generally speaking you could use a factory to return controller instances, based on a common subclass, that implement requirements for a specific user/customer and return views appropriate to that user.
I'm not well enough versed in the specifics of wiring routes in ASP.Net MVC to suggest how specifically to set that up, but it feels like the right approach. Perhaps another poster can shed more light.
Business Logic
This is a classic use of polymorphism, when requirements vary significantly. Alternatives to per-customer classes include configuration-driven behavior and rules engines. The best choice depends on your specific sitation.
Data Localization
Things like order status in the DB should not be bound to a text like 'Open'. They should be bound to a binary representation (e.g. an INT). Leave it to the View to translate that meaning into something specific to the user's language.
In a SaaS application we have developed we have clients who have their own private domains so being able to support something like that was a must. We had to be able to support:
www.mycompany.com/u/clientname
clientname.mycompany.com
www.clientname.com
On of the things we considered was how we could use a single deployment/code base to handle all of these clients. What we ended up with was a Base system that could be extended through the use of "plugins" which are basically class libraries named "APP.Clients.{ClientName}".
We wrote a custom ViewEngine that allows us to make use of these plugins to load Views, Controllers and even Controller Actions from the clients custom plugin to over-ride the base site.
What we ended up with is similar to what people call "portable areas" or basically external views and controllers in an Assembly.
Clients can share a common "network" database or they can be rolled off in to their own database. Most all of the config comes from reading the current URL and having logic that can determine which "client" it is and loading their settings and processing their customization.
Being able to load the client views required adding in additional search locations for Master Pages, Views and Partial Views (why we have a custom ViewEngine).
There is no simple answer and what works for one SaaS project may not work exactly the same for another. Your architecture will likely be similar but your business needs will dictate where your project takes you!
I have an existing MVC app which will be utlized by another user group in the near future. Both the existing and new user group/program will have independant data. I was just thinking to add flags in the tables to distinguish between the two user group/programs and do some routing when they access the application to pull up respective data.
Now when it comes to code customization, for instance one group/program wants to have extra fields on a page which the first group does not want or the process flow of the application is seperate between the two user groups.
If the above two scenarios will occur frequently, should I just do a new web and database instance rather than customizing the code for each program/user group. This way both of my customers/user groups will have flexibility to add different logic/fields to the application.
The only con I see with the non-multi tenant approach is the time effort by the developer to maintain two seperate applications. I am scared of adding contional logic to customize the same code base for each different user group/program. Cost of infrastructure is not an issue. Also I do not forsee this application to be used by more than 2 user groups/programs at any time. So what do you guys think which apporach i should take and why? thanks all in advance
P.S The users arent any ninjas who will try to hack the site to see the other tenants data. They are corporate users. Theyd rather not use this application but its part of the process so they have to use it.
It's worth taking a look at microsoft's article on multi-tenancy.
I'm also working on trying to design an mvc app with such an architecture where each client can have separate fields and customised screens.
The conclusion that I have come to is that using an IOC container with multi-tenancy support will probably make the whole thing a lot easier.
Autofac has built in multi-tenancy support.
In terms of having logic for clients in each view I believe that if you go down the IOC path you can have a controller for each tenant and in that case hard coding such client specific logic isn't necessarily as bad as it would be having it hard coded all into a shared controller. In essence I believe when writing a component that is for a particular tenant you can switch you mindset to writing as if that tenant was the only one using the system.
The other solution I have landed in for customising views is to use a variation of the RazorGenerator approach for compiled views where I have each tenants views compiled into a separate assembly and have created my own view engine (based on this) where I can swap out the assembly that I look for views in depending on a value in the routing parameters.
Of course I'm still exploring this approach and haven't fully flushed it out in order to find out where it may fall short.
If the difference in the 2 users' requirements is more than 10% of the screens/functionality then you better have 2 databases and apps. If it is expected to be less than 10% then just write separate actions (possibly with different prefixes or suffixes in Action names) for where the functionality differs.
maybe i am wrong but i seriously i don't like the current structure of MVC application, and i think on big projects it will cause trouble to maintain.
so is there a way to group related Controllers,Views, Models together, like if i have gallery Module i want all it's Controllers, Views, Models to be grouped under Gallery Folder.
Areas sound like what you are looking for. This will let you group controllers/views/etc. Unless I misunderstood the question?
Phil Haack discussed this here, it's the same issue I've faced and have yet to overcome correctly.
From the sound of it you're moving against the basic principals of MVC, that being the separation of Model, View and Controller rather than your desire to split at 90 degrees to that by using modules.
I'm not entirely sure what benefit you would get from splitting it in to modules any way since I would expect you to have one GalleryController. Where you are likely to have the most 'entities' needing grouping is with the views, possibly one or more for each GalleryController action, but they are in their own folder which gives the sort of functionality you are looking for anyway.
Finally there are the models. Obviously I don't know your project so I don't know how it is laid out, but the Models do not usually exist for the use of one Controller (or module in your case). For example - I have Models for Users, Companies, Vehicles, etc, etc. These models are a shared representation of my data structure and have nothing to do with modules as a user may see it looking at a web page. I can't split them in to modules because the whole point is that they are shared by the entire application.
So...in reality it is the Views which can get a bit messy, but they are already split in to folders based on their Controller. Having said that you can move them around a bit if that suits your needs better. For the rest of it there is no need, either because you shouldn't if you want to use 'proper' MVC (i.e. modular Models) or there's no need (i.e. only one Controller). And if your controller gets too big just create a separate module for any functionality in that you want to split out. I reckon that's as modular as you should ever need to get.
I found a relatively simple solution that uses IIS configuration to simulate areas. No extensions to the existing MVC framework are needed.
Create a new MVC project under your solution for each area you want in your site (ex. Root, Blog, Forum, App1, App2). If you need any common supporting code or a common model, put it in a seperate dll project that the MVC projects depend on.
In IIS, configure the site root to point at the root project directory. Create web applications under the site root that point to each of the sub-area project directories.
When configuring the route maps for each sub area, don't include the name of the application in the route. IIS seems to take care of this for you. (ex. "ShowPost/{postname}", not "/Blog/ShowPost/{postname}")
The benefit is that you can change the name of the web applications independent of the routing system, and each application believes it is running with the whole server to itself.