Ошибка синтаксического анализатора: не Мог загрузить тип "x" из appdomain из виртуального каталога в IIS7

Так мои сценарии, немного забавные, но существует причина его.

У меня есть родительское веб-приложение, названное Родителем и вторым веб-приложением под названием Ребенок. Ребенок является виртуальным каталогом в IIS7 под Родителем, который является приложением в IIS. Ребенок не является дочерним каталогом родителя в файловой системе, только в IIS как виртуальный каталог. На загрузке приложения (Application_Start в global.asax) в родительском веб-приложении я говорю этому загружать дочернюю сеть dlls из childs папки мусорного ведра с помощью блока. LoadFrom () загрузка его в домен приложения Родителя. Затем, когда я пытаюсь посетить/Child/Default.aspx, я получаю ошибку при высказывании:

Ошибка синтаксического анализатора

Сообщение об ошибке синтаксического анализатора: не Мог загрузить тип 'Ребенок. _ Значение по умолчанию'.

Теперь Child.dll (сеть dll содержащий childs код позади и т.д.) находится в домене приложения родительского приложения, и я могу успешно отразить его и его участников из кода позади на странице Parent Default.aspx.

Кроме того, на Child/Default.aspx, если я изменяю Наследовать = "Ребенок. _ Значение по умолчанию" к Наследовалось = "Система. Сеть. UI.Page" и затем в <% %> наклеивает страницу, перечисляют dlls в домене приложения i, видят Child.dll и отражают его участников и вызывают функции.

Одна вещь, которая работы изменяют CodeBehind на CodeFile в директиве страницы. Затем страница анализирует правильно. Однако это только работает, когда веб-сайты находятся в нескомпилированном, не опубликованной форме.

1
задан Peter Short 4 August 2010 в 16:40
поделиться

1 ответ

Что происходит, так это то, что домен приложения не просматривает свой список сборок, когда пытается разрешить сборку «Дочерняя» для страницы в дочернем проекте.

Что вам нужно сделать, так это использовать обработчик событий AssemblyResolve в домене приложений. Вы можете сделать это следующим образом:

Сначала мы создаем класс AssemblyLoader:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Reflection;
using System.IO;

namespace Parent
{
    internal class AssemblyLoader
    {
        private static List<AssemblyInformation> virtualDirectoryAssemblies = new List<AssemblyInformation>();
        private static readonly string virtualDirectoryBinFolderFormatString = "~/{0}/bin/";
        private static readonly string[] pathSplitParams = new string[1] { "\\" };
        private static readonly string[] assemblyNameSplitParams = new string[1] { "," };

        internal static Assembly AssemblyResolve(object sender, ResolveEventArgs e)
        {
            var name = e.Name.Split(assemblyNameSplitParams, StringSplitOptions.RemoveEmptyEntries).First();
            if (!virtualDirectoryAssemblies.Exists(a => a.Name.Equals(name)))
                return null;

            return Assembly.LoadFrom(virtualDirectoryAssemblies.Single(a => a.Name.Equals(name)).Path);
        }

        internal static void LoadVirtualDirectories(List<string> virtualDirectories)
        {
            foreach (var v in virtualDirectories)
            {
                var path = HttpContext.Current.Server.MapPath(string.Format(virtualDirectoryBinFolderFormatString, v));
                AppDomain.CurrentDomain.AppendPrivatePath(path);
                AppDomain.CurrentDomain.SetShadowCopyPath(path);

                var assemblies = Directory.GetFiles(path, "*.dll", SearchOption.AllDirectories).ToList();
                foreach (var a in assemblies)
                {
                    var name = a.Split(pathSplitParams, StringSplitOptions.RemoveEmptyEntries).Last().Replace(".dll", string.Empty);
                    if(!virtualDirectoryAssemblies.Exists(i => i.Name.Equals(name)))
                    {
                        virtualDirectoryAssemblies.Add(new AssemblyInformation
                        {
                            Name = name,
                            Path = a
                        });
                    }
                }
            }
        }

        class AssemblyInformation
        {
            public string Name { get;set; }
            public string Path { get; set; }
        }
    }
}

В файле web.config для родительского проекта я добавил это (если у вас больше виртуальных каталогов, идея состоит в том, чтобы иметь список, разделенный запятыми. ):

<appSettings>
    <add key="VirtualDirectories" value="Child"/>
</appSettings>

В web.config дочернего проекта вы добавляете эту ссылку на сборку Дочерняя сборка:

<system.web>
    <compilation>
        <assemblies>
            <add assembly="Child, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
        </assemblies>
    </compilation>
</system.web>

Это также может быть так:

<system.web>
    <compilation>
        <assemblies>
            <add assembly="Child"/>
        </assemblies>
    </compilation>
</system.web>

Теперь, последнее, но не менее важное, мы помещаем это в Global.asax:

    protected void Application_Start(object sender, EventArgs e)
    {
        AppDomain.CurrentDomain.AssemblyResolve += AssemblyLoader.AssemblyResolve;

        var virtualDirectories = 
            ConfigurationManager.AppSettings.Get("VirtualDirectories").Split(new string[1] { "," }, StringSplitOptions.RemoveEmptyEntries).ToList();

        AssemblyLoader.LoadVirtualDirectories(virtualDirectories);
    }

И мы закончили ...: P

2
ответ дан 2 September 2019 в 22:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: