Juxtapose 1.4.0

dotnet add package Juxtapose --version 1.4.0
NuGet\Install-Package Juxtapose -Version 1.4.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Juxtapose" Version="1.4.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Juxtapose --version 1.4.0
#r "nuget: Juxtapose, 1.4.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Juxtapose as a Cake Addin
#addin nuget:?package=Juxtapose&version=1.4.0

// Install Juxtapose as a Cake Tool
#tool nuget:?package=Juxtapose&version=1.4.0

Juxtapose

1. Intro

A multi process runtime library based on 'SourceGenerator'. 基于 SourceGenerator 的多进程运行库。

2. Features

  • 可以为类型接口静态类生成代理,无需手动编写RPC相关代码,即可多进程运行;
  • 编译时生成所有代码,运行时无显式的反射调用和动态构造;
  • 支持委托CancellationToken类型的方法参数(其余类型未特殊处理,将会进行序列化,目前回调委托不支持嵌套和CancellationToken);
  • 支持LinuxWindows(其它未测试);
  • 支持调试子进程(Windows&&VisualStudio Only);
  • AOT支持*(net8.0+);

注意事项

  • 目前参数不支持定义为父类型,实际传递子类型,序列化时将会按照定义的类型进行序列化和反序列化,会导致具体类型丢失;
  • 目前所有的参数都不应该在方法完成后进行保留,CancellationToken委托等在方法完成后会被释放;

3. Requirement

  • .Net6.0+(其它版本没有尝试过)

4. 使用方法

4.1 引用包

<ItemGroup>
  <PackageReference Include="Juxtapose" Version="1.4.0" />
  
</ItemGroup>

4.2 建立上下文

4.2.1 创建上下文类型,并使用 [Illusion] 特性指定要生成的类型
[Illusion(typeof(Greeter), "Juxtapose.Test.GreeterAsIGreeterIllusion")]
public partial class GreeterJuxtaposeContext : JuxtaposeContext
{
}

示例代码将为Greeter生成代理类型Juxtapose.Test.GreeterAsIGreeterIllusion

Note!!!

  • 必须继承JuxtaposeContext
  • 必须标记partial关键字;

4.2.2 [Illusion] 的多种用法
  • 直接为类型生成代理,如下示例生成 Juxtapose.Test.GreeterIllusion 类型,且不继承接口(静态类型相同用法)
[Illusion(typeof(Greeter))]
  • 为类型生成代理,并继承指定接口,如下示例生成 Juxtapose.Test.GreeterAsIGreeterIllusion 类型且继承IGreeter接口
    • 现在需要手动声明 partial 类来使生成的类型派生自目标接口
partial class GreeterIllusion : IGreeter
{ }
  • 生成类型,并指定类型名称,如下示例生成 Juxtapose.Test.HelloGreeter 类型
