如何在当前应用程序域中加载另一个程序集?

时间:2018-06-27 23:11:07

标签: .net asp.net-core appdomain

问题摘自this的github问题,并且与使用另一个程序集中的WebHost构建Startup有关。

在通过.Build()配置的IWebHostBuilder上调用WebHostBuilderExtensions.UseStartup(this IWebHostBuilder hostBuilder, Type startupType)时,其中startupType是通过其字符串从单独的.exe程序集中检索的System.InvalidOperationException: 'Unable to resolve service for type 'Microsoft.Extensions.Configuration.IConfiguration' while attempting to activate 'WebAppWithAfterBuildTarget.Startup'.',在依赖注入时失败时间。

对于默认的ASP.NET Core + .NET Framework项目,将引发以下情况: Microsoft.Build.[Framework/Utilities.v4.0]

最小复制步骤

创建一个面向net462的名为“ MsBuildTask”的简单库项目。

添加对Microsoft.AspNetCore程序集的引用,以及对.Http.Abstractions + 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; } } nuget的引用。

像这样创建一个类:

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

构建MsBuildTask项目,将路径复制到dll输出(用于下面)。

在Visual Studio中创建一个ASP.NET Core 2.0 + .Net Framework 462项目。

在webapp csproj文件中,添加

AfterBuild

构建Web应用程序。 (出于调试目的,您可以在MsBuildTask> Properties> Debug中将Launch设置为可执行文件,将Executable设置为msbuild的路径,将Application参数设置为Webapp的路径,然后在MsBuildTask上按F5键)。 预期结果 构建任务将成功完成,我们可以与主机做更多有趣的事情。

实际结果 请注意,在MsBuildTask.RunStartup.Execute目标部分中,运行.Build()方法。

由于尚未注册IConfiguration,因此在AspNetCore.Mvc阶段失败。

更多技术细节 我尝试将启动程序复制到该项目(根据需要添加.UseStartup<Startup>() nuget)并像在普通的ASP.NET Core应用程序中那样运行CreateDefaultBuilder(),此操作成功。正是在按名称引用程序集时,我遇到了似乎未注册依赖项的错误。


在此方面有更多进展: 在我的asp.net核心项目中,我公开了一个Build()方法,该方法调用与上述相同的方法,但是使用正确的类型上下文。然后,我通过反射对返回的对象调用Execute()。这表明某些依赖项版本不匹配。我通过在 AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(OnResolve); 方法的开头添加以下内容来解决这些问题:

    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;
    }

具有这样定义的OnResolve,本质上是迫使dll从我的asp.net核心项目的bin目录中加载

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()'.

但是由于某些原因,它似乎由于以下异常而失败:

SELECT `id`, `market_id`, `sector_id`, `symbol`, `name_en`, `name_ar`, `price`, `per`, `num_followers`, `num_posts`, `company_id`, `msgTrend`, `date` 
From 
(
SELECT `ticker_id`, `date`, COUNT(*) AS `msgTrend`
FROM `post_ticker` AS `mt` 
INNER JOIN `post` AS `p` ON `post_id` = `p`.`id` 
WHERE `ticker_id` IN (SELECT `id` FROM `ticker` WHERE `sector_id`!=0 AND `market_id`!=0) 
AND `date`>=DATE_SUB((SELECT `date` FROM `post_ticker` INNER JOIN `post` AS `p` ON `post_id` = `p`.`id` ORDER BY `date` DESC LIMIT 1), INTERVAL 1 day) 
GROUP BY `ticker_id`
) AS `mentioned_ticker`

INNER JOIN `ticker` on `ticker_id`=`id` 
ORDER BY `msgTrend` DESC, `date` DESC 
Limit 4

0 个答案:

没有答案