我有一个系统,最终用户是开发人员,可以创建ASP.NET MVC视图/控制器并即时运行它们。
当前,我有两个数据库表,一个用于存储视图名称和代码,另一个用于在C#中存储控制器代码。我可以编译生成程序集并将dll文件保存在服务器文件夹中。
第1步:我添加了一个自定义控制器工厂以从数据库中加载控制器,在项目中有一个区域名为( 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);
}
}
第2步:我创建了 VirtualPathProvider VirtualFile
QS_VirtualPathProvider
类:
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
类:
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);
}
}
步骤3 :在Global.asax
**文件中注册控制器工厂和虚拟路径提供程序:
HostingEnvironment.RegisterVirtualPathProvider(new QS_VirtualPathProvider());
ControllerBuilder.Current.SetControllerFactory(new QS_DynamicControllerFactory());
测试代码 为了测试上面的代码,我在数据库中添加了一个名为(test)的控制器和一个名为(testView.cshtml)的视图,并请求以下网址:
我收到此错误
我想这意味着控制器工厂工作正常,但视图未加载
有什么想法吗?
答案 0 :(得分:0)
那是因为它正在寻找您在硬盘上的视图。 View Engine使用VirtualPathProviders
来解析您的视图,因此您需要编写自己的VirtualPathProvider
并注册它。
您可以在这里找到文档: https://docs.microsoft.com/en-us/dotnet/api/system.web.hosting.virtualpathprovider?view=netframework-4.8
不幸的是,对于我来说,在这里复制太多代码,但是您可以在此处找到完整的示例。 请注意,该示例适用于.NET 4.8,因此,如果您使用的是Core,则可能不适用。