[Illusion(typeof(Greeter), generatedTypeName: "Juxtapose.Test.HelloGreeter")]
  • 生成从IoC容器获取的接口代理类型,如下示例生成 Juxtapose.Test.IGreeterIllusionFromIoCContainer 类型(此时Context类需要实现IIoCContainerProvider接口,并提供有效的IServiceProvider
[Illusion(typeof(IGreeterFromServiceProvider), generatedTypeName: "Juxtapose.Test.IGreeterIllusionFromIoCContainer", fromIoCContainer: true)]

4.3 添加入口点

Main方法开始处添加入口点代码,并使用指定上下文

await JuxtaposeEntryPoint.TryAsEndpointAsync(args, GreeterJuxtaposeContext.SharedInstance);

到此已完成开发,创建类型Juxtapose.Test.GreeterAsIGreeterIllusion的对象,并调用其方法,其实际逻辑将在子进程中运行;

5. 调试子进程(Windows&&VisualStudio Only)

现在会自动附加调试器(启动项目需要直接引用Juxtapose包,以确保依赖包正确引入)

在代码中打上断点,运行时将会正确命中断点(只在 VisualStudio2022 17.0.5 && Win11 21TH2 中进行了测试,理论上是通用)

6. AOT支持*(net8.0+)

受限于代码生成器不能相互访问生成的代码,AOT支持需要手动编写部分代码
  • 声明 JsonSerializerContext 框架默认使用 System.Text.Json 进行消息的序列化与反序列化,需要手动定义 JsonSerializerContext 声明所有类型:
[JsonSerializable(typeof(global::Juxtapose.Messages.JuxtaposeAckMessage))]
[JsonSerializable(typeof(global::Juxtapose.Messages.ExceptionMessage))]
[JsonSerializable(typeof(global::Juxtapose.Messages.InstanceMethodInvokeMessage<global::Juxtapose.Messages.ParameterPacks.CancellationTokenSourceCancelParameterPack>))]
[JsonSerializable(typeof(global::Juxtapose.Messages.DisposeObjectInstanceMessage))]
[JsonSerializable(typeof(global::Juxtapose.Messages.CreateObjectInstanceMessage<global::Juxtapose.Messages.ParameterPacks.ServiceProviderGetInstanceParameterPack>))]
// .........
[JsonSourceGenerationOptions(IgnoreReadOnlyProperties = false, IgnoreReadOnlyFields = false, IncludeFields = true, WriteIndented = false)]
partial class SampleJsonSerializerContext : JsonSerializerContext {}
  • 重写 JuxtaposeContextCreateCommunicationMessageCodecFactory 方法 应用前置步骤声明的 JsonSerializerContext
 partial class SampleJuxtaposeContext : global::Juxtapose.JuxtaposeContext
 {
   protected override ICommunicationMessageCodecFactory CreateCommunicationMessageCodecFactory()
   {
       var communicationMessageCodec = new DefaultJsonBasedMessageCodec(GetMessageTypes(), LoggerFactory, SampleJsonSerializerContext.Default.Options);
       return new GenericSharedMessageCodecFactory(communicationMessageCodec);
   }
 }
至此已完成AOT支持;
Note: 为方便开发,上述代码已生成在 Context 代码中,可从分析器中找到代码,复制后可直接使用;
Note: 已经过有限的测试;

7. 工作逻辑

SourceGenerator在编译时生成代理类型,封装通信消息。在创建代理类型对象时,会自动创建子进程,并在子进程中创建目标类型的对象,使用命名管道进行进程间通信,使用System.Text.Json进行消息的序列化与反序列化。

7.1 关键词列表

关键字 名称 来源 作用
Context 上下文 手动定义 用于承载所有子进程运行的相关信息
Executor 执行器 自动生成 用于运行时消息解析收发,创建对象,执行静态方法等
ParameterPack 参数包 自动生成 将方法参数封装到一个类型中,以便序列化
Illusion 幻象 自动生成 实际使用的类
RealObjectInvoker 真实对象执行器 自动生成 在子进程中接收消息,并进行实际的对象方法调用

更多功能细节参见示例代码


示例列表

项目 内容
SampleLibrary 基于库的使用示例,可由其它程序直接使用
SampleConsoleApp 基于控制台的使用示例,可使用当前程序集生成的类,或使用其他库生成的类
ResourceBasedObjectPool 基于系统资源的动态对象池示例
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
1.4.0 4,553 11/21/2023
1.3.0 230 11/15/2023
1.2.2 27,663 12/19/2022
1.2.1 728 10/12/2022
1.2.0 698 10/11/2022
1.1.2 698 9/16/2022
1.1.1 716 7/29/2022
1.1.0 726 7/23/2022
1.1.0-beta0001 525 7/6/2022
1.0.2 778 6/19/2022
1.0.1 757 5/26/2022
1.0.0 858 1/24/2022
1.0.0-dev-028 443 1/24/2022
1.0.0-dev-027 457 1/23/2022
1.0.0-dev-026 515 1/22/2022
1.0.0-dev-025 478 1/18/2022
1.0.0-dev-024 430 1/16/2022
1.0.0-dev-023 491 1/11/2022
1.0.0-dev-022 552 1/5/2022
1.0.0-dev-021 472 12/29/2021
1.0.0-dev-020 488 12/7/2021
1.0.0-dev-019 474 12/7/2021
1.0.0-dev-018 465 12/7/2021
1.0.0-dev-017 481 12/6/2021
1.0.0-dev-016 443 12/5/2021
1.0.0-dev-015 465 12/3/2021
1.0.0-dev-014 421 12/2/2021
1.0.0-dev-013 494 12/2/2021
1.0.0-dev-012 513 12/1/2021
1.0.0-dev-011 487 12/1/2021
1.0.0-dev-010 445 11/30/2021