I'm fairly decent with MVC3 and enjoy creating my sites with it, however, I am yet to think up and implement a decent method of a "plugin" system.
Basically, I aim to have a generic "blog-type" CMS which I can distribute across my sites, but with the option to have certain things as plugins.
For example:
Generic build:
User area
Basic blog/news editing
Plugins: (May be needed for one or two sites, but not all)
Chatroom plugin
Stats
and so on...
Currently I would just make it all and disable things through a config file, however it would be nice if i could just drop a folder into my FTP and have an MVC page which automatically picks it up!
I assume I would have to start with scanning the directory "/plugins" and picking up a "plugin.config" (Or similar) file which would contain the basic details.
But how would I get my main system to pick these things up and actually use them?!
You may be able to do this using MVC Areas, here are some links about them:
ASP.NET MVC 2 Areas
ASP.NET MVC Areas: Are they important to a large application?
https://stackoverflow.com/questions/462458/asp-net-mvc-areas-are-they-important-to-a-large-application
Try assembly scanning with StructureMap dependency injection.
Read this great tutorial: ASP.NET MVC2 Plugin Architecture Tutorial
It help me create a plugin architecture with MVC3.
Areas solve the problem for you providing you have everything in the original project/assembly. You could write your plugin system to allow the plugins to register their own areas, or alternatively you could register some new view search paths in a custom Razor view engine.
I chose the latter for a recent OS project I wrote called Spruce, which uses a whole plugin architecture you might find useful as a reference.
You can scan all the assemblies in the bin directory on startup to check for plugins, via reflection. You usually check for types that implement an interface or inherit from a class, and use these along side an IoC container such as TinyIoc, NInject, StructureMap or Unity. I'd recommend TinyIoC which is used by NancyFX.
Related
I am working on a multi-tenant MVC4 web portal that is meant to host dynamically generated MVC4 applications.
Use case: The client uses the web portal to upload a xml specification. The specification gets passed to a web service that generates an mvc4 application, compiles it and returns a zip file to the portal containing the views, css, javascript and a dll(compiled c# code). Then, the portal unzips the received zip file and places it's contents in a folder (Modules) inside the portal itself. Then the client can browse the newly 'deployed' application. Many versions of the same application can be deployed and I am planning to use different Namespaces for each deployment. Note: The generated modules have some dependencies that will be injected by the web portal using a DI injector (was thinking of using ninject)
I have done a lot of research on how to build a modular MVC application. I've looked at MVC Areas, done some research on MEF, DI frameworks, looked at nopCommerce and orchard code. One thing that I cannot seem to find an answer to is how to add the Modules at runtime without requiring an AppDomain restart? Also, is there an easy way to register routes for each of these modules at runtime?
I am trying to avoid app restarts because there may be other people using the portal/deployed modules while others are uploading new specifications.
Did you have a look on this (just very slightly outdated) Tutorial? It won't solve the problem of re-scanning the Modules, but the introduced PluginAreaBootstrapper class seems to be a good start. Maybe you would be able to run the PluginAreaBootstrapper's Init() method upon a specific Event in your System (let's call it OnNewModuleDeployed).
I've been struggling to do this in a way that fulfills all of my requirements.
Here is what we have in our library:
Base classes for controllers and services
Business objects (stores, departments, etc)
Common Partial Views (Login, Error, etc)
Base class for HttpApplication
General common code (read an INI file, create a db conn, etc)
The one requirement that has been giving me trouble is as follows:
Lives in one place on a server. (i.e. copy local = false)
This breaks because:
The DLL containing the HttpApplication class must be in the same directory as the web apps dll to launch. I haven't found a way around that. I'm ok with duplicating this code in every app, but would rather not.
The shared views don't like to work if I use Assembly.LoadFrom() to load the dll from the shared location. (I've been using this method to precompile my views)
Any namespace shortcuts in web.config break at runtime with compilation errors because the web.config is parsed before the assembly is loaded.
My question to you folks is how do you handle your common code in a similar environment?
The GAC seems to be more trouble than its worth, and we want all of our apps to be using the same code, and not have multiple apps on multiple versions and have to maintain all of that. Are there design patters/best practices that can guide us in this regard?
Also, as a bonus, if you can solve any of the problems above, that would be great, too.
Thanks!
Edit: I guess a question that follows is whether or not we should even have a directory with the common dll(s) on the server, or if they should only be deployed as projects are deployed/updated?
Firstly, you will want to separate out what you're trying to achieve. Don't create 1 library that does everything or you will have a Big Ball of Mud. Don't be afraid to create several maintainable libraries to achieve what you're after. Is there a specific reason it needs to be stored in one location?
For example, several of the items you mention are MVC or web specific. If you have items that can be reused by MVC, create a class library that contains MVC base classes you inherit and reference them in your project. Use the single responsibility principle as much as possible.
Regarding the other items you mentioned, like database connectivity, if it's reusable, abstract it out in a data access class library and reference it. Other simple operations like reading an ini file or creating a file, create another library and abstract it to easy to use methods.
I prefer to copy the library dlls locally. You never know when you will need to make changes to the library, but you don't want all of your projects to stop compiling. When you're ready to implement a new version of the library, copy the dll in and recompile.
Not sure why all the hate towards the gac. It was designed to handle this specific problem. Install your common dlls to the gac and all apps can see them. Need to deploy a new one, just re-install it in one place.
I'm creating a Service for my organization that will be installed on hundreds of computers. The Implementation of it may need to change over time. After watching and read a bit about MEF I'm still a little lost. Is MEF a good soulution for say if I wanted to Drop a dll into the service folder and have that service pick up the changes?
I have done quite a bit with MEF. Yes, MEF will do what you're looking for, with a caveat...
You can discover and load in a new DLL at runtime
However, it loads into the same App domain as your main application so,
You can't unload or change the DLL without restarting your application
If that last point is a problem, consider MAF (although it's much heavier). But in MAF, it will load your extensions into a separate app domain.
Your other option is just to spawn off another process to handle the request, and pass command line parameters to it.
if you are using VS2010 i recommend you try first Click Once. It gives you the setup.exe but also gives you an HTML file (and other files), wich you can upload to an IIS server or an FTP site, or even to a shared folder over your local network. The thing is, when you configure your deployment you can tell the installer to auto-update all clientes directly from the site (the HTML file, ftp or lan shared folder). When user starts the application it will connect to the site and ask for an update if it exists, and if it does, the application will self-update. If you want to deploy an update, you only need to upload again the HTML file and all other files in the folder.
Check out this links:
http://msdn.microsoft.com/en-us/library/ms953320.aspx
http://weblogs.asp.net/shahar/archive/2008/01/29/how-to-use-clickonce-to-deploy-your-applications.aspx
Happy coding ;)
I am no expert about MEF. Documentation says Mef is all about making plug-in based systems. so your system expects some interfaces and MEF makes easy to import classes implemented these interfaces to your system.your case seems suitable for this. MEF has directory catalog and by using catalogs you can import types/dlls runtime.
How do I get a MEF Directory catalog looking at the same directory for both the Servicelayer and DAL?
I think you can do this if you have your service logic in a separated class library and you got the needed contract interfaces in another class library. Then you can create a directory catalog and import your service implementation with MEF (you only need to reference to the contract interfaces assembly). Then you can pick up the new dll/service implementation if changed. You only need a directory watcher (FileSystemWatcher), then you have to call your catalog's refresh method when directory watcher fires. In theory it should work, but it's just an idea. :) Anyway, hope this helps.
You could also look into Prism. From what I understand, they are two different frameworks to do pretty much the same thing. Prism allows you to create modules by having a class in a dll that implements the IModule interface. You can just drag and drop dlls into a folder this way just like in MEF. You can statically or dynamically load modules, and do a bunch of other things I don't even know about.
Prism also has other features bundled with it, i.e. the Unity dependency injection container (which I like to call "The Magical Black Box"), a neat event and command system, etc. I'm sure MEF has all these things too.
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.
I have been using the Windsor IoC Container for my web-based application, to resolve the data access layer implementation the application should use.
The web application's UI will consist of pages, and each page consists of small units called portlets. (Their concept is somewhat similar to widgets.) These so-called portlets are basically web controls and can be configured in runtime for every page invidually.
The application will ship with some of these built-in, but I would like to enable extending it easily.
I figured out that this mechanism is exactly what MEF is built for. So I decided to implement the system in such a way that it discovers portlets using MEF. Then, I realized that it can also do what I currently use Windsor for, so I decided to ditch Windsor in favor of MEF.
Obviously, I will have to use the DirectoryCatalog, which scans for the .dlls in the app's bin folder and returns everything I need.
I read some tutorials, examples, and all questions regarding MEF in StackOverflow, as well. I figured that the easiest way to use MEF is through the PartInitializer which Glenn Block mentioned in his tutorials, but I realized that it is not in MEF. Actually, it is in the code I downloaded from CodePlex, but in a separate assembly, and only in source, not in binary form. (Does this mean that it isn't a part of MEF? Or what's the point in putting it to a separate project?)
Then, I realized that it is for Silverlight, so it doesn't really help me.
(Or should I just compile that against .NET 3.5, or include it in my project, and I'm good to go?)
So now I have a problem which is the following: where should I put the CompositionContainer in my application?
There is another thing I would like to consider: should I use only one CompositionContainer in the lifetime of the app, or I'm better off creating a container for every time when I need it?
Good questions.
In general in terms of questions about where to put the container, I recommend the following posts: http://blogs.msdn.com/nblumhardt/archive/tags/Container+Managed+Application+Design/default.aspx
In of MEF on the web, web-based apps are a bit tricker because of the request / response nature and scalability concerns. For web you would likely want to have a hierarchy of containers, one root one for the application which is shared, as well as child contianers per-request. The child containers should live and die with the request in order to conserve resources. The shared container contains services that are shared by all callers.
You might check out these articles for more insight into how to do this:
http://blogs.msdn.com/hammett/archive/2009/04/23/mef-and-asp-net-mvc-sample.aspx
http://blogs.msdn.com/hammett/archive/2009/07/15/mef-and-asp-net-mvc-sample-updated.aspx
http://mef.codeplex.com/wikipage?title=Parts%20Lifetime&referringTitle=Guide
As far as PartInitializer, I would avoid using something like it unless you have to. ASP.NET provides sufficient hooks in the pipeline through HTTP Handlers, modules and such to let automatically compose on creation.
The only place i would see using PI on the web would be possibly within a custom user control. PI ships as part of Silverlight 4 and is not available in the box for .NET 4.0. I have created a usable version for .NET 4.0 which you can find here: http://cid-f8b2fd72406fb218.skydrive.live.com/self.aspx/blog/Composition.Initialization.Desktop.zip
HTH
Glenn