Repository: dotnet-campus/dotnetCampus.Ipc Branch: main Commit: c728ca3f03f5 Files: 455 Total size: 1.2 MB Directory structure: gitextract_cjt1cj37/ ├── .editorconfig ├── .gitattributes ├── .github/ │ └── workflows/ │ ├── dotnet-core.yml │ ├── dotnet-format.yml │ └── nuget-tag-publish.yml ├── .gitignore ├── CHANGELOG.md ├── Directory.Build.props ├── Directory.Packages.props ├── LICENSE ├── README.md ├── analyzers/ │ └── dotnetCampus.Ipc.SourceGenerators/ │ ├── GeneratedIpcJointGenerator.cs │ ├── Properties/ │ │ └── GlobalUsings.cs │ └── dotnetCampus.Ipc.SourceGenerators.csproj ├── build/ │ └── Version.props ├── demo/ │ ├── IpcDirectRoutedAotDemo/ │ │ ├── DemoRequest.cs │ │ ├── DemoResponse.cs │ │ ├── IpcDirectRoutedAotDemo.csproj │ │ ├── NotifyInfo.cs │ │ ├── Program.cs │ │ └── SourceGenerationContext.cs │ ├── IpcRemotingObjectDemo/ │ │ ├── IpcRemotingObjectClientDemo/ │ │ │ ├── IFoo.cs │ │ │ ├── IpcRemotingObjectClientDemo.csproj │ │ │ └── Program.cs │ │ └── IpcRemotingObjectServerDemo/ │ │ ├── Foo.cs │ │ ├── IFoo.cs │ │ ├── IpcRemotingObjectServerDemo.csproj │ │ └── Program.cs │ ├── PipeMvc/ │ │ ├── PipeMvcClientDemo/ │ │ │ ├── App.xaml │ │ │ ├── App.xaml.cs │ │ │ ├── AssemblyInfo.cs │ │ │ ├── MainWindow.xaml │ │ │ ├── MainWindow.xaml.cs │ │ │ └── PipeMvcClientDemo.csproj │ │ └── PipeMvcServerDemo/ │ │ ├── FooContent.cs │ │ ├── FooController.cs │ │ ├── MainWindow.xaml │ │ ├── MainWindow.xaml.cs │ │ ├── PipeMvcServerDemo.csproj │ │ ├── Program.cs │ │ ├── Properties/ │ │ │ └── launchSettings.json │ │ ├── appsettings.Development.json │ │ └── appsettings.json │ ├── UnoDemo/ │ │ ├── IpcUno/ │ │ │ ├── .editorconfig │ │ │ ├── .gitignore │ │ │ ├── .vsconfig │ │ │ ├── Directory.Build.props │ │ │ ├── Directory.Build.targets │ │ │ ├── Directory.Packages.props │ │ │ ├── IpcUno/ │ │ │ │ ├── App.cs │ │ │ │ ├── AppResources.xaml │ │ │ │ ├── Assets/ │ │ │ │ │ └── SharedAssets.md │ │ │ │ ├── Business/ │ │ │ │ │ └── Models/ │ │ │ │ │ ├── AppConfig.cs │ │ │ │ │ ├── ConnectedPeerModel.cs │ │ │ │ │ ├── Entity.cs │ │ │ │ │ └── IpcServerEntity.cs │ │ │ │ ├── GlobalSuppressions.cs │ │ │ │ ├── GlobalUsings.cs │ │ │ │ ├── IpcUno.csproj │ │ │ │ ├── Presentation/ │ │ │ │ │ ├── AddConnectPage.xaml │ │ │ │ │ ├── AddConnectPage.xaml.cs │ │ │ │ │ ├── ChatPage.xaml │ │ │ │ │ ├── ChatPage.xaml.cs │ │ │ │ │ ├── MainPage.xaml │ │ │ │ │ ├── MainPage.xaml.cs │ │ │ │ │ ├── MainViewModel.cs │ │ │ │ │ ├── SecondPage.xaml │ │ │ │ │ ├── SecondPage.xaml.cs │ │ │ │ │ ├── SecondViewModel.cs │ │ │ │ │ ├── ServerPage.xaml │ │ │ │ │ ├── ServerPage.xaml.cs │ │ │ │ │ ├── ServerViewModel.cs │ │ │ │ │ ├── Shell.xaml │ │ │ │ │ ├── Shell.xaml.cs │ │ │ │ │ └── ShellViewModel.cs │ │ │ │ ├── Strings/ │ │ │ │ │ └── en/ │ │ │ │ │ └── Resources.resw │ │ │ │ ├── Styles/ │ │ │ │ │ ├── ColorPaletteOverride.xaml │ │ │ │ │ └── MaterialFontsOverride.xaml │ │ │ │ ├── Utils/ │ │ │ │ │ ├── ScrollViewerExtensions.cs │ │ │ │ │ ├── TreeExtensions.cs │ │ │ │ │ └── UISpyHelper.cs │ │ │ │ ├── appsettings.development.json │ │ │ │ └── appsettings.json │ │ │ ├── IpcUno.Base/ │ │ │ │ ├── AppHead.xaml │ │ │ │ ├── AppHead.xaml.cs │ │ │ │ ├── IpcUno.Base.csproj │ │ │ │ └── base.props │ │ │ ├── IpcUno.MauiControls/ │ │ │ │ ├── App.xaml │ │ │ │ ├── App.xaml.cs │ │ │ │ ├── AppBuilderExtensions.cs │ │ │ │ ├── EmbeddedControl.xaml │ │ │ │ ├── EmbeddedControl.xaml.cs │ │ │ │ ├── IpcUno.MauiControls.csproj │ │ │ │ ├── Styles/ │ │ │ │ │ ├── Colors.xaml │ │ │ │ │ └── Styles.xaml │ │ │ │ └── UnoImageConverter.cs │ │ │ ├── IpcUno.Skia.Gtk/ │ │ │ │ ├── IpcUno.Skia.Gtk.csproj │ │ │ │ ├── Package.appxmanifest │ │ │ │ ├── Program.cs │ │ │ │ └── app.manifest │ │ │ ├── IpcUno.Skia.WPF/ │ │ │ │ ├── IpcUno.Skia.WPF.csproj │ │ │ │ ├── Package.appxmanifest │ │ │ │ ├── Wpf/ │ │ │ │ │ ├── App.xaml │ │ │ │ │ └── App.xaml.cs │ │ │ │ └── app.manifest │ │ │ ├── IpcUno.Tests/ │ │ │ │ ├── AppInfoTests.cs │ │ │ │ ├── GlobalUsings.cs │ │ │ │ └── IpcUno.Tests.csproj │ │ │ ├── IpcUno.UITests/ │ │ │ │ ├── Constants.cs │ │ │ │ ├── Given_MainPage.cs │ │ │ │ ├── GlobalUsings.cs │ │ │ │ ├── IpcUno.UITests.csproj │ │ │ │ └── TestBase.cs │ │ │ ├── IpcUno.Windows/ │ │ │ │ ├── IpcUno.Windows.csproj │ │ │ │ ├── Package.appxmanifest │ │ │ │ ├── Properties/ │ │ │ │ │ ├── PublishProfiles/ │ │ │ │ │ │ ├── win-arm64.pubxml │ │ │ │ │ │ ├── win-x64.pubxml │ │ │ │ │ │ └── win-x86.pubxml │ │ │ │ │ └── launchsettings.json │ │ │ │ ├── Resources.lang-en-us.resw │ │ │ │ └── app.manifest │ │ │ └── solution-config.props.sample │ │ ├── IpcUno.sln │ │ └── README.md │ ├── dotnetCampus.Ipc.Demo/ │ │ ├── Program.cs │ │ └── dotnetCampus.Ipc.Demo.csproj │ └── dotnetCampus.Ipc.WpfDemo/ │ ├── App.xaml │ ├── App.xaml.cs │ ├── AssemblyInfo.cs │ ├── ConnectedPeerModel.cs │ ├── DispatcherSwitcher.cs │ ├── MainWindow.xaml │ ├── MainWindow.xaml.cs │ ├── Options.cs │ ├── View/ │ │ ├── AddConnectPage.xaml │ │ ├── AddConnectPage.xaml.cs │ │ ├── CharPage.xaml │ │ ├── CharPage.xaml.cs │ │ ├── ListViewExtensions.cs │ │ ├── ServerPage.xaml │ │ └── ServerPage.xaml.cs │ └── dotnetCampus.Ipc.WpfDemo.csproj ├── docs/ │ ├── IpcObject.01.md │ ├── IpcObject.02.md │ └── JsonIpcDirectRouted.md ├── dotnetCampus.Ipc.sln ├── dotnetCampus.Ipc.sln.DotSettings ├── src/ │ ├── PipeMvc/ │ │ ├── dotnetCampus.Ipc.PipeMvcClient/ │ │ │ ├── IpcNamedPipeClientHandler.cs │ │ │ ├── IpcPipeMvcClientProvider.cs │ │ │ └── dotnetCampus.Ipc.PipeMvcClient.csproj │ │ ├── dotnetCampus.Ipc.PipeMvcServer/ │ │ │ ├── HostFramework/ │ │ │ │ ├── ApplicationWrapper.cs │ │ │ │ ├── AsyncStreamWrapper.cs │ │ │ │ ├── ClientHandler.cs │ │ │ │ ├── HttpContextBuilder.cs │ │ │ │ ├── HttpResetTestException.cs │ │ │ │ ├── IpcServer.cs │ │ │ │ ├── IpcServerOptions.cs │ │ │ │ ├── NoopHostLifetime.cs │ │ │ │ ├── RequestBodyDetectionFeature.cs │ │ │ │ ├── RequestBuilder.cs │ │ │ │ ├── RequestFeature.cs │ │ │ │ ├── RequestLifetimeFeature.cs │ │ │ │ ├── ResponseBodyPipeWriter.cs │ │ │ │ ├── ResponseBodyReaderStream.cs │ │ │ │ ├── ResponseBodyWriterStream.cs │ │ │ │ ├── ResponseFeature.cs │ │ │ │ ├── ResponseTrailersFeature.cs │ │ │ │ ├── TestWebSocket.cs │ │ │ │ ├── UpgradeFeature.cs │ │ │ │ ├── WebHostBuilderFactory.cs │ │ │ │ └── WebSocketClient.cs │ │ │ ├── IpcFramework/ │ │ │ │ └── IpcPipeMvcServerCore.cs │ │ │ ├── Properties/ │ │ │ │ └── launchSettings.json │ │ │ ├── WebHostBuilderExtensions.cs │ │ │ ├── dotnetCampus.Ipc.PipeMvcServer.csproj │ │ │ └── dotnetCampus.Ipc.PipeMvcServer.csproj.DotSettings │ │ └── dotnetCampus.Ipc.PipeMvcShare/ │ │ ├── HeaderContent.cs │ │ ├── HttpMessageSerializer.cs │ │ ├── HttpRequestMessageContentBase.cs │ │ ├── HttpRequestMessageDeserializeContent.cs │ │ ├── HttpRequestMessageSerializeContent.cs │ │ ├── HttpResponseMessageContentBase.cs │ │ ├── HttpResponseMessageDeserializeContent.cs │ │ ├── HttpResponseMessageSerializeContent.cs │ │ ├── IpcPipeMvcContext.cs │ │ ├── IpcResponseMessageResult.cs │ │ ├── dotnetCampus.Ipc.PipeMvcShare.projitems │ │ └── dotnetCampus.Ipc.PipeMvcShare.shproj │ ├── dotnetCampus.Ipc/ │ │ ├── CompilerServices/ │ │ │ ├── Attributes/ │ │ │ │ ├── AssemblyIpcProxyAttribute.cs │ │ │ │ ├── AssemblyIpcProxyJointAttribute.cs │ │ │ │ ├── IpcEventAttribute.cs │ │ │ │ ├── IpcMemberAttribute.cs │ │ │ │ ├── IpcMethodAttribute.cs │ │ │ │ ├── IpcPropertyAttribute.cs │ │ │ │ ├── IpcPublicAttribute.cs │ │ │ │ └── IpcShapeAttribute.cs │ │ │ └── GeneratedProxies/ │ │ │ ├── Contexts/ │ │ │ │ └── GeneratedIpcJointResponse.cs │ │ │ ├── Garms/ │ │ │ │ ├── Garm.cs │ │ │ │ ├── Garm.generic.cs │ │ │ │ └── IGarmObject.cs │ │ │ ├── GeneratedIpcFactory.cs │ │ │ ├── GeneratedIpcJoint.cs │ │ │ ├── GeneratedIpcJoint.generic.cs │ │ │ ├── GeneratedIpcProxy.cs │ │ │ ├── GeneratedProxyJointIpcContext.cs │ │ │ ├── GeneratedProxyJointIpcRequestHandler.cs │ │ │ ├── IpcProxyConfigs.cs │ │ │ ├── Models/ │ │ │ │ ├── GeneratedIpcProxyJointInstanceCache.cs │ │ │ │ ├── GeneratedProxyExceptionModel.cs │ │ │ │ ├── GeneratedProxyMemberInvokeModel.cs │ │ │ │ ├── GeneratedProxyMemberReturnModel.cs │ │ │ │ ├── GeneratedProxyObjectModel.cs │ │ │ │ ├── IpcJsonElement.cs │ │ │ │ ├── IpcMemberInfo.cs │ │ │ │ └── MemberInvokingType.cs │ │ │ ├── PublicIpcJointManager.cs │ │ │ └── Utils/ │ │ │ └── IpcProxyInvokingHelper.cs │ │ ├── Context/ │ │ │ ├── AckArgs.cs │ │ │ ├── AckTask.cs │ │ │ ├── ConnectToExistingPeerResult.cs │ │ │ ├── DelegateIpcRequestHandler.cs │ │ │ ├── IIpcRequestContext.cs │ │ │ ├── IPeerConnectionBrokenArgs.cs │ │ │ ├── IPeerMessageArgs.cs │ │ │ ├── IPeerReconnectedArgs.cs │ │ │ ├── IpcBufferMessageContext.cs │ │ │ ├── IpcClientRequestArgs.cs │ │ │ ├── IpcConfiguration.cs │ │ │ ├── IpcConfigurationExtensions.cs │ │ │ ├── IpcContext.cs │ │ │ ├── IpcInternalPeerConnectedArgs.cs │ │ │ ├── IpcPipeServerMessageProviderPeerConnectionBrokenArgs.cs │ │ │ ├── IpcRequest.cs │ │ │ ├── IpcRequestParameter.cs │ │ │ ├── IpcRequestParameterType.cs │ │ │ ├── IpcResponse.cs │ │ │ ├── IpcSerializableType.cs │ │ │ ├── IpcStatus.cs │ │ │ ├── KnownMessageHeaders.cs │ │ │ ├── LoggingContext/ │ │ │ │ ├── IpcContextLoggerExtension.cs │ │ │ │ ├── IpcMessageBodyFormatter.cs │ │ │ │ ├── LoggerEventIds.cs │ │ │ │ ├── ReceiveMessageBodyLogState.cs │ │ │ │ ├── SendMessageBodiesLogState.cs │ │ │ │ └── SendMessageBodyLogState.cs │ │ │ ├── PeerConnectedArgs.cs │ │ │ ├── PeerConnectionBrokenArgs.cs │ │ │ ├── PeerMessageArgs.cs │ │ │ └── PeerStreamMessageArgs.cs │ │ ├── Diagnostics/ │ │ │ ├── IIpcMessageInspector.cs │ │ │ ├── IpcMessageInspectionContext.cs │ │ │ ├── IpcMessageInspectorManager.cs │ │ │ └── IpcMessageTracker.cs │ │ ├── Exceptions/ │ │ │ ├── IpcClientPipeConnectionException.cs │ │ │ ├── IpcException.cs │ │ │ ├── IpcInvokingException.cs │ │ │ ├── IpcInvokingTimeoutException.cs │ │ │ ├── IpcLocalException.cs │ │ │ ├── IpcMemberNotFoundException.cs │ │ │ ├── IpcPeerConnectionBrokenException.cs │ │ │ ├── IpcPipeConnectionException.cs │ │ │ ├── IpcRemoteException.cs │ │ │ ├── JsonIpcDirectRouteSerializeLocalException.cs │ │ │ ├── JsonIpcDirectRoutedCanNotFindRequestHandlerException.cs │ │ │ ├── JsonIpcDirectRoutedHandleRequestRemoteException.cs │ │ │ ├── JsonIpcDirectRoutedLocalException.cs │ │ │ └── JsonIpcDirectRoutedRemoteException.cs │ │ ├── IIpcProvider.cs │ │ ├── IIpcRequestHandler.cs │ │ ├── IMessageWriter.cs │ │ ├── IPeerProxy.cs │ │ ├── Internals/ │ │ │ ├── AckManager.cs │ │ │ ├── DebugContext.cs │ │ │ ├── EmptyIpcRequestHandler.cs │ │ │ ├── IClientMessageWriter.cs │ │ │ ├── IpcHandleRequestMessageResult.cs │ │ │ ├── IpcMessageConverter.cs │ │ │ ├── IpcPipeServerMessageProvider.cs │ │ │ ├── PeerManager.cs │ │ │ ├── PeerReConnector.cs │ │ │ ├── PeerRegisterProvider.cs │ │ │ └── ServerStreamMessageReader.cs │ │ ├── IpcMessageCommandType.cs │ │ ├── IpcMessageWriter.cs │ │ ├── IpcRouteds/ │ │ │ └── DirectRouteds/ │ │ │ ├── Base_/ │ │ │ │ ├── IpcDirectRoutedClientProxyBase.cs │ │ │ │ └── IpcDirectRoutedProviderBase.cs │ │ │ ├── IpcDirectRoutedMessageWriter.cs │ │ │ ├── Json_/ │ │ │ │ ├── JsonIpcDirectRoutedCanNotFindRequestHandlerExceptionInfo.cs │ │ │ │ ├── JsonIpcDirectRoutedClientProxy.cs │ │ │ │ ├── JsonIpcDirectRoutedContext.cs │ │ │ │ ├── JsonIpcDirectRoutedHandleRequestExceptionInfo.cs │ │ │ │ ├── JsonIpcDirectRoutedLogStateMessageType.cs │ │ │ │ ├── JsonIpcDirectRoutedLoggerExtension.cs │ │ │ │ ├── JsonIpcDirectRoutedMessageLogState.cs │ │ │ │ ├── JsonIpcDirectRoutedParameterlessType.cs │ │ │ │ └── JsonIpcDirectRoutedProvider.cs │ │ │ └── RawByte_/ │ │ │ ├── RawByteIpcDirectRoutedClientProxy.cs │ │ │ └── RawByteIpcDirectRoutedProvider.cs │ │ ├── Messages/ │ │ │ ├── Ack.cs │ │ │ ├── CoreMessageType.cs │ │ │ ├── IIpcResponseMessage.cs │ │ │ ├── IpcClientRequestMessage.cs │ │ │ ├── IpcClientRequestMessageId.cs │ │ │ ├── IpcMessage.cs │ │ │ ├── IpcMessageBody.cs │ │ │ ├── IpcMessageContext.cs │ │ │ ├── IpcMessageResult.cs │ │ │ └── KnownResponseMessages.cs │ │ ├── Package/ │ │ │ └── build/ │ │ │ └── Package.props │ │ ├── Pipes/ │ │ │ ├── IpcClientService.cs │ │ │ ├── IpcMessageManagerBase.cs │ │ │ ├── IpcMessageRequestManager.cs │ │ │ ├── IpcMessageResponseManager.cs │ │ │ ├── IpcProvider.cs │ │ │ ├── IpcRequestHandlerProvider.cs │ │ │ ├── IpcRequestMessageContext.cs │ │ │ ├── IpcServerService.cs │ │ │ ├── PeerProxy.cs │ │ │ └── PipeConnectors/ │ │ │ ├── IIpcClientPipeConnector.cs │ │ │ ├── IpcClientPipeConnectionContext.cs │ │ │ └── IpcClientPipeConnector.cs │ │ ├── Properties/ │ │ │ └── .gitignore │ │ ├── Serialization/ │ │ │ ├── IIpcObjectSerializer.cs │ │ │ ├── IpcObjectJsonSerializer.cs │ │ │ ├── JsonIpcMessageSerializer.cs │ │ │ └── SystemTextJsonIpcObjectSerializer.cs │ │ ├── Threading/ │ │ │ ├── IIpcThreadPool.cs │ │ │ ├── IpcSingleThreadPool.cs │ │ │ ├── IpcTaskScheduling.cs │ │ │ ├── IpcThreadPool.cs │ │ │ └── Tasks/ │ │ │ ├── IpcStartEndTaskItem.cs │ │ │ ├── IpcTask.cs │ │ │ └── TaskItem.cs │ │ ├── Utils/ │ │ │ ├── Buffers/ │ │ │ │ ├── ISharedArrayPool.cs │ │ │ │ └── SharedArrayPool.cs │ │ │ ├── Caching/ │ │ │ │ ├── CachePool.cs │ │ │ │ └── CachePoolValueMap.cs │ │ │ ├── Extensions/ │ │ │ │ ├── BinaryArrayExtensions.cs │ │ │ │ ├── ByteListExtensions.cs │ │ │ │ ├── DoubleBufferTaskExtensions.cs │ │ │ │ ├── IpcMessageCommandExtensions.cs │ │ │ │ ├── IpcMessageContextExtensions.cs │ │ │ │ ├── IpcMessageExtension.cs │ │ │ │ ├── LoggerExtensions.cs │ │ │ │ ├── PeerMessageArgsExtension.cs │ │ │ │ └── StreamExtensions.cs │ │ │ ├── IO/ │ │ │ │ ├── AsyncBinaryReader.cs │ │ │ │ ├── AsyncBinaryWriter.cs │ │ │ │ ├── ByteListMessageStream.cs │ │ │ │ └── PipeHelper.cs │ │ │ ├── Logging/ │ │ │ │ ├── EventId.cs │ │ │ │ ├── ILogger.cs │ │ │ │ ├── IpcLogger.cs │ │ │ │ └── LogLevel.cs │ │ │ ├── NullableBooleans.cs │ │ │ └── TaskUtils.cs │ │ ├── dotnetCampus.Ipc.csproj │ │ └── dotnetCampus.Ipc.csproj.DotSettings │ ├── dotnetCampus.Ipc.Analyzers/ │ │ ├── Analyzers/ │ │ │ ├── AddIpcProxyConfigsAnalyzer.cs │ │ │ ├── AddIpcShapeAnalyzer.cs │ │ │ ├── Compiling/ │ │ │ │ ├── IpcAttributeHelper.cs │ │ │ │ └── IpcProxyInvokingInfo.cs │ │ │ ├── ContractTypeDismatchWithInterfaceAnalyzer.cs │ │ │ ├── ContractTypeMustBeAnInterfaceAnalyzer.cs │ │ │ ├── DefaultReturnDependsOnIgnoresIpcExceptionAnalyzer.cs │ │ │ ├── EmptyIpcMemberAttributeIsUnnecessaryAnalyzer.cs │ │ │ └── IgnoresIpcExceptionIsRecommendedAnalyzer.cs │ │ ├── CodeAnalysis/ │ │ │ ├── Core/ │ │ │ │ ├── DiagnosticException.cs │ │ │ │ └── Diagnostics.cs │ │ │ ├── Models/ │ │ │ │ ├── IpcPublicAttributeNamedValues.cs │ │ │ │ └── IpcShapeAttributeNamedValues.cs │ │ │ └── Utils/ │ │ │ ├── IpcSemanticAttributeHelper.cs │ │ │ ├── IpcSemanticSyntaxHelper.cs │ │ │ ├── SemanticAttributeHelper.cs │ │ │ ├── SemanticModelsHelper.cs │ │ │ ├── SemanticSyntaxHelper.cs │ │ │ └── SyntaxNameGuesser.cs │ │ ├── CodeFixes/ │ │ │ ├── AddIpcShapeCodeFixProvider.cs │ │ │ ├── ChangeClassContractTypeCodeFixProvider.cs │ │ │ ├── DefaultReturnDependsOnIgnoresIpcExceptionCodeFixProvider.cs │ │ │ ├── EmptyIpcMemberAttributeIsUnnecessaryCodeFixProvider.cs │ │ │ ├── IgnoresIpcExceptionIsRecommendedCodeFixProvider.cs │ │ │ └── LetClassImplementInterfaceCodeFixProvider.cs │ │ ├── Core/ │ │ │ └── ComponentModels/ │ │ │ └── Assignable.cs │ │ ├── Generators/ │ │ │ ├── Compiling/ │ │ │ │ ├── IpcPublicCompilation.cs │ │ │ │ ├── IpcPublicMemberProxyJointGenerator.cs │ │ │ │ ├── IpcShapeCompilation.cs │ │ │ │ └── Members/ │ │ │ │ ├── IPublicIpcObjectMemberGenerator.cs │ │ │ │ ├── IpcPublicMethodInfo.cs │ │ │ │ ├── IpcPublicPropertyInfo.cs │ │ │ │ └── MemberIdGenerator.cs │ │ │ ├── IpcPublicGenerator.cs │ │ │ └── Utils/ │ │ │ └── GeneratorHelper.cs │ │ ├── Properties/ │ │ │ ├── AssemblyInfo.cs │ │ │ ├── GlobalUsings.cs │ │ │ ├── Localizations.Designer.cs │ │ │ ├── Localizations.resx │ │ │ ├── Localizations.zh-hans.resx │ │ │ └── launchSettings.json │ │ ├── dotnetCampus.Ipc.Analyzers.csproj │ │ └── 分析器诊断.xlsx │ └── dotnetCampus.Ipc.PipeMvc/ │ └── dotnetCampus.Ipc.PipeMvc.csproj └── tests/ ├── dotnetCampus.Ipc.Analyzers.Tests/ │ ├── IgnoresIpcExceptionAnalyzerTests.cs │ ├── Verifiers/ │ │ ├── CSharpAnalyzerVerifier`1+Test.cs │ │ ├── CSharpAnalyzerVerifier`1.cs │ │ ├── CSharpCodeFixVerifier`2+Test.cs │ │ ├── CSharpCodeFixVerifier`2.cs │ │ ├── CSharpCodeRefactoringVerifier`1+Test.cs │ │ ├── CSharpCodeRefactoringVerifier`1.cs │ │ ├── CSharpVerifierHelper.cs │ │ ├── VisualBasicAnalyzerVerifier`1+Test.cs │ │ ├── VisualBasicAnalyzerVerifier`1.cs │ │ ├── VisualBasicCodeFixVerifier`2+Test.cs │ │ ├── VisualBasicCodeFixVerifier`2.cs │ │ ├── VisualBasicCodeRefactoringVerifier`1+Test.cs │ │ └── VisualBasicCodeRefactoringVerifier`1.cs │ └── dotnetCampus.Ipc.Analyzers.Tests.csproj ├── dotnetCampus.Ipc.FakeTests/ │ ├── FakeApis/ │ │ ├── IRemoteFakeIpcArgumentOrReturn.cs │ │ ├── IRemoteFakeIpcObject.cs │ │ ├── RemoteFakeIpcObject.cs │ │ └── RemoteIpcReturn.cs │ ├── Program.cs │ └── dotnetCampus.Ipc.FakeTests.csproj └── dotnetCampus.Ipc.Tests/ ├── AckManagerTest.cs ├── Attributes.cs ├── CompilerServices/ │ ├── Fake/ │ │ ├── FakeIpcObject.cs │ │ ├── FakeIpcObjectSubModelA.cs │ │ ├── FakeIpcObjectWithTypeAttributes.cs │ │ ├── IFakeIpcObject.cs │ │ ├── IFakeIpcObjectBase.cs │ │ └── INestedFakeIpcArgumentOrReturn.cs │ ├── FakeRemote/ │ │ └── RemoteIpcArgument.cs │ └── GeneratedProxies/ │ ├── IpcObjectTests.cs │ └── NotGeneratedTestOnlyFakeIpcObjectIpcShape.cs ├── IpcClientServiceTests.cs ├── IpcMessageConverterTest.cs ├── IpcObjectJsonSerializerTests.cs ├── IpcProviderTests.cs ├── IpcRouteds/ │ └── DirectRouteds/ │ ├── JsonIpcDirectRoutedProviderSystemJsonSerializerTest.cs │ └── JsonIpcDirectRoutedProviderTest.cs ├── NotifyTest.cs ├── PeerManagerTest.cs ├── PeerProxyTest.cs ├── PeerReConnectorTest.cs ├── PeerRegisterProviderTests.cs ├── Pipes/ │ └── PipeConnectors/ │ └── IpcClientPipeConnectorTest.cs ├── Properties/ │ └── Compatibility.cs ├── ResponseManagerTests.cs ├── TaskExtension.cs ├── TestJsonContext.cs ├── TestLogger.cs ├── Threading/ │ └── IpcThreadPoolTests.cs ├── Utils/ │ ├── Extensions/ │ │ └── PeerMessageArgsExtensionTest.cs │ └── IO/ │ └── AsyncBinaryReaderTests.cs └── dotnetCampus.Ipc.Tests.csproj ================================================ FILE CONTENTS ================================================ ================================================ FILE: .editorconfig ================================================ [*] end_of_line = crlf charset = utf-8-bom indent_size = 4 insert_final_newline = true tab_width = 4 trim_trailing_whitespace = true [*.{xml,csproj,vbproj,props,targets}] indent_size =2 indent_style = space tab_width =2 [*.{cs,vb}] dotnet_sort_system_directives_first = true dotnet_style_coalesce_expression = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_object_initializer = true:suggestion dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent dotnet_style_predefined_type_for_locals_parameters_members = true:silent dotnet_style_predefined_type_for_member_access = true:silent dotnet_style_prefer_auto_properties = true:silent dotnet_style_prefer_conditional_expression_over_assignment = true dotnet_style_prefer_conditional_expression_over_return = true dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion dotnet_style_prefer_inferred_tuple_names = true:suggestion dotnet_style_prefer_is_null_check_over_reference_equality_method = true:silent dotnet_style_qualification_for_event = false:silent dotnet_style_qualification_for_field = false:silent dotnet_style_qualification_for_method = false:silent dotnet_style_qualification_for_property = false:silent dotnet_style_readonly_field = true:suggestion dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent [*.cs] csharp_indent_case_contents = true csharp_indent_labels = flush_left csharp_indent_switch_labels = true csharp_new_line_before_catch = true csharp_new_line_before_else = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_anonymous_types = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_open_brace = all csharp_new_line_between_query_expression_clauses = true csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion csharp_prefer_braces = true:silent csharp_prefer_simple_default_expression = true:suggestion csharp_preserve_single_line_blocks = true csharp_space_after_cast = true csharp_space_after_colon_in_inheritance_clause = true csharp_space_after_keywords_in_control_flow_statements = true csharp_space_around_binary_operators = before_and_after csharp_space_before_colon_in_inheritance_clause = true csharp_space_between_method_call_empty_parameter_list_parentheses = false csharp_space_between_method_call_name_and_opening_parenthesis = false csharp_space_between_method_call_parameter_list_parentheses = false csharp_space_between_method_declaration_empty_parameter_list_parentheses = false csharp_space_between_method_declaration_parameter_list_parentheses = false csharp_space_between_parentheses = false csharp_style_conditional_delegate_call = true:suggestion csharp_style_deconstructed_variable_declaration = true:suggestion csharp_style_expression_bodied_accessors = true:silent csharp_style_expression_bodied_constructors = false:silent csharp_style_expression_bodied_indexers = true:silent csharp_style_expression_bodied_methods = false:silent csharp_style_expression_bodied_operators = false:silent csharp_style_expression_bodied_properties = true:silent csharp_style_inlined_variable_declaration = true:suggestion csharp_style_pattern_local_over_anonymous_function = true:suggestion csharp_style_pattern_matching_over_as_with_null_check = true:suggestion csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion csharp_style_throw_expression = true:suggestion csharp_style_var_elsewhere = true:silent csharp_style_var_for_built_in_types = true:silent csharp_style_var_when_type_is_apparent = true:silent ================================================ FILE: .gitattributes ================================================ ############################################################################### # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto ############################################################################### # Set default behavior for command prompt diff. # # This is need for earlier builds of msysgit that does not have it on by # default for csharp files. # Note: This is only used by command line ############################################################################### #*.cs diff=csharp ############################################################################### # Set the merge driver for project and solution files # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS # the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below ############################################################################### #*.sln merge=binary #*.csproj merge=binary #*.vbproj merge=binary #*.vcxproj merge=binary #*.vcproj merge=binary #*.dbproj merge=binary #*.fsproj merge=binary #*.lsproj merge=binary #*.wixproj merge=binary #*.modelproj merge=binary #*.sqlproj merge=binary #*.wwaproj merge=binary ############################################################################### # behavior for image files # # image files are treated as binary by default. ############################################################################### #*.jpg binary #*.png binary #*.gif binary ############################################################################### # diff behavior for common document formats # # Convert binary document formats to text before diffing them. This feature # is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain #*.DOC diff=astextplain #*.docx diff=astextplain #*.DOCX diff=astextplain #*.dot diff=astextplain #*.DOT diff=astextplain #*.pdf diff=astextplain #*.PDF diff=astextplain #*.rtf diff=astextplain #*.RTF diff=astextplain ================================================ FILE: .github/workflows/dotnet-core.yml ================================================ name: .NET Core on: [push] jobs: build: runs-on: windows-latest timeout-minutes: 15 steps: - uses: actions/checkout@v1 - name: Setup .NET uses: actions/setup-dotnet@v1 with: dotnet-version: | 3.1.x 6.0.x 8.0.x 9.0.x - name: Build run: dotnet build -c release - name: Test-net8.0 run: dotnet test -c release -f net8.0 -v:n --tl:off --no-build --logger:"console;verbosity=detailed" - name: Test-net6.0 run: dotnet test -c release -f net6.0 -v:n --tl:off --no-build --logger:"console;verbosity=detailed" - name: Pack run: dotnet pack -c release --no-build ================================================ FILE: .github/workflows/dotnet-format.yml ================================================ name: Code format check # 代码格式化机器人,详细请看 [dotnet 基于 dotnet format 的 GitHub Action 自动代码格式化机器人](https://blog.lindexi.com/post/dotnet-%E5%9F%BA%E4%BA%8E-dotnet-format-%E7%9A%84-GitHub-Action-%E8%87%AA%E5%8A%A8%E4%BB%A3%E7%A0%81%E6%A0%BC%E5%BC%8F%E5%8C%96%E6%9C%BA%E5%99%A8%E4%BA%BA.html ) on: push: branches: - main jobs: dotnet-format: runs-on: windows-latest steps: - name: Checkout repo uses: actions/checkout@v2 with: ref: ${{ github.head_ref }} - name: Setup .NET uses: actions/setup-dotnet@v1 with: dotnet-version: | 3.1.x 6.0.x 8.0.x 9.0.x - name: Install dotnetCampus.EncodingNormalior run: dotnet tool update -g dotnetCampus.EncodingNormalior - name: Fix encoding run: EncodingNormalior -f . --TryFix true - name: Install dotnet-format run: dotnet tool install -g dotnet-format - name: Run dotnet format run: dotnet format - name: Commit files # 下面将使用机器人的账号,你可以替换为你自己的账号 run: | git config --local user.name "github-actions-dotnet-formatter[bot]" git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" git commit -a -m 'Automated dotnet-format update' continue-on-error: true - name: Create Pull Request # if: steps.format.outputs.has-changes == 'true' # 如果有格式化,才继续 uses: peter-evans/create-pull-request@v3 with: title: '[Bot] Automated PR to fix formatting errors' body: | Automated PR to fix formatting errors committer: GitHub author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> # 以下是给定代码审查者,需要设置仓库有权限的开发者 assignees: lindexi,walterlv reviewers: lindexi,walterlv # 对应的上传分支 branch: t/bot/fix-codeformatting ================================================ FILE: .github/workflows/nuget-tag-publish.yml ================================================ name: publish nuget on: push: tags: - '*' jobs: build: runs-on: windows-latest steps: - uses: actions/checkout@v1 - name: Setup .NET uses: actions/setup-dotnet@v1 with: dotnet-version: | 3.1.x 6.0.x 8.0.x 9.0.x - name: Install dotnet tool run: dotnet tool install -g dotnetCampus.TagToVersion - name: Set tag to version run: dotnet TagToVersion -t ${{ github.ref }} - name: Build with dotnet run: | dotnet build --configuration Release dotnet pack --configuration Release --no-build - name: Install Nuget uses: nuget/setup-nuget@v1 with: nuget-version: '6.x' - name: Add private GitHub registry to NuGet run: | nuget sources add -name github -Source https://nuget.pkg.github.com/dotnet-campus/index.json -Username dotnet-campus -Password ${{ secrets.GITHUB_TOKEN }} - name: Push generated package to GitHub registry run: | nuget push .\artifacts\package\release\*.nupkg -Source github -SkipDuplicate nuget push .\artifacts\package\release\*.nupkg -Source https://api.nuget.org/v3/index.json -SkipDuplicate -ApiKey ${{ secrets.NugetKey }} ================================================ FILE: .gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUNIT *.VisualState.xml TestResult.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- Backup*.rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # JetBrains Rider .idea/ *.sln.iml # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb /GetAssemblyVersionTask/Properties/launchSettings.json /WriteAppVersionTask/Properties/launchSettings.json /src/dotnetCampus.Ipc.PipeMvc/Properties/launchSettings.json ================================================ FILE: CHANGELOG.md ================================================ # dotnetCampus.Ipc ================================================ FILE: Directory.Build.props ================================================  latest enable enable $(MSBuildThisFileDirectory)artifacts true true $(NoWarn);NU1507;NU1803;NETSDK1201;NETSDK1138;PRI257 $(WarningsAsErrors);CA1416 $(MSBuildThisFileDirectory) $([System.DateTime]::Now.ToString(`yyyy`)) 本机内多进程通讯库,稳定 IPC 通讯库 dotnet campus(.NET 职业技术学院) dotnet-campus Copyright © 2020-$(ThisYear) dotnet campus, All Rights Reserved. git https://github.com/dotnet-campus/dotnetCampus.Ipc https://github.com/dotnet-campus/dotnetCampus.Ipc ================================================ FILE: Directory.Packages.props ================================================  ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020-2023 dotnet campus Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # dotnetCampus.Ipc 本机内多进程通讯库 | Build | NuGet | |--|--| |![](https://github.com/dotnet-campus/dotnetCampus.Ipc/workflows/.NET%20Core/badge.svg)|[![](https://img.shields.io/nuget/v/dotnetCampus.Ipc.svg)](https://www.nuget.org/packages/dotnetCampus.Ipc)| ## 使用方法 库中提供了较为底层的通信方案,也提供了高级的封装方案(基于Json数据格式的通信方案),完整文档可参阅: - 🌀 远程对象调用 - [基础入门教程](./docs/IpcObject.01.md) - [通讯方式详解](./docs/IpcObject.02.md) - 🌐 直接路由 - [通讯方式详解](./docs/JsonIpcDirectRouted.md) ### 案例:直接路由Json通信(需要2.0.0-alpha版本以上) #### 步骤一 导入nuget包 **dotnetCampus.Ipc**(需要2.0.0-alpha版本以上),并引入所需要的命名空间; ``` C# using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.IpcRouteds.DirectRouteds; using dotnetCampus.Ipc.Pipes; ``` #### 步骤二 创建实际负责IPC通信的代理对象 ``` C# /// /// 根据创建一个 JsonIpcDirectRoutedProvider 对象 /// /// 不同的IPC对象所使用的管道名称,一个管道名称只能被用于一个IPC对象 /// private JsonIpcDirectRoutedProvider CreateJsonIpcDirectRoutedProvider(string pipeName) { // 创建一个 IpcProvider,实际创建管道,进行IPC通信的底层对象 // 可在 IpcConfiguration 进行详细的配置,包括配置断线重连、日志等级、线程池等等 var ipcProvider = new IpcProvider(pipeName, new IpcConfiguration()); // 创建一个 JsonIpcDirectRoutedProvider,封装了通信中的Json数据解析、简化方法调用 var ipcDirectRoutedProvider = new JsonIpcDirectRoutedProvider(ipcProvider); return ipcDirectRoutedProvider; } ``` #### 步骤三 向IPC对象注册接受到指定消息后的处理函数(如果该IPC对象只负责发送消息,则它不需要注册消息处理回调) ``` C# var ipcDirectRoutedProvider = CreateJsonIpcDirectRoutedProvider("我是接收消息的IPC对象"); //对无参的通知消息注册回调函数 ipcDirectRoutedProvider.AddNotifyHandler("通知消息A", () => { Console.WriteLine("我是进程A,我收到了通知消息B,该消息无参数"); }); //对参数类型为ParamType的通知消息注册回调函数 ipcDirectRoutedProvider.AddNotifyHandler("通知消息B", param => { Console.WriteLine($"我是进程A,我收到了通知消息B,该消息参数:{param.Message}"); }); //对参数类型为ParamType的请求注册回调函数并返回响应数据(可以异步处理响应、也可以无参) ipcDirectRoutedProvider.AddRequestHandler("请求消息C", (ParamType argument) => { //处理请求消息C var response = new IpcResponse { Message = $"我是进程A,我收到了请求消息C,该消息参数:{argument.Message}" }; //返回响应数据 return response; }); ``` #### 步骤四 启动服务 ``` C# var ipcDirectRoutedProvider = CreateJsonIpcDirectRoutedProvider("我是接收消息的IPC对象"); /** 一些消息注册(如果该IPC对象只负责发送消息,则它不需要注册消息处理回调;接受消息的一方需要注册接收到消息后的处理函数) …… **/ //启动该服务 ipcDirectRoutedProvider.StartServer(); ``` #### 步骤五 发送消息(如果该IPC对象只负责接收和处理消息,则它不需要发送消息) ``` C# var ipcDirectRoutedProvider = CreateJsonIpcDirectRoutedProvider("我是发送消息的IPC对象"); //启动该服务 ipcDirectRoutedProvider.StartServer(); //根据接收方的管道名,获取需要接受到消息的IPC对象,并发送通知 var ipcReceivingObjectA = await ipcDirectRoutedProvider.GetAndConnectClientAsync("我是接收消息的IPC对象"); await ipcReceivingObjectA.NotifyAsync("通知消息A"); await ipcReceivingObjectA.NotifyAsync("通知消息B", new ParamType { Message = "我发送的通知消息是XXX" }); var response = await ipcReceivingObjectA.GetResponseAsync("请求消息C", new ParamType { Message = "我发送的请求消息XXX" }); ``` #### 调用关系图 ![](./docs/image/README/zh-CN/sample0.png) *更多案例详见:* [Demo](https://github.com/dotnet-campus/dotnetCampus.Ipc/tree/master/demo) ### FAQ #### AOT 支持 Q: 此 Ipc 库支持 AOT 吗? A: 此 Ipc 库支持 AOT,但需要注意以下几点: - 如果是完全使用 byte[] 作为数据传输格式,则不需要任何额外的配置,直接就支持 AOT 了 - 如果是采用 Json 通讯系列,则需要在使用 Json 序列化时,使用 `JsonSerializerOptions` 的 `TypeInfoResolver` 属性来指定类型解析器。具体的配置可以参考 [JsonSerializerOptions](https://learn.microsoft.com/dotnet/api/system.text.json.jsonserializeroptions?view=dotnet-plat-ext-7.0) 的文档。一般而言,可采用封装好的 UseSystemTextJsonIpcObjectSerializer 扩展方法辅助传入 `System.Text.Json.Serialization.JsonSerializerContext` 对象,如以下示例代码所示 ``` C# IpcConfiguration ipcConfiguration = new IpcConfiguration() { // 进行设置其他配置 }.UseSystemTextJsonIpcObjectSerializer(SourceGenerationContext.Default); var ipcProvider = new IpcProvider(pipeName, ipcConfiguration); ``` 或者注入 IpcConfiguration 的 IpcObjectSerializer 属性,进行更加灵活的序列化配置。此时将不仅限于使用 System.Text.Json 进行序列化,也可以使用其他的序列化方式,如二进制序列化等等 Q: 采用 直接路由 Json 通信(JsonIpcDirectRoutedProvider)时,如何改造让其支持 AOT 编译? A:如上问所述,可在 IpcConfiguration 里面设置 IpcObjectSerializer 属性,或调用 UseSystemTextJsonIpcObjectSerializer 扩展辅助方法。如以下示代码所示 ``` C# // 创建一个 IpcProvider,实际创建管道,进行IPC通信的底层对象 // 可在 IpcConfiguration 进行详细的配置,包括配置断线重连、日志等级、线程池等等 IpcConfiguration ipcConfiguration = new IpcConfiguration() { // 进行设置其他配置 }.UseSystemTextJsonIpcObjectSerializer(SourceGenerationContext.Default); var ipcProvider = new IpcProvider(pipeName, ipcConfiguration); // 创建一个 JsonIpcDirectRoutedProvider,封装了通信中的Json数据解析、简化方法调用 var ipcDirectRoutedProvider = new JsonIpcDirectRoutedProvider(ipcProvider); ``` ## 项目结构图 ![](./docs/image/README/zh-CN/Architecture0.png) ## 特点 - 采用两个半工命名管道 - 采用 P2P 方式,每个端都是服务端也是客户端 - 提供 PeerProxy 机制,利用这个机制可以进行发送和接收某个对方的信息 - 追求稳定,而不追求高性能 ## 功能 - [x] 通讯建立 - [x] 消息收到回复机制 - [x] 断线重连功能 - [x] 大量异常处理 - [x] 支持裸数据双向传输方式 - [x] 支持裸数据请求响应模式 - [x] 支持字符串消息协议 - [x] 支持远程对象调用和对象存根传输方式 - [x] 支持 NamedPipeStreamForMvc (NamedPipeMvc) 客户端服务器端 MVC 模式 - [x] 支持直接路由的 Json 数据通讯方式 ## 感谢 - [jacqueskang/IpcServiceFramework](https://github.com/jacqueskang/IpcServiceFramework) - [https://github.com/dotnet/aspnetcore](https://github.com/dotnet/aspnetcore) for PipeMVC ## 踩过的坑 - [2019-12-1-构造PipeAccessRule时请不要使用字符串指定Identity - huangtengxiao](https://huangtengxiao.gitee.io/post/%E6%9E%84%E9%80%A0PipeAccessRule%E6%97%B6%E8%AF%B7%E4%B8%8D%E8%A6%81%E4%BD%BF%E7%94%A8%E5%AD%97%E7%AC%A6%E4%B8%B2%E6%8C%87%E5%AE%9AIdentity.html) ================================================ FILE: analyzers/dotnetCampus.Ipc.SourceGenerators/GeneratedIpcJointGenerator.cs ================================================ using System.Text.RegularExpressions; using Microsoft.CodeAnalysis.Text; namespace dotnetCampus.Ipc; /// /// 为 GeneratedIpcJoint 类生成更多的泛型参数。 /// [Generator(LanguageNames.CSharp)] public class GeneratedIpcJointGenerator : IIncrementalGenerator { public void Initialize(IncrementalGeneratorInitializationContext context) { var compilations = context.SyntaxProvider.CreateSyntaxProvider( // 找到 GeneratedIpcJoint 类型。 (syntaxNode, ct) => syntaxNode is ClassDeclarationSyntax cds && cds.Identifier.ToString() == "GeneratedIpcJoint", // 语义解析:确定是否真的是感兴趣的 IPC 接口。 (generatorSyntaxContext, ct) => generatorSyntaxContext) .Where(x => { var node = x.Node as ClassDeclarationSyntax; var symbol = x.SemanticModel.GetDeclaredSymbol(x.Node) as INamedTypeSymbol; return node is not null && symbol is not null && symbol.IsGenericType; }); context.RegisterSourceOutput(compilations, Execute); } private void Execute(SourceProductionContext context, GeneratorSyntaxContext generatorContext) { var source = GenerateGeneratedIpcJoint(generatorContext); context.AddSource($"GeneratedIpcJoint.generic", SourceText.From(source, Encoding.UTF8)); } private string GenerateGeneratedIpcJoint(GeneratorSyntaxContext context) => $$""" using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using dotnetCampus.Ipc.CompilerServices.GeneratedProxies.Models; namespace dotnetCampus.Ipc.CompilerServices.GeneratedProxies; partial class GeneratedIpcJoint { {{string.Join("\r\n\r\n", Enumerable.Range(2, 15) .Select(x => GenerateMethodGroup(context, x)) .SelectMany(x => x))}} } """; private IEnumerable GenerateMethodGroup(GeneratorSyntaxContext context, int genericCount) { yield return GenerateVoidMethod(context, genericCount); yield return GenerateReturnMethod(context, genericCount); yield return GenerateAsyncVoidMethod(context, genericCount); yield return GenerateAsyncReturnMethod(context, genericCount); } private string GenerateVoidMethod(GeneratorSyntaxContext context, int genericCount) => $$""" /// /// 匹配一个 IPC 目标对象上的某个方法,使其他 IPC 节点访问此 IPC 对象时能执行 所指向的具体实现。 /// /// 方法签名的 Id。 /// 对接实现。 protected void MatchMethod<{{GenerateTs(genericCount)}}>(ulong memberId, Action<{{GenerateTs(genericCount)}}> methodInvoker) { _methods.Add(memberId, (new[] { {{GenerateTs(genericCount, "typeof(T)")}} }, args => { methodInvoker({{GenerateTs(genericCount, i => $"CastArg(args![{i - 1}])!")}}); return DefaultGarm; } )); } """; private string GenerateReturnMethod(GeneratorSyntaxContext context, int genericCount) => $$""" /// /// 匹配一个 IPC 目标对象上的某个方法,使其他 IPC 节点访问此 IPC 对象时能执行 所指向的具体实现。 /// /// 方法签名的 Id。 /// 对接实现。 protected void MatchMethod<{{GenerateTs(genericCount)}}>(ulong memberId, Func<{{GenerateTs(genericCount)}}, Task> methodInvoker) { _asyncMethods.Add(memberId, (new[] { {{GenerateTs(genericCount, "typeof(T)")}} }, async args => { await methodInvoker({{GenerateTs(genericCount, i => $"CastArg(args![{i - 1}])!")}}).ConfigureAwait(false); return DefaultGarm; } )); } """; private string GenerateAsyncVoidMethod(GeneratorSyntaxContext context, int genericCount) => $$""" /// /// 匹配一个 IPC 目标对象上的某个方法,使其他 IPC 节点访问此 IPC 对象时能执行 所指向的具体实现。 /// /// 方法签名的 Id。 /// 对接实现。 protected void MatchMethod<{{GenerateTs(genericCount)}}, TReturn>(ulong memberId, Func<{{GenerateTs(genericCount)}}, Garm> methodInvoker) { _methods.Add(memberId, (new[] { {{GenerateTs(genericCount, "typeof(T)")}} }, args => methodInvoker({{GenerateTs(genericCount, i => $"CastArg(args![{i - 1}])!")}}))); } """; private string GenerateAsyncReturnMethod(GeneratorSyntaxContext context, int genericCount) => $$""" /// /// 匹配一个 IPC 目标对象上的某个方法,使其他 IPC 节点访问此 IPC 对象时能执行 所指向的具体实现。 /// /// 方法签名的 Id。 /// 对接实现。 protected void MatchMethod<{{GenerateTs(genericCount)}}, TReturn>(ulong memberId, Func<{{GenerateTs(genericCount)}}, Task>> methodInvoker) { _asyncMethods.Add(memberId, (new[] { {{GenerateTs(genericCount, "typeof(T)")}} }, async args => await methodInvoker({{GenerateTs(genericCount, i => $"CastArg(args![{i - 1}])!")}}).ConfigureAwait(false))); } """; private string GenerateTs(int genericCount, string? template = null) { var templateWithDefault = template ?? "T"; return string.Join(", ", Enumerable.Range(1, genericCount) .Select(x => GenrateT(x, templateWithDefault))); } private string GenerateTs(int genericCount, Func templateGetter) { return string.Join(", ", Enumerable.Range(1, genericCount) .Select(x => GenrateT(x, templateGetter(x)))); } /// /// 使用正则表达式找到 template 中独立的 T,然后替换为 T1、T2、T3…… /// /// 泛型序号,从 1 开始。 /// 泛型格式化模板,默认为 T;也可以用别的,如 typeof(T)。 private string GenrateT(int genericIndex, string template) { var regex = new Regex(@"\bT\b"); var match = regex.Match(template); if (match.Success) { var index = match.Index; var length = match.Length; var prefix = template.Substring(0, index); var suffix = template.Substring(index + length); return prefix + $"T{genericIndex}" + suffix; } else { return template; } } } ================================================ FILE: analyzers/dotnetCampus.Ipc.SourceGenerators/Properties/GlobalUsings.cs ================================================ global using System; global using System.Collections.Generic; global using System.Collections.Immutable; global using System.Composition; global using System.Diagnostics; global using System.Diagnostics.CodeAnalysis; global using System.Globalization; global using System.Linq; global using System.Text; global using System.Threading; global using System.Threading.Tasks; global using Microsoft.CodeAnalysis; global using Microsoft.CodeAnalysis.CSharp; global using Microsoft.CodeAnalysis.CSharp.Syntax; global using Microsoft.CodeAnalysis.Diagnostics; ================================================ FILE: analyzers/dotnetCampus.Ipc.SourceGenerators/dotnetCampus.Ipc.SourceGenerators.csproj ================================================  netstandard2.0 false enable dotnetCampus.Ipc true all runtime; build; native; contentfiles; analyzers; buildtransitive ================================================ FILE: build/Version.props ================================================ 1.0.0 ================================================ FILE: demo/IpcDirectRoutedAotDemo/DemoRequest.cs ================================================ namespace IpcDirectRoutedAotDemo; public record DemoRequest { public required string Value { get; init; } } ================================================ FILE: demo/IpcDirectRoutedAotDemo/DemoResponse.cs ================================================ namespace IpcDirectRoutedAotDemo; public record DemoResponse { public required string Result { get; init; } } ================================================ FILE: demo/IpcDirectRoutedAotDemo/IpcDirectRoutedAotDemo.csproj ================================================  Exe net9.0 enable false true true true ================================================ FILE: demo/IpcDirectRoutedAotDemo/NotifyInfo.cs ================================================ namespace IpcDirectRoutedAotDemo; public record NotifyInfo { public required string Value { get; init; } } ================================================ FILE: demo/IpcDirectRoutedAotDemo/Program.cs ================================================ // See https://aka.ms/new-console-template for more information using System.Diagnostics; using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.IpcRouteds.DirectRouteds; using dotnetCampus.Ipc.Pipes; using IpcDirectRoutedAotDemo; var notifyPath = "NotifyFoo"; var notifyPath2 = "NotifyFoo2"; var requestPath = "RequestFoo"; var requestPath2 = "RequestFoo2"; if (args.Length == 0) { // 首个启动的,当成服务端 string pipeName = Guid.NewGuid().ToString(); var ipcProvider = new IpcProvider(pipeName, new IpcConfiguration() { }.UseSystemTextJsonIpcObjectSerializer(SourceGenerationContext.Default)); var ipcDirectRoutedProvider = new JsonIpcDirectRoutedProvider(ipcProvider); ipcDirectRoutedProvider.AddNotifyHandler(notifyPath, () => { Console.WriteLine($"[{Environment.ProcessId}] Receive Notify. 服务端收到通知"); }); ipcDirectRoutedProvider.AddNotifyHandler(notifyPath2, (NotifyInfo notifyInfo) => { Console.WriteLine($"[{Environment.ProcessId}] Receive Notify. 服务端收到通知 NotifyInfo={notifyInfo}"); }); ipcDirectRoutedProvider.AddRequestHandler(requestPath, () => "ResponseFoo"); ipcDirectRoutedProvider.AddRequestHandler(requestPath2, (DemoRequest request) => { Console.WriteLine($"[{Environment.ProcessId}] Receive Request. 服务端收到请求 DemoRequest={request}"); return new DemoResponse() { Result = "返回内容" }; }); ipcDirectRoutedProvider.StartServer(); Console.WriteLine($"[{Environment.ProcessId}] 服务启动"); // 启动另一个进程 Process.Start(Environment.ProcessPath!, pipeName); } else { var peerName = args[0]; Console.WriteLine($"[{Environment.ProcessId}] 客户端进程启动"); var jsonIpcDirectRoutedProvider = new JsonIpcDirectRoutedProvider(ipcConfiguration: new IpcConfiguration() .UseSystemTextJsonIpcObjectSerializer(SourceGenerationContext.Default)); JsonIpcDirectRoutedClientProxy jsonIpcDirectRoutedClientProxy = await jsonIpcDirectRoutedProvider.GetAndConnectClientAsync(peerName); Console.WriteLine($"[{Environment.ProcessId}] 客户端发送通知"); await jsonIpcDirectRoutedClientProxy.NotifyAsync(notifyPath); Console.WriteLine($"[{Environment.ProcessId}] 客户端发送通知完成"); Console.WriteLine($"[{Environment.ProcessId}] 客户端发送通知2"); await jsonIpcDirectRoutedClientProxy.NotifyAsync(notifyPath2, new NotifyInfo() { Value = "通知2" }); Console.WriteLine($"[{Environment.ProcessId}] 客户端发送通知2完成"); Console.WriteLine($"[{Environment.ProcessId}] 客户端发送请求"); var responseValue = await jsonIpcDirectRoutedClientProxy.GetResponseAsync(requestPath); Console.WriteLine($"[{Environment.ProcessId}] 客户端完成请求,收到响应内容 {responseValue}"); Console.WriteLine($"[{Environment.ProcessId}] 客户端发送请求2"); var responseValue2 = await jsonIpcDirectRoutedClientProxy.GetResponseAsync(requestPath2, new DemoRequest() { Value = "客户端请求内容" }); Console.WriteLine($"[{Environment.ProcessId}] 客户端完成请求2,收到响应内容 {responseValue2}"); } Console.WriteLine($"[{Environment.ProcessId}] 等待退出"); Console.Read(); Console.WriteLine($"[{Environment.ProcessId}] 进程准备退出"); ================================================ FILE: demo/IpcDirectRoutedAotDemo/SourceGenerationContext.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Json.Serialization; using System.Threading.Tasks; namespace IpcDirectRoutedAotDemo; [JsonSerializable(typeof(NotifyInfo))] [JsonSerializable(typeof(DemoRequest))] [JsonSerializable(typeof(DemoResponse))] internal partial class SourceGenerationContext : JsonSerializerContext { } ================================================ FILE: demo/IpcRemotingObjectDemo/IpcRemotingObjectClientDemo/IFoo.cs ================================================ using dotnetCampus.Ipc.CompilerServices.Attributes; namespace IpcRemotingObjectServerDemo; // Must the same namespace /// /// 可跨进程调用的接口演示。 /// [IpcPublic] public interface IFoo { /// /// 属性演示。支持 get/set 属性、get 只读属性,支持跨进程报告异常。 /// string Name { get; set; } /// /// 方法演示。支持参数、返回值,支持跨进程报告异常。 /// int Add(int a, int b); /// /// 异步方法(更推荐)演示。支持参数、返回值,支持跨进程报告异常。 /// Task AddAsync(string a, int b); } ================================================ FILE: demo/IpcRemotingObjectDemo/IpcRemotingObjectClientDemo/IpcRemotingObjectClientDemo.csproj ================================================  Exe net6.0 enable enable false ================================================ FILE: demo/IpcRemotingObjectDemo/IpcRemotingObjectClientDemo/Program.cs ================================================ using dotnetCampus.Ipc.CompilerServices.GeneratedProxies; using dotnetCampus.Ipc.Pipes; using IpcRemotingObjectServerDemo; var ipcProvider = new IpcProvider("IpcRemotingObjectClientDemo"); ipcProvider.StartServer(); var peer = await ipcProvider.GetAndConnectToPeerAsync("IpcRemotingObjectServerDemo"); var foo = ipcProvider.CreateIpcProxy(peer); Console.WriteLine(await foo.AddAsync("a", 1)); Console.WriteLine(foo.Add(1, 2)); Console.Read(); ================================================ FILE: demo/IpcRemotingObjectDemo/IpcRemotingObjectServerDemo/Foo.cs ================================================ namespace IpcRemotingObjectServerDemo; class Foo : IFoo { public string Name { get; set; } = "Foo"; public int Add(int a, int b) { Console.WriteLine($"a({a})+b({b})={a + b}"); return a + b; } public async Task AddAsync(string a, int b) { return await Task.Run(() => { Console.WriteLine($"a({a})+b({b})={a + b}"); return a + b; }); } } ================================================ FILE: demo/IpcRemotingObjectDemo/IpcRemotingObjectServerDemo/IFoo.cs ================================================ using dotnetCampus.Ipc.CompilerServices.Attributes; namespace IpcRemotingObjectServerDemo; /// /// 可跨进程调用的接口演示。 /// [IpcPublic(IgnoresIpcException = true, Timeout = 1000)] public interface IFoo { /// /// 属性演示。支持 get/set 属性、get 只读属性,支持跨进程报告异常。 /// string Name { get; set; } /// /// 方法演示。支持参数、返回值,支持跨进程报告异常。 /// int Add(int a, int b); /// /// 异步方法(更推荐)演示。支持参数、返回值,支持跨进程报告异常。 /// Task AddAsync(string a, int b); } ================================================ FILE: demo/IpcRemotingObjectDemo/IpcRemotingObjectServerDemo/IpcRemotingObjectServerDemo.csproj ================================================  Exe net6.0 enable enable false ================================================ FILE: demo/IpcRemotingObjectDemo/IpcRemotingObjectServerDemo/Program.cs ================================================ using System; using dotnetCampus.Ipc.CompilerServices.GeneratedProxies; using dotnetCampus.Ipc.Pipes; using IpcRemotingObjectServerDemo; var ipcProvider = new IpcProvider("IpcRemotingObjectServerDemo"); ipcProvider.CreateIpcJoint(new Foo()); ipcProvider.PeerConnected += (sender, connectedArgs) => { Console.WriteLine($"PeerConnected. {connectedArgs.Peer.PeerName}"); }; ipcProvider.StartServer(); Console.Read(); ================================================ FILE: demo/PipeMvc/PipeMvcClientDemo/App.xaml ================================================  ================================================ FILE: demo/PipeMvc/PipeMvcClientDemo/App.xaml.cs ================================================ using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Linq; using System.Threading.Tasks; using System.Windows; namespace PipeMvcClientDemo; /// /// Interaction logic for App.xaml /// public partial class App : Application { } ================================================ FILE: demo/PipeMvc/PipeMvcClientDemo/AssemblyInfo.cs ================================================ using System.Windows; [assembly: ThemeInfo( ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located //(used if a resource is not found in the page, // or application resource dictionaries) ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located //(used if a resource is not found in the page, // app, or any theme specific resource dictionaries) )] ================================================ FILE: demo/PipeMvc/PipeMvcClientDemo/MainWindow.xaml ================================================  ================================================ FILE: demo/PipeMvc/PipeMvcClientDemo/MainWindow.xaml.cs ================================================ using System; using System.Net.Http; using System.Text; using System.Text.Json; using System.Threading.Tasks; using System.Windows; using dotnetCampus.Ipc.PipeMvcClient; using PipeMvcServerDemo; namespace PipeMvcClientDemo; /// /// Interaction logic for MainWindow.xaml /// public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Loaded += MainWindow_Loaded; } private async void MainWindow_Loaded(object sender, RoutedEventArgs e) { Log($"Start create PipeMvcClient."); var ipcPipeMvcClient = await IpcPipeMvcClientProvider.CreateIpcMvcClientAsync("PipeMvcServerDemo"); _ipcPipeMvcClient = ipcPipeMvcClient; Log($"Finish create PipeMvcClient."); } private HttpClient? _ipcPipeMvcClient; private async void GetFooButton_Click(object sender, RoutedEventArgs e) { if (_ipcPipeMvcClient is null) { return; } Log($"[Request][Get] IpcPipeMvcServer://api/Foo"); var response = await _ipcPipeMvcClient.GetStringAsync("api/Foo"); Log($"[Response][Get] IpcPipeMvcServer://api/Foo {response}"); } private void Log(string message) { Dispatcher.InvokeAsync(() => { TraceTextBlock.Text += message + "\r\n"; if (TraceTextBlock.Text.Length > 10000) { TraceTextBlock.Text = TraceTextBlock.Text[5000..]; } }); } private async void GetFooWithArgumentButton_Click(object sender, RoutedEventArgs e) { if (_ipcPipeMvcClient is null) { return; } Log($"[Request][Get] IpcPipeMvcServer://api/Foo/Add"); var response = await _ipcPipeMvcClient.GetStringAsync("api/Foo/Add?a=1&b=1"); Log($"[Response][Get] IpcPipeMvcServer://api/Foo/Add {response}"); } private async void PostFooButton_Click(object sender, RoutedEventArgs e) { if (_ipcPipeMvcClient is null) { return; } Log($"[Request][Post] IpcPipeMvcServer://api/Foo"); var response = await _ipcPipeMvcClient.PostAsync("api/Foo", new StringContent("")); var m = await response.Content.ReadAsStringAsync(); Log($"[Response][Post] IpcPipeMvcServer://api/Foo {response.StatusCode} {m}"); } private async void PostFooWithArgumentButton_Click(object sender, RoutedEventArgs e) { if (_ipcPipeMvcClient is null) { return; } Log($"[Request][Post] IpcPipeMvcServer://api/Foo"); var json = JsonSerializer.Serialize(new FooContent { Foo1 = "Foo PostFooWithArgumentButton", Foo2 = null, }); StringContent content = new StringContent(json, Encoding.UTF8, "application/json"); var response = await _ipcPipeMvcClient.PostAsync("api/Foo/PostFoo", content); var m = await response.Content.ReadAsStringAsync(); Log($"[Response][Post] IpcPipeMvcServer://api/Foo/PostFoo {response.StatusCode} {m}"); } private void MultiThreadButton_OnClick(object sender, RoutedEventArgs e) { if (_ipcPipeMvcClient is null) { return; } var count = 10; for (int i = 0; i < count; i++) { var id = i; Task.Run(async () => { Log($"[{id}][Request][Post] IpcPipeMvcServer://api/Foo"); var response = await _ipcPipeMvcClient.PostAsync("api/Foo", new StringContent("")); var m = await response.Content.ReadAsStringAsync(); Log($"[{id}][Response][Post] IpcPipeMvcServer://api/Foo {response.StatusCode} {m}"); var a = Random.Shared.Next(); var b = Random.Shared.Next(); Log($"[{id}][Request][Get] IpcPipeMvcServer://api/Foo/Add?a={a}&b={b}"); m = await _ipcPipeMvcClient.GetStringAsync($"api/Foo/Add?a={a}&b={b}"); Log($"[{id}][Response][Get] IpcPipeMvcServer://api/Foo/Add {m} {a}+{b}={a + b}"); Log($"[{id}][Request][Post] IpcPipeMvcServer://api/Foo"); response = await _ipcPipeMvcClient.PostAsync("api/Foo", new StringContent(BuildRandomText())); m = await response.Content.ReadAsStringAsync(); Log($"[Response][Post] IpcPipeMvcServer://api/Foo {response.StatusCode} {m}"); Log($"[{id}][Request][Post] IpcPipeMvcServer://api/Foo"); var json = JsonSerializer.Serialize(new FooContent { Foo1 = Random.Shared.Next(2) == 1 ? BuildRandomText() : null, Foo2 = Random.Shared.Next(2) == 1 ? BuildRandomText() : null, }); StringContent content = new StringContent(json, Encoding.UTF8, "application/json"); response = await _ipcPipeMvcClient.PostAsync("api/Foo/PostFoo", content); m = await response.Content.ReadAsStringAsync(); Log($"[{id}][Response][Post] IpcPipeMvcServer://api/Foo/PostFoo {response.StatusCode} {m}"); }); } } private static string BuildRandomText() { var count = 10; var text = new StringBuilder(); for (int i = 0; i < count; i++) { text.Append((char) Random.Shared.Next('a', 'z' + 1)); } return text.ToString(); } } ================================================ FILE: demo/PipeMvc/PipeMvcClientDemo/PipeMvcClientDemo.csproj ================================================  WinExe net6.0-windows enable true false ================================================ FILE: demo/PipeMvc/PipeMvcServerDemo/FooContent.cs ================================================ namespace PipeMvcServerDemo; public class FooContent { public string? Foo1 { set; get; } public string? Foo2 { set; get; } } ================================================ FILE: demo/PipeMvc/PipeMvcServerDemo/FooController.cs ================================================ using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace PipeMvcServerDemo; [Route("api/[controller]")] [ApiController] public class FooController : ControllerBase { public FooController(ILogger logger) { Logger = logger; } public ILogger Logger { get; } [HttpGet] public IActionResult Get() { Logger.LogInformation("FooController_Get"); return Ok(DateTime.Now.ToString()); } [HttpGet("Add")] public IActionResult Add(int a, int b) { Logger.LogInformation($"FooController_Add a={a};b={b}"); return Ok(a + b); } [HttpPost] public IActionResult Post() { Logger.LogInformation("FooController_Post"); return Ok($"POST {DateTime.Now}"); } [HttpPost("PostFoo")] public IActionResult PostFooContent(FooContent foo) { Logger.LogInformation($"FooController_PostFooContent Foo1={foo.Foo1};Foo2={foo.Foo2 ?? ""}"); return Ok($"PostFooContent Foo1={foo.Foo1};Foo2={foo.Foo2 ?? ""}"); } } ================================================ FILE: demo/PipeMvc/PipeMvcServerDemo/MainWindow.xaml ================================================  ================================================ FILE: demo/PipeMvc/PipeMvcServerDemo/MainWindow.xaml.cs ================================================ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; namespace PipeMvcServerDemo; /// /// MainWindow.xaml 的交互逻辑 /// public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } public void Log(string message) { Dispatcher.InvokeAsync(() => { TraceTextBlock.Text += message + "\r\n"; if (TraceTextBlock.Text.Length > 10000) { TraceTextBlock.Text = TraceTextBlock.Text[5000..]; } }); } } ================================================ FILE: demo/PipeMvc/PipeMvcServerDemo/PipeMvcServerDemo.csproj ================================================  net6.0-windows WinExe enable enable true false ================================================ FILE: demo/PipeMvc/PipeMvcServerDemo/Program.cs ================================================ using System.Windows; using System.Windows.Threading; using dotnetCampus.Ipc.PipeMvcServer; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; namespace PipeMvcServerDemo; public class Program { [STAThread] static void Main(string[] args) { Task.Run(() => RunMvc(args)); RunWpf(); } private static void RunWpf() { Application application = new Application(); application.Startup += (s, e) => { MainWindow mainWindow = new MainWindow(); mainWindow.Show(); }; application.Run(); } private static void RunMvc(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.WebHost.UsePipeIpcServer("PipeMvcServerDemo"); builder.Services.AddControllers(); builder.Services.AddLogging(loggingBuilder => { loggingBuilder.AddProvider(new DemoLogProvider()); }); var app = builder.Build(); app.MapControllers(); app.Run(); } class DemoLogProvider : ILoggerProvider { public ILogger CreateLogger(string categoryName) { return new DemoLogger(); } public void Dispose() { throw new NotImplementedException(); } class DemoLogger : ILogger { public IDisposable BeginScope(TState state) { return new Empty(); } class Empty : IDisposable { /// public void Dispose() { } } public bool IsEnabled(LogLevel logLevel) { return true; } public void Log(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func formatter) { var message = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}][{logLevel}][EventId={eventId.Id}:{eventId.Name}] {formatter(state, exception)}"; Application.Current?.Dispatcher.InvokeAsync(() => { var mainWindow = (MainWindow) Application.Current.MainWindow; mainWindow.Log(message); }); } } } } ================================================ FILE: demo/PipeMvc/PipeMvcServerDemo/Properties/launchSettings.json ================================================ { "iisSettings": { "windowsAuthentication": false, "anonymousAuthentication": true, "iisExpress": { "applicationUrl": "http://localhost:8638", "sslPort": 0 } }, "profiles": { "PipeMvcServerDemo": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": true, "applicationUrl": "http://localhost:5035", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } }, "IIS Express": { "commandName": "IISExpress", "launchBrowser": true, "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } ================================================ FILE: demo/PipeMvc/PipeMvcServerDemo/appsettings.Development.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } } } ================================================ FILE: demo/PipeMvc/PipeMvcServerDemo/appsettings.json ================================================ { "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*" } ================================================ FILE: demo/UnoDemo/IpcUno/.editorconfig ================================================ ; This file is for unifying the coding style for different editors and IDEs. ; More information at http://editorconfig.org # This file is the top-most EditorConfig file root = true ########################################## # Common Settings ########################################## [*] indent_style = space end_of_line = crlf trim_trailing_whitespace = true insert_final_newline = true charset = utf-8 ########################################## # File Extension Settings ########################################## [*.{yml,yaml}] indent_size = 2 [.vsconfig] indent_size = 2 end_of_line = lf [*.sln] indent_style = tab indent_size = 2 [*.{csproj,proj,projitems,shproj}] indent_size = 2 [*.{json,slnf}] indent_size = 2 end_of_line = lf [*.{props,targets}] indent_size = 2 [*.xaml] indent_size = 2 charset = utf-8-bom [*.xml] indent_size = 2 end_of_line = lf [*.plist] indent_size = 2 indent_style = tab end_of_line = lf [*.manifest] indent_size = 2 [*.appxmanifest] indent_size = 2 [*.{json,css,webmanifest}] indent_size = 2 end_of_line = lf [web.config] indent_size = 2 end_of_line = lf [*.sh] indent_size = 2 end_of_line = lf [*.cs] # EOL should be normalized by Git. See https://github.com/dotnet/format/issues/1099 end_of_line = unset # See https://github.com/dotnet/roslyn/issues/20356#issuecomment-310143926 trim_trailing_whitespace = false tab_width = 4 indent_size = 4 # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = true # Avoid "this." and "Me." if not necessary dotnet_style_qualification_for_field = false:suggestion dotnet_style_qualification_for_property = false:suggestion dotnet_style_qualification_for_method = false:suggestion dotnet_style_qualification_for_event = false:suggestion #### Naming styles #### # Naming rules dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion dotnet_naming_rule.types_should_be_pascal_case.symbols = types dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case # Symbol specifications dotnet_naming_symbols.interface.applicable_kinds = interface dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected dotnet_naming_symbols.interface.required_modifiers = dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected dotnet_naming_symbols.types.required_modifiers = dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected dotnet_naming_symbols.non_field_members.required_modifiers = # Naming styles dotnet_naming_style.begins_with_i.required_prefix = I dotnet_naming_style.begins_with_i.required_suffix = dotnet_naming_style.begins_with_i.word_separator = dotnet_naming_style.begins_with_i.capitalization = pascal_case dotnet_naming_style.pascal_case.required_prefix = dotnet_naming_style.pascal_case.required_suffix = dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case dotnet_naming_style.pascal_case.required_prefix = dotnet_naming_style.pascal_case.required_suffix = dotnet_naming_style.pascal_case.word_separator = dotnet_naming_style.pascal_case.capitalization = pascal_case dotnet_style_operator_placement_when_wrapping = beginning_of_line dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion dotnet_style_prefer_auto_properties = true:silent dotnet_style_object_initializer = true:suggestion dotnet_style_collection_initializer = true:suggestion dotnet_style_prefer_simplified_boolean_expressions = true:suggestion dotnet_style_prefer_conditional_expression_over_assignment = true:silent dotnet_style_prefer_conditional_expression_over_return = true:silent dotnet_style_explicit_tuple_names = true:suggestion dotnet_style_prefer_inferred_tuple_names = true:suggestion csharp_indent_labels = one_less_than_current csharp_using_directive_placement = outside_namespace:silent csharp_prefer_simple_using_statement = true:suggestion csharp_prefer_braces = true:silent csharp_style_namespace_declarations = block_scoped:silent csharp_style_prefer_method_group_conversion = true:silent csharp_style_prefer_top_level_statements = true:silent csharp_style_prefer_primary_constructors = true:suggestion csharp_style_expression_bodied_methods = false:silent csharp_style_expression_bodied_constructors = false:silent csharp_style_expression_bodied_operators = false:silent csharp_style_expression_bodied_properties = true:silent csharp_style_expression_bodied_indexers = true:silent csharp_style_expression_bodied_accessors = true:silent csharp_style_expression_bodied_lambdas = true:silent csharp_style_expression_bodied_local_functions = false:silent ================================================ FILE: demo/UnoDemo/IpcUno/.gitignore ================================================ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Ww][Ii][Nn]32/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ [Ll]ogs/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUnit *.VisualState.xml TestResult.xml nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # ASP.NET Scaffolding ScaffoldingReadMe.txt # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.obj *.iobj *.pch *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.tlog *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Coverlet is a free, cross platform Code Coverage Tool coverage*.json coverage*.xml coverage*.info # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx *.appxbundle *.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- [Bb]ackup.rdl *- [Bb]ackup ([0-9]).rdl *- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio 6 auto-generated project file (contains which files were open etc.) *.vbp # Visual Studio 6 workspace and project file (working project files containing files to include in project) *.dsw *.dsp # Visual Studio 6 technical files *.ncb *.aps # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # Visual Studio History (VSHistory) files .vshistory/ # BeatPulse healthcheck temp database healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ # Ionide (cross platform F# VS Code tools) working folder .ionide/ # Fody - auto-generated XML schema FodyWeavers.xsd # VS Code files for those working on multiple tools .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json *.code-workspace # Local History for Visual Studio Code .history/ # Windows Installer files from build outputs *.cab *.msi *.msix *.msm *.msp # JetBrains Rider *.sln.iml # Single Target Config solution-config.props # Windows Publish Profiles !**/*.Windows/Properties/PublishProfiles/*.pubxml ================================================ FILE: demo/UnoDemo/IpcUno/.vsconfig ================================================ { "version": "1.0", "components": [ "Microsoft.VisualStudio.Component.CoreEditor", "Microsoft.VisualStudio.Workload.CoreEditor", "Microsoft.NetCore.Component.SDK", "Microsoft.NetCore.Component.DevelopmentTools", "Microsoft.Net.ComponentGroup.DevelopmentPrerequisites", "Microsoft.VisualStudio.Component.TextTemplating", "Microsoft.VisualStudio.Component.Windows10SDK.19041", "Microsoft.VisualStudio.ComponentGroup.MSIX.Packaging", "Microsoft.VisualStudio.Component.ManagedDesktop.Prerequisites", "Microsoft.VisualStudio.Component.Debugger.JustInTime", "Microsoft.VisualStudio.Workload.ManagedDesktop", "Microsoft.Component.NetFX.Native", "Microsoft.VisualStudio.Component.Graphics", "Microsoft.VisualStudio.Component.Merq", "Microsoft.VisualStudio.Workload.NetCrossPlat", "Microsoft.VisualStudio.Workload.NetCoreTools" ] } ================================================ FILE: demo/UnoDemo/IpcUno/Directory.Build.props ================================================ enable enable portable True true $(NoWarn);NU1507;NETSDK1201;NETSDK1023;PRI257;CA1416;IDE0090 en false false false false false 8.0.0-rc.2.9373 1.10.0.1 2.6.0.1 1.3.0.1 false true 21.0 true 14.2 true 10.14 true 14.0 true 10.0.18362.0 10.0.18362.0 win-x86;win-x64;win-arm64 false ================================================ FILE: demo/UnoDemo/IpcUno/Directory.Build.targets ================================================  ================================================ FILE: demo/UnoDemo/IpcUno/Directory.Packages.props ================================================  ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/App.cs ================================================ namespace IpcUno { public class App : EmbeddingApplication { public Microsoft.UI.Dispatching.DispatcherQueue Dispatcher { private set; get; } = null!; protected Window? MainWindow { get; private set; } protected IHost? Host { get; private set; } protected async override void OnLaunched(LaunchActivatedEventArgs args) { var builder = this.CreateBuilder(args) // Add navigation support for toolkit controls such as TabBar and NavigationView .UseToolkitNavigation() #if MAUI_EMBEDDING .UseMauiEmbedding(maui => maui .UseMauiControls()) #endif .Configure(host => host #if DEBUG // Switch to Development environment when running in DEBUG .UseEnvironment(Environments.Development) #endif .UseLogging(configure: (context, logBuilder) => { // Configure log levels for different categories of logging logBuilder .SetMinimumLevel( context.HostingEnvironment.IsDevelopment() ? LogLevel.Information : LogLevel.Warning) // Default filters for core Uno Platform namespaces .CoreLogLevel(LogLevel.Warning); // Uno Platform namespace filter groups // Uncomment individual methods to see more detailed logging //// Generic Xaml events //logBuilder.XamlLogLevel(LogLevel.Debug); //// Layout specific messages //logBuilder.XamlLayoutLogLevel(LogLevel.Debug); //// Storage messages //logBuilder.StorageLogLevel(LogLevel.Debug); //// Binding related messages //logBuilder.XamlBindingLogLevel(LogLevel.Debug); //// Binder memory references tracking //logBuilder.BinderMemoryReferenceLogLevel(LogLevel.Debug); //// DevServer and HotReload related //logBuilder.HotReloadCoreLogLevel(LogLevel.Information); //// Debug JS interop //logBuilder.WebAssemblyLogLevel(LogLevel.Debug); }, enableUnoLogging: true) .UseConfiguration(configure: configBuilder => configBuilder .EmbeddedSource() .Section() ) .ConfigureServices((context, services) => { // TODO: Register your services //services.AddSingleton(); }) .UseNavigation(RegisterRoutes) ); MainWindow = builder.Window; #if DEBUG MainWindow.EnableHotReload(); #endif Dispatcher = MainWindow.DispatcherQueue; Host = await builder.NavigateAsync(); } private static void RegisterRoutes(IViewRegistry views, IRouteRegistry routes) { views.Register( new ViewMap(ViewModel: typeof(ShellViewModel)), new ViewMap(), new DataViewMap(), new DataViewMap() ); routes.Register( new RouteMap("", View: views.FindByViewModel(), Nested: new RouteMap[] { new RouteMap("Main", View: views.FindByViewModel()), new RouteMap("Second", View: views.FindByViewModel()), } ) ); } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/AppResources.xaml ================================================  ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Assets/SharedAssets.md ================================================ # Shared Assets See documentation about assets here: https://github.com/unoplatform/uno/blob/master/doc/articles/features/working-with-assets.md ## Here is a cheat sheet 1. Add the image file to the `Assets` directory of a shared project. 2. Set the build action to `Content`. 3. (Recommended) Provide an asset for various scales/dpi ### Examples ```text \Assets\Images\logo.scale-100.png \Assets\Images\logo.scale-200.png \Assets\Images\logo.scale-400.png \Assets\Images\scale-100\logo.png \Assets\Images\scale-200\logo.png \Assets\Images\scale-400\logo.png ``` ### Table of scales | Scale | WinUI | iOS/MacCatalyst | Android | |-------|:-----------:|:---------------:|:-------:| | `100` | scale-100 | @1x | mdpi | | `125` | scale-125 | N/A | N/A | | `150` | scale-150 | N/A | hdpi | | `200` | scale-200 | @2x | xhdpi | | `300` | scale-300 | @3x | xxhdpi | | `400` | scale-400 | N/A | xxxhdpi | ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Business/Models/AppConfig.cs ================================================ namespace IpcUno.Business.Models { public record AppConfig { public string? Environment { get; init; } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Business/Models/ConnectedPeerModel.cs ================================================ using System.Collections.ObjectModel; using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Messages; using dotnetCampus.Ipc.Pipes; using Windows.ApplicationModel.Core; using Windows.UI.Core; namespace IpcUno.Business.Models { public class ConnectedPeerModel { public ConnectedPeerModel() { Peer = null!; } public ConnectedPeerModel(PeerProxy peer) { Peer = peer; peer.MessageReceived += Peer_MessageReceived; } private void Peer_MessageReceived(object? sender, IPeerMessageArgs e) { var streamReader = new StreamReader(e.Message.Body.ToMemoryStream()); var message = streamReader.ReadToEnd(); _ = CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { AddMessage(PeerName, message); }); } public void AddMessage(string name, string message) { MessageList.Add($"{name} {DateTime.Now:yyyy/MM/dd hh:mm:ss.fff}:\r\n{message}"); } public ObservableCollection MessageList { get; } = new ObservableCollection(); public PeerProxy Peer { get; } public string PeerName => Peer.PeerName; } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Business/Models/Entity.cs ================================================ namespace IpcUno.Business.Models { public record Entity(string Name); } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Business/Models/IpcServerEntity.cs ================================================ namespace IpcUno.Business.Models { public record IpcServerEntity(string Name); } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/GlobalSuppressions.cs ================================================ // This file is used by Code Analysis to maintain SuppressMessage // attributes that are applied to this project. // Project-level suppressions either have no target or are given // a specific target and scoped to a namespace, type, member, etc. using System.Diagnostics.CodeAnalysis; [assembly: SuppressMessage("Interoperability", "CA1416:验证平台兼容性", Justification = "<挂起>")] ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/GlobalUsings.cs ================================================ global using System.Collections.Immutable; global using System.Windows.Input; global using Microsoft.Extensions.DependencyInjection; global using Windows.Networking.Connectivity; global using Windows.Storage; global using Microsoft.Extensions.Hosting; global using Microsoft.Extensions.Logging; global using Microsoft.UI.Xaml; global using Microsoft.UI.Xaml.Controls; global using Microsoft.UI.Xaml.Media; global using Microsoft.UI.Xaml.Navigation; global using Microsoft.Extensions.Options; global using IpcUno.Business.Models; global using IpcUno.Presentation; #if MAUI_EMBEDDING global using IpcUno.MauiControls; #endif global using Uno.UI; global using Windows.ApplicationModel; global using ApplicationExecutionState = Windows.ApplicationModel.Activation.ApplicationExecutionState; global using CommunityToolkit.Mvvm.ComponentModel; global using CommunityToolkit.Mvvm.Input; ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/IpcUno.csproj ================================================ $(TargetFrameworks);net8.0-windows10.0.19041 $(TargetFrameworks);net8.0; $(OverrideTargetFrameworks) true %(Filename) ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/AddConnectPage.xaml ================================================  添加设备 ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/AddConnectPage.xaml.cs ================================================ namespace IpcUno.Presentation { public sealed partial class AddConnectPage : Page { public AddConnectPage() { this.InitializeComponent(); } private void ConnectServerButton_OnClick(object sender, RoutedEventArgs e) { ServerConnecting?.Invoke(this, ServerNameTextBox.Text); } private void StartServerButton_OnClick(object sender, RoutedEventArgs e) { ServerStarting?.Invoke(this, ServerNameTextBox.Text); BuildServerName(); } private void BuildServerName() { ServerNameTextBox.Text = System.IO.Path.GetRandomFileName(); } public event EventHandler? ServerConnecting; public event EventHandler? ServerStarting; } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/ChatPage.xaml ================================================  ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/MainPage.xaml.cs ================================================ using System.Diagnostics; using IpcUno.Utils; namespace IpcUno.Presentation { public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); DataContextChanged += MainPage_DataContextChanged; Loaded += MainPage_Loaded; } private void MainPage_Loaded(object sender, RoutedEventArgs e) { ShowAddConnectPage(); } private void MainPage_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args) { // 在这个时机可以拿到 ViewModel 对象 ViewModel.AddedLogMessage += ViewModel_AddedLogMessage; } private void ViewModel_AddedLogMessage(object? sender, string message) { // 收到日志 LogTextBox.Text += $"{DateTime.Now:hh:mm:ss,fff} {message}\r\n"; // 延迟一下,防止界面还没刷新就执行滚动 _ = Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, () => { LogTextBox.ScrollToBottom(); }); } public MainViewModel ViewModel => (MainViewModel) DataContext; private void ConnectedPeerListView_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (e.AddedItems.Count == 1) { var connectedPeerModel = (ConnectedPeerModel) e.AddedItems[0]!; MainPanelContentControl.Content = new ChatPage(connectedPeerModel, ViewModel.CurrentServerName); } } private void AddConnectButton_Click(object sender, RoutedEventArgs e) { ShowAddConnectPage(); } private void ShowAddConnectPage() { ConnectedPeerListView.SelectedItem = null; AddConnectPage addConnectPage = new AddConnectPage(); addConnectPage.ServerConnecting += async (s, e) => { var serverName = e; await ViewModel.ConnectAsync(serverName); ConnectedPeerListView.SelectedItem = ViewModel.ConnectedPeerModelList.FirstOrDefault(t => t.PeerName == serverName); }; MainPanelContentControl.Content = addConnectPage; } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/MainViewModel.cs ================================================ using System.Collections.ObjectModel; using dotnetCampus.Ipc.Context; using dotnetCampus.Ipc.Pipes; using Microsoft.UI.Dispatching; using Windows.ApplicationModel.Core; using Windows.UI.Core; namespace IpcUno.Presentation { public partial class MainViewModel : ObservableObject, IInjectable { [ObservableProperty] private string _currentServerName = "dotnet_campus"; private readonly IpcProvider _ipcProvider; public ObservableCollection ConnectedPeerModelList { get; } = new ObservableCollection(); public MainViewModel(IpcServerEntity entity) { _currentServerName = entity.Name; _ipcProvider = new IpcProvider(_currentServerName); _ipcProvider.PeerConnected += IpcProvider_PeerConnected; _ipcProvider.StartServer(); } private void IpcProvider_PeerConnected(object? sender, dotnetCampus.Ipc.Context.PeerConnectedArgs e) { Log($"[被动连接] {e.Peer.PeerName}"); _ = AddPeer(e.Peer); } private async Task AddPeer(PeerProxy peer) { //var dispatcherQueue = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread(); // WinUI: null //var currentView = CoreApplication.GetCurrentView();// WinUI: System.Runtime.InteropServices.COMException:“Element not found. //var dispatcher = ((IpcUno.App) IpcUno.App.Current).Dispatcher; //await dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => //{ // var currentPeer = ConnectedPeerModelList.FirstOrDefault(temp => temp.PeerName == peer.PeerName); // if (currentPeer != null) // { // currentPeer.Peer.PeerConnectionBroken -= Peer_PeerConnectBroke; // ConnectedPeerModelList.Remove(currentPeer); // } // ConnectedPeerModelList.Add(new ConnectedPeerModel(peer)); // peer.PeerConnectionBroken += Peer_PeerConnectBroke; //}); var dispatcher = ((IpcUno.App) IpcUno.App.Current).Dispatcher; TaskCompletionSource source = new(); dispatcher.TryEnqueue(() => { var currentPeer = ConnectedPeerModelList.FirstOrDefault(temp => temp.PeerName == peer.PeerName); if (currentPeer != null) { currentPeer.Peer.PeerConnectionBroken -= Peer_PeerConnectBroke; ConnectedPeerModelList.Remove(currentPeer); } ConnectedPeerModelList.Add(new ConnectedPeerModel(peer)); peer.PeerConnectionBroken += Peer_PeerConnectBroke; source.SetResult(); }); await source.Task; } private void Peer_PeerConnectBroke(object? sender, IPeerConnectionBrokenArgs e) { var peer = (PeerProxy) sender!; Log($"[连接断开] {peer.PeerName}"); } private void Log(string message) { AddedLogMessage?.Invoke(this, message); } public event EventHandler? AddedLogMessage; public void Inject(IServiceProvider entity) { } public async Task ConnectAsync(string serverName) { Log($"[开始连接] {serverName}"); var peer = await _ipcProvider.GetAndConnectToPeerAsync(serverName).ConfigureAwait(false); await AddPeer(peer); Log($"[完成连接] {serverName}"); } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/SecondPage.xaml ================================================  ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/SecondPage.xaml.cs ================================================ namespace IpcUno.Presentation { public sealed partial class SecondPage : Page { public SecondPage() { this.InitializeComponent(); } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/SecondViewModel.cs ================================================ namespace IpcUno.Presentation { public partial record SecondViewModel(Entity Entity) { } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/ServerPage.xaml ================================================  ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/ServerPage.xaml.cs ================================================ namespace IpcUno.Presentation { public sealed partial class ServerPage : Page { public ServerPage() { this.InitializeComponent(); } public ServerViewModel ViewModel => (ServerViewModel) DataContext; } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/ServerViewModel.cs ================================================ namespace IpcUno.Presentation { public partial class ServerViewModel : ObservableObject { public ServerViewModel(INavigator navigator) { _navigator = navigator; } private readonly INavigator _navigator; [ObservableProperty] private string _currentServerName = "dotnet_campus"; [RelayCommand] private void NavigateMainPage() { _ = _navigator.NavigateViewModelAsync(this, data: new IpcServerEntity(CurrentServerName)); } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/Shell.xaml ================================================  ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/Shell.xaml.cs ================================================ namespace IpcUno.Presentation { public sealed partial class Shell : UserControl, IContentControlProvider { public Shell() { this.InitializeComponent(); } public ContentControl ContentControl => Splash; } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Presentation/ShellViewModel.cs ================================================ namespace IpcUno.Presentation { public class ShellViewModel { private readonly INavigator _navigator; public ShellViewModel( INavigator navigator) { _navigator = navigator; _ = Start(); } public async Task Start() { await _navigator.NavigateViewModelAsync(this); } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Strings/en/Resources.resw ================================================  text/microsoft-resx 2.0 System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 IpcUno-en ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Styles/ColorPaletteOverride.xaml ================================================  #5946D2 #FFFFFF #E5DEFF #170065 #6B4EA2 #FFFFFF #EBDDFF #220555 #0061A4 #FFFFFF #CFE4FF #001D36 #B3261E #F9DEDC #FFFFFF #410E0B #FCFBFF #1C1B1F #FFFFFF #1C1B1F #F2EFF5 #8B8494 #79747E #F4EFF4 #313033 #C8BFFF #5946D2 #C9C5D0 #C7BFFF #2A009F #4129BA #E4DFFF #CDC2DC #332D41 #433C52 #EDDFFF #9FCAFF #003258 #00497D #D1E4FF #FFB4AB #93000A #690005 #FFDAD6 #1C1B1F #E5E1E6 #302D37 #E6E1E5 #47464F #C9C5D0 #928F99 #1C1B1F #E6E1E5 #2A009F #C7BFFF #57545D ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Styles/MaterialFontsOverride.xaml ================================================  ms-appx:///Uno.Fonts.Roboto/Fonts/Roboto-Light.ttf#Roboto ms-appx:///Uno.Fonts.Roboto/Fonts/Roboto-Medium.ttf#Roboto ms-appx:///Uno.Fonts.Roboto/Fonts/Roboto-Regular.ttf#Roboto ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Utils/ScrollViewerExtensions.cs ================================================ namespace IpcUno.Utils { static class ScrollViewerExtensions { public static void ScrollToBottom(this TextBox textBox) { ScrollToBottomInner(textBox); } public static void ScrollToBottom(this ListView listView) { ScrollToBottomInner(listView); } private static void ScrollToBottomInner(UIElement element) { if (element.VisualDescendant() is { } scrollViewer) { scrollViewer.ChangeView(0.0f, scrollViewer.ExtentHeight, 1.0f, true); } } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Utils/TreeExtensions.cs ================================================ namespace IpcUno.Utils { static class TreeExtensions { public static T? VisualDescendant(this UIElement element) where T : DependencyObject => VisualDescendant((DependencyObject) element); public static T? VisualDescendant(DependencyObject element) where T : DependencyObject { if (element is T) { return (T) element; } T? foundElement = default; for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) { var child = VisualTreeHelper.GetChild(element, i); foundElement = VisualDescendant(child); if (foundElement != null) { break; } } return foundElement; } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/Utils/UISpyHelper.cs ================================================ using System.Diagnostics; namespace IpcUno.Utils { static class UISpyHelper { public static void Spy(this DependencyObject element) { Uno.Extensions.IndentedStringBuilder builder = new (); SpyInner(element, builder); var spyText = builder.ToString(); Debug.WriteLine(spyText); } private static void SpyInner(DependencyObject element, Uno.Extensions.IndentedStringBuilder builder) { var name = string.Empty; if (element is FrameworkElement frameworkElement) { name = frameworkElement.Name; } builder.AppendLine($"{name}({element.GetType().FullName})\r\n"); for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) { using var t = builder.Indent(); var child = VisualTreeHelper.GetChild(element, i); SpyInner(child, builder); } } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/appsettings.development.json ================================================ { "AppConfig": { "Environment": "Development" } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno/appsettings.json ================================================ { "AppConfig": { "Environment": "Production" } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno.Base/AppHead.xaml ================================================  ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno.Base/AppHead.xaml.cs ================================================ using Microsoft.UI.Xaml; using Uno.Resizetizer; namespace IpcUno { public sealed partial class AppHead : App { /// /// Initializes the singleton application object. This is the first line of authored code /// executed, and as such is the logical equivalent of main() or WinMain(). /// public AppHead() { this.InitializeComponent(); } /// /// Invoked when the application is launched normally by the end user. Other entry points /// will be used such as when the application is launched to open a specific file. /// /// Details about the launch request and process. protected override void OnLaunched(LaunchActivatedEventArgs args) { base.OnLaunched(args); MainWindow.SetWindowIcon(); } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno.Base/IpcUno.Base.csproj ================================================ net8.0 false ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno.Base/base.props ================================================ ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno.MauiControls/App.xaml ================================================  ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno.MauiControls/App.xaml.cs ================================================ namespace IpcUno.MauiControls { public partial class App : Application { public App() { InitializeComponent(); } } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno.MauiControls/AppBuilderExtensions.cs ================================================ namespace IpcUno { public static class AppBuilderExtensions { public static MauiAppBuilder UseMauiControls(this MauiAppBuilder builder) => builder .ConfigureFonts(fonts => { fonts.AddFont("IpcUno/Assets/Fonts/OpenSansRegular.ttf", "OpenSansRegular"); fonts.AddFont("IpcUno/Assets/Fonts/OpenSansSemibold.ttf", "OpenSansSemibold"); }); } } ================================================ FILE: demo/UnoDemo/IpcUno/IpcUno.MauiControls/EmbeddedControl.xaml ================================================