Загрузка кода представлений и контроллеров ASP.NET MVC из базы данных

У меня есть система, в которой конечный пользователь является разработчиком, который может создавать представления / контроллеры 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: зарегистрируйте фабрику контроллеров и поставщик виртуального пути в файле _6 _ **:

HostingEnvironment.RegisterVirtualPathProvider(new QS_VirtualPathProvider());
        ControllerBuilder.Current.SetControllerFactory(new QS_DynamicControllerFactory());

тестирование кода, чтобы проверить код выше, я добавил контроллер с именем (test) и представление с именем (testView.cshtml) в базу данных и запросил URL-адрес ниже:

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

и я получил эту ошибку

введите описание изображения здесь

Я предполагаю, что это означает, что фабрика контроллеров работала нормально, но представление не было загружено

Любые идеи?


person Abd-elhameed Quraim    schedule 21.08.2019    source источник


Ответы (1)


Это потому, что он ищет ваш взгляд на жестком диске. Механизм просмотра использует VirtualPathProviders для разрешения ваших представлений, поэтому вам нужно написать свой собственный VirtualPathProvider и зарегистрировать его.

Вы можете найти документацию здесь: https://docs.microsoft.com/en-us/dotnet/api/system.web.hosting.virtualpathprovider?view=netframework-4.8

К сожалению, я не могу скопировать здесь слишком много кода, но вы можете найти там полный пример. Имейте в виду, что пример для .NET 4.8, поэтому, если вы используете Core, это может быть неприменимо.

person Steven Lemmens    schedule 21.08.2019
comment
вот что я сделал, я создал собственный VirtualPathProvider. он показан в вопросе QS_VirtualPathProvider и также зарегистрирован. кроме того, я следовал образцу MSDN. - person Abd-elhameed Quraim; 21.08.2019
comment
Можете ли вы убедиться, что ваш провайдер виртуального пути вызывается, поставив точку останова в код? - person Steven Lemmens; 22.08.2019
comment
он вызывается, а также вызывается фабрика контроллеров, но, насколько я вижу, метод (FileExists) вызывается снова и снова, даже если файл найден - person Abd-elhameed Quraim; 22.08.2019
comment
Хорошо, а содержимое переменной заполнено правильно? Так что Exists определенно правда? - person Steven Lemmens; 22.08.2019
comment
Я пробовал оба метода, один для возврата true дает ошибку 404, а возврат false дает ошибку в вопросе выше - person Abd-elhameed Quraim; 23.08.2019