Проблема взята из этой проблемы 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()'.