The goal is to create ASP.NET MVC Plugins. I have it all working as I want, except I cannot get different versions of the same plugin to play nicely together when it comes to the Views. Everything else is working fine; including paths to the different views.
Each plugin has 2 projects, a class library, and a web project that references the class library.
In the web project I have this view:
@model MyPluginClass
<p>Hello from the View</p>
But when running the view, I get
The type 'MyPluginClass' exists in both 'MyCompany.Plugin.Default.v1.0, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' and 'MyCompany.Plugin.Default.v1.1, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null'
To get the different view paths to exist for each version, I created a custom
PluginRazorViewEngine that inherits from RazorViewEngine
public PluginRazorViewEngine(PluginType pluginType, string pluginCode, decimal version, IViewPageActivator viewPageActivator) : base(viewPageActivator)
{
var viewLocationPrefix = "~/Plugins/";
viewLocationPrefix += pluginCode + " v" + version.ToString("N1");
ViewLocationFormats = new[]
{
viewLocationPrefix + "/Views/{1}/{0}.cshtml",
viewLocationPrefix + "/Views/Shared/{0}.cshtml"
};
MasterLocationFormats = new[]
{
viewLocationPrefix + "/Views/{1}/{0}.cshtml",
viewLocationPrefix + "/Views/Shared/{0}.cshtml"
};
PartialViewLocationFormats = new[]
{
viewLocationPrefix + "/Views/{1}/{0}.cshtml",
viewLocationPrefix + "/Views/Shared/{0}.cshtml"
};
FileExtensions = new[]
{
"cshtml"
};
}
The plugins must be loaded in a Plugins Folder structure in the website as follows
Plugins/Default v1.0/ dlls go here
Plugins/Default v1.0/Views
Plugins/Default v1.1/ dlls go here
Plugins/Default v1.1/Views
I use a PostApplicationStartMethod
to then load the view engine
var engine = new PluginRazorViewEngine(PluginType.Label, Settings.PluginCode, Settings.Version);
ViewEngines.Engines.Add(engine); // want to add the engine to the end not the start
var routeNamePrefix = Settings.PluginCode + "_v" + Settings.Version.ToString("N1") + "_";
var routePrefix = Settings.PluginCode + "/" + Settings.Version.ToString("N1") + "/";
RouteTable.Routes.MapRoute(
routeNamePrefix + "Default",
routePrefix + "{controller}/{action}/{id}",
new
{
action = "Index",
id = UrlParameter.Optional
},
new[] { "MyCompany.Plugin.Default.Web.Controllers" }
);
NOTE: I loaded this using reflection from the class library, as again the PostApplicationStartMethod
played happily with the class library, but on the web project the PostApplicationStartMethod
always ended up referencing the v1.0 assembly and v1.1 assembly got ignored.
It is like class libraries work with versioning and web projects just do not.
Anyhow, is there any way of getting the RazorViewEngine to use the correct assemblies for each version short of changing the namespaces?
I thought of using RazorGenerator, but the virtual paths don't work with what I want to do.
And am not sure if Signing the assembly would solve all problems. But if I went down that route, it looks like I would need to strongly sign all the projects which am not that keen to do.
To version the assemblies, I am changing the assembly name MyCompany.Plugin.Default.Web.v1.1 and the assembly version and file version to 1.1.0.0
Any thoughts?