从数据库加载ASP.NET MVC视图和控制器代码

时间:2019-08-21 12:03:44

标签: asp.net-mvc razor model-view-controller virtualpathprovider

我有一个系统,最终用户是开发人员,可以创建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)的视图,并请求以下网址:

  

http://localhost:1001/qzone/test/TestView

我收到此错误

enter image description here

我想这意味着控制器工厂工作正常,但视图未加载

有什么想法吗?

1 个答案:

答案 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,则可能不适用。