【问题标题】:How can I have the entry point to a .NET Core program be in a NuGet package it references如何将 .NET Core 程序的入口点放在它引用的 NuGet 包中
【发布时间】:2019-03-26 22:16:45
【问题描述】:

我正在构建一个作业运行系统,其中有一个 .NET Core 控制台应用程序作为作业运行器,以及用户可扩展的作业 - 用户可以引用我的 NuGet 包,编写一个扩展我的作业类型的类,并实现执行方法。我想在 NuGet 包中提供所有控制台逻辑,这样引用它就可以构建一个可立即运行的控制台应用程序。我已经能够使用 NuGet 发布构建应用所需的构建目标,但我正在寻找一种方法来实际加载作业 dll。

我目前的解决方案是:

  1. Job-runner 通过反射加载其工作目录中的所有 dll
  2. Job-runner 检查所有这些 dll 中是否有实现所需类型的 dll
  3. Job-runner 创建作业类型的实例并执行作业

我想避免第 1 步,如果 NuGet 包只是为控制台应用程序提供了一个入口点,我相信我可以做到这一点。是否可以构建一个没有入口点的控制台应用程序并通过 NuGet 提供它,或者使用类库并将所有必需的 dll 加载到一个应用程序域中?

【问题讨论】:

    标签: c# reflection .net-core nuget clr


    【解决方案1】:

    你愿意为此付出多少努力?

    Windows 知道可执行文件的入口点在文件 PE 标头中 _IMAGE_OPTIONAL_HEADER 结构的 AddressOfEntryPoint 字段中的方式。我不是专家,但我相信 dotnet CLI 也使用它。由于 AddressOfEntryPoint 字段只是文件中的一个字节偏移量,因此不可能将入口点放在不同的文件中。

    它可以工作的一种方式(我没有测试过)是如果你的工作运行者是 nupkg 中的 exe,而不是 dll。这样,当每个作业构建时(如果需要,也使用 dotnet cli,也已发布),输出文件夹将包含正在运行的作业运行程序 exe。作业本身可以是一个 dll,因此它不需要自己的入口点。但是你的工作运行者仍然需要使用反射来加载所有程序集,我同意这是一个坏主意。它还阻止 dotnet run 处理作业任务项目,这使得执行作业的人员调试更加困难。

    另一种选择是告诉作业任务实现者在他们的 exe 中包含一行 Main 方法

    public static void Main()
    {
      JobRunner.Run();
    }
    

    这也需要 JobRunner 使用反射来查找作业,但至少您可以使用 Assembly.GetCallingAssembly()Assembly.GetEntryAssembly() 来避免加载所有 dll。您可以将JobRunner.Run() 更改为JobRunner.Run(Type)JobRunner.Run<T>() where T : IJob,以便作业实施者准确地告诉作业运行者在他们自己的 Main 方法中运行哪个作业,并避免在作业运行器中执行第 2 步。它类似于 ASP.NET Core 应用程序有一个相似的(如果不完全相同的话)Program.Main,所以它并不是前所未有的。

    如果您想让您的工作实施者尽可能轻松,您可以从 .NET Core 如何在 obj/$(Configuration)/ 文件夹中创建临时 .cs 文件中获得灵感。创建您的 nuget 包 with the appropriate msbuild .targets file 并让您的自定义 msbuild 目标文件在包含 Main() 入口点的 obj 文件中创建另一个临时 .cs 文件,并包含 .cs 文件以进行编译。

    为了获得额外的功劳,您可以使用 Roslyn 分析项目中的所有非临时 .cs 文件,找到所有作业,然后在生成的 .cs 文件中使用检测到的类型调用 JobRunner 的 Main 方法,所以在运行时它不需要使用反射来执行第 2 步。

    【讨论】:

    • 我的团队愿意付出多少努力?没有那么多。为了找到一个简洁的解决方案,我想要付出多少努力?相当多。感谢您涵盖所有基础
    • 仅供参考,我找到了有关在您的 nupkg 中包含 msbuild 目标/道具的文档。我已经编辑了答案以添加链接。
    【解决方案2】:

    如果我正确理解你有以下项目:

    • Runner - 用于执行作业
    • JobTypeBaseClass - 可由 Jobs(定义如下)和 Runner 使用的通用类
    • 作业 - 执行不同开发人员定义的工作的任务

    目前 Jobs 正在使用其中定义的反射执行工作来引用 JobTypeBaseClass 和 Runner。 这是正确且广为人知的方法。

    但我理解您的目标是为将创建工作的开发人员提供一种非常容易开始工作的方式。所以他们应该引用 nuget,就像它应该工作一样。

    回答您的问题:没有入口点就无法构建控制台应用程序,因此没有静态 Main 方法。但是您可以使用此要求。在 nuget 文件中,您可以添加将更改 Program.cs 文件的 Main 方法的安装脚本并添加将调用所需代码的行。

    这种方式在安装 nuget 作业后将起作用。当然它不会做任何事情。

    所以你的 nuget 应该:

    • 包含 JobTypeBaseClass
    • 包含将创建新 Job.cs 文件的脚本,该文件将是从 JobTypeBaseClass 实现基类的类
    • 包含将更改 Program.cs 中的 Main 方法的脚本,该方法将调用上面创建的方法。

    【讨论】:

    • 原帖明确表示.NET Core。 .NET Core只支持PackageReference,不支持packages.config,相信nupkg中的install.ps1只有在使用package.config时才会执行。
    猜你喜欢
    • 1970-01-01
    • 2021-09-02
    • 1970-01-01
    • 2018-10-22
    • 2019-01-26
    • 2021-08-14
    • 1970-01-01
    • 2017-05-29
    • 1970-01-01
    相关资源
    最近更新 更多