I have a system in which the end-user is a developer who can create ASP.NET MVC views/controllers and run them on the fly.
Currently, I have two database tables, one to store the view name and code and other to store controller code in C#. I can compile the build an assembly and save a dll file on the server folder.
Step 1: I added a custom controller factory to load my controller from the database, having an area in the project named (QZone).
public class QS_DynamicControllerFactory : DefaultControllerFactory//, IController
{
QS_DBConnection _db = new QS_DBConnection();
public QS_DynamicControllerFactory() { }
public override IController CreateController(RequestContext requestContext, string controllerName)
{
return (requestContext.RouteData.DataTokens["area"] != null &&
requestContext.RouteData.DataTokens["area"].ToString().ToLower() == "qzone") ?
QGetControllerInstance(controllerName) : base.CreateController(requestContext, controllerName);
}
internal IController QGetControllerInstance(string controllerName)
{
//load controller from the database and compile it then return an instance
}
public override void ReleaseController(IController controller)
{
base.ReleaseController(controller);
}
}
Step 2: I created a VirtualPathProvider, VirtualFile
QS_VirtualPathProvider
class:
public class QS_VirtualPathProvider : VirtualPathProvider
{
public QDynamicView GetVirtualData(string viewPath)
{
QS_DBConnection _db = new QS_DBConnection();
QDynamicView view = (from v in _db.QDynamicViews
where v.Name.ToLower() == "TestView.cshtml".ToLower()//viewPath.ToLower()
select v).SingleOrDefault();
return view;
}
private bool IsPathVirtual(string virtualPath)
{
var path = (VirtualPathUtility.GetDirectory(virtualPath) != "~/") ? VirtualPathUtility.RemoveTrailingSlash(VirtualPathUtility.GetDirectory(virtualPath)) : VirtualPathUtility.GetDirectory(virtualPath);
if (path.ToLower().Contains("/qzone/"))
return true;
else
return false;
}
public override bool FileExists(string virtualPath)
{
if (IsPathVirtual(virtualPath))
{
QS_VirtualFile file = (QS_VirtualFile)GetFile(virtualPath);
bool isExists = file.Exists;
return isExists;
}
else
return Previous.FileExists(virtualPath);
}
public override VirtualFile GetFile(string virtualPath)
{
if (IsPathVirtual(virtualPath))
{
QDynamicView vw = GetVirtualData(virtualPath);
var bytes = Encoding.ASCII.GetBytes(vw.ViewCode);
return new QS_VirtualFile(virtualPath, bytes);
}
else
return Previous.GetFile(virtualPath);
}
public override CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
{
if (IsPathVirtual(virtualPath))
{
return null;
}
else
return Previous.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
}
public override string GetFileHash(string virtualPath, IEnumerable virtualPathDependencies)
{
if (IsPathVirtual(virtualPath))
return Guid.NewGuid().ToString();
return base.GetFileHash(virtualPath, virtualPathDependencies);
}
}
QS_VirtualFile
class:
public class QS_VirtualFile : VirtualFile
{
private string content;
private QS_VirtualPathProvider spp;
public bool Exists
{
get { return (content != null); }
}
public QS_VirtualFile(string virtualPath, QS_VirtualPathProvider provider) : base(virtualPath)
{
this.spp = provider;
GetData(virtualPath);
}
public QS_VirtualFile(QDynamicView vw, string virtualPath) : base(virtualPath)
{
content = vw.ViewCode;
}
private byte[] _BinaryContent;
public QS_VirtualFile(string virtualPath, byte[] contents) : base(virtualPath)
{
this._BinaryContent = contents;
}
protected void GetData(string virtualPath)
{
QDynamicView QSView = spp.GetVirtualData(virtualPath);
if (QSView != null)
{
content = QSView.ViewCode;
}
}
public override Stream Open()
{
return new MemoryStream(_BinaryContent);
}
}
Step 3: register the controller factory and the virtual path provider in the in Global.asax
** file:
HostingEnvironment.RegisterVirtualPathProvider(new QS_VirtualPathProvider());
ControllerBuilder.Current.SetControllerFactory(new QS_DynamicControllerFactory());
testing the code in order to test the code above i added a controller named (test) and a view named (testView.cshtml) in the database and requested the url below:
and I got this error
I guess this mean that the controller factory worked fine but the view was not loaded
Any ideas?