Как загрузить другую сборку в текущем домене приложения? - PullRequest
0 голосов
/ 28 июня 2018

Проблема взята из этой проблемы github и связана конкретно со сборкой WebHost с использованием Startup из другой сборки.

Вызов .Build() для IWebHostBuilder, настроенного через WebHostBuilderExtensions.UseStartup(this IWebHostBuilder hostBuilder, Type startupType), где startupType извлекается из отдельной сборки .exe через его строку. Имя сборки не выполняется во время внедрения зависимости.

В проекте ASP.NET Core + .NET Framework по умолчанию выбрасывается следующее: System.InvalidOperationException: 'Unable to resolve service for type 'Microsoft.Extensions.Configuration.IConfiguration' while attempting to activate 'WebAppWithAfterBuildTarget.Startup'.'

Минимальные шаги репро :

Создайте простой библиотечный проект с именем «MsBuildTask», ориентированный на net462.

Добавить ссылку на Microsoft.Build.[Framework/Utilities.v4.0] сборки и ссылку на Microsoft.AspNetCore + .Http.Abstractions nugets.

Создайте класс примерно так:

public class RunStartup : Microsoft.Build.Utilities.Task
{
    public string AssemblyToLoad { get; set; }

    public override bool Execute()
    {
        var startupAssembly = Assembly.LoadFrom(Path.Combine(Directory.GetCurrentDirectory(), AssemblyToLoad));
        var builder = WebHost.CreateDefaultBuilder();
        builder.UseStartup(startupAssembly.FullName);
        var host = builder.Build();

        // ... do more stuff
        return true;
    }
}

Создайте проект MsBuildTask, скопируйте путь к выводу dll (используется ниже).

Создание проекта ASP.NET Core 2.0 + .Net Framework 462 в Visual Studio.

В файле webapp csproj добавьте

<UsingTask AssemblyFile="..\MsBuildTask\bin\Debug\net462\MsBuildTask.dll" TaskName="RunStartup" />
<Target Name="RunStartup" AfterTargets="AfterBuild">
  <RunStartup AssemblyToLoad="$(OutputPath)$(AssemblyName).exe" />
</Target>

Создайте веб-приложение. (для целей отладки в MsBuildTask> Свойства> Отладка вы можете установить Launch в качестве исполняемого файла, Executable в качестве пути к msbuild и Application аргументы в качестве пути к веб-приложению, а затем просто нажмите F5 в MsBuildTask). Ожидаемый результат Задача сборки была бы успешно завершена, мы могли бы сделать более интересные вещи с хостом.

Фактический результат Обратите внимание, что во время раздела целей AfterBuild выполняется метод MsBuildTask.RunStartup.Execute.

Сбой на этапе .Build(), так как IConfiguration не зарегистрирован.

Дополнительные технические детали Я попытался скопировать автозагрузку в этот проект (при необходимости добавив nuget AspNetCore.Mvc) и запустить .UseStartup<Startup>() как в обычном приложении ASP.NET Core, и это успешно. При обращении к сборке по имени я сталкиваюсь с этой ошибкой, когда зависимости, кажется, не регистрируются.


Так что немного больше прогресса с этим: В моем основном проекте asp.net я раскрыл метод CreateDefaultBuilder(), который вызывает те же методы, что и выше, но с использованием правильного контекста типа. Затем я вызываю Build() на возвращенный объект через отражение. Это показало некоторые несоответствия версий зависимостей. Я обошел их, добавив следующее в начале моего Execute() метода:

        AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnResolve);

с OnResolve, определенным так, что заставляет dll загружаться из каталога bin моего основного проекта asp.net

    private Assembly OnResolve(object sender, ResolveEventArgs args)
    {
        String currentFolder = Path.Combine(Directory.GetCurrentDirectory(), AssemblyToLoad);
        AssemblyName requestedName = new AssemblyName(args.Name);
        var resolvedAssembly = Assembly.LoadFrom(Path.Combine(currentFolder, requestedName.Name + (requestedName.Name == this.AssemblyName ? ".exe" : ".dll")));
        if (resolvedAssembly.GetName().Version < requestedName.Version)

        {
            return null;
        }

        return resolvedAssembly;
    }

Однако по какой-то причине это, по-видимому, завершается ошибкой:

System.Reflection.TargetInvocationException
  HResult=0x80131604
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
   at Swashbuckle.AspNetCore.MSBuild.SwaggerGenerator.Execute() in C:\dev\Swashbuckle.AspNetCore\src\Swashbuckle.AspNetCore.MSBuild\SwaggerGenerator.cs:line 42
   at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
   at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__26.MoveNext()

Inner Exception 1:
MissingMethodException: Method not found: 'Newtonsoft.Json.JsonSerializerSettings Microsoft.AspNetCore.Mvc.MvcJsonOptions.get_SerializerSettings()'.
...