Lately my focus has been on creating an ASP.NET MVC application that can host 3rd party MVC plugins. Ideally, development of those plugins would follow these rules:
After some research I've come up with the following approaches to achieve this, each with their own advantages and disadvantages.
Work Flow
PreApplicationStartMethodAttribute
, MEF or a basic assembly reference within the host project (if possible).Area
within the host.Advantages
PreApplicationStartMethodAttribute
, project reference) and after application start (MEF)Disadvantages
Conclusion
This is the easiest approach, however it is also the least secure. It essentially removes the possibility of allowing untrusted developers to create plugins because those plugins will have the same trust level as the host application (meaning that if the host application can execute methods such as System.IO.File.Delete
, so can the plugin)
This approach intends to allow the creation of MVC plugins that can be sandboxed into their own AppDomains
and used by the host via the System.Addin
libraries.
Structure
A route is setup in the host that determines whether the url being processed is targeting a plugin. May have a pattern such as example.com/p/{plugin}/{controller}/{action}/{id}
All routes that have the above pattern are mapped to a host controller that has a module routing action. That action looks at any given route and determines the appropriate plugin to process the request based on the {plugin}
segment.
The plugin view is a receiver/sender object that acts as a gateway to the plugin controllers. It has a method called AcceptRequest that receives a RequestContext
from the host, and that returns an ActionResult
.
The plugin pipeline contains adapters that can serialise RequestContext
and ActionResult
for transmission across the isolation boundary of the pipeline.
Execution Flow
A route for a plugin is matched and the plugin routing controller is called.
The controller loads the required plugin into it's own AppDomain
and calls AcceptRequest, passing through the RequestContext
(which is serialised via the pipeline)
AcceptRequest receives the context and determines the appropriate controller to execute based on that request (using a custom controller factory).
Once the controller has finished executing the request, it returns an ActionResult
to the receiver object which then passed that ActionResult
(also serialised via the pipeline) back to the host AppDomain
.
The controller that initially called AcceptRequest can then return the ActionResult
to the host MVC execution pipeline, as if it processed the request itself. The plugin AppDomain
can then be unloaded if so wished.
Advantages
Plugin will be sandboxed in it's AppDomain
, thus any permission set can be used that suits the host.
Disadvantages
RequestContext
and ActionResult
.AppDomain
.Conclusion
This approach sounds good on paper, but I'm not sure if it's possible/feasible to serialise the RequestContext
and ActionResult
objects, as well as run an MVC controller in isolation.
The first approach is fine if the code is being created by trusted developers. I know that I'm not going delete all the host view files or it's web.config file. But ultimately, if you want third party devs to create plugins for your MVC app, you need to be able to sandbox their code.
From all my research, the System.Addin
library makes it easy to implement a host/plugin environment when you are using simple API based class libraries. However it seems that it isn't easy to do this when MVC is involved.
Some questions I have are:
ASP.NET will see the cookie and know that the user is already authenticated and does not need to sign on again. Note: Word of warning, SSL is required to make Forms authentications secure. If you are running the application over http, anybody snooping the network can see the users credentials.
The ASP.NET MVC plugins is actually a extension based on another plugin framework OSGi.NET, technically, you can replace it with any other frameworks like MEF, Sharp-develop with some wrapping.
The plugin framework is a NuGet package that allows you to customise and extend a . NET application at runtime. Code examples are provided for ASP.NET Core, Blazor, Console Apps and WPF & WinForms. The plugin framework package can be installed from NuGet and also supports the delivery of plugins from NuGet.
You're going to end up making separate sites for each plugin. This way you can create reduced-privilege users for each AppPool and a systems administrator can install the "plugin" as a website running under that user.
Any alternatives are going to exhibit the Inner Platform antipattern. Unless you have a lot of time and money to spend developing a plugin-hosting system, you're going to become mired in it and resent it. I speak from experience.
The sites can share AspnetIdentity user repos and you can provide your core objects as a dll that can be referenced. Host your content (script files, css, images) on a CDN so they can be referenced. If you want to share views with your child sites, compile them in as resources:
Including Pre-Compiled Views in an ASP.NET MVC Web Application
Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With