├── .dockerignore ├── .gitignore ├── LICENSE ├── Oxygen.sln ├── README.md ├── sample ├── Basic.yaml ├── ClienActorSample │ ├── ClienActorSample.csproj │ ├── HelloActorService.cs │ ├── HelloRepository.cs │ ├── IHelloRepository.cs │ └── MyActor.cs ├── Client │ ├── .dockerignore │ ├── CallServiceImpl.cs │ ├── Client.csproj │ ├── Dockerfile │ ├── Dockerfile.Debug │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ └── start.bat ├── DaprActorProxyGenerator │ ├── DaprActorProxyGenerator.csproj │ └── DefaultSourceGenerator.cs ├── RemoteInterface │ ├── ICallService.cs │ ├── IHelloService.cs │ └── RemoteInterface.csproj ├── RunBasic.bat ├── Server │ ├── .dockerignore │ ├── Dockerfile │ ├── Dockerfile.Debug │ ├── HelloEventHandler.cs │ ├── HelloServiceImpl.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Server.csproj │ └── start.bat ├── start-dapr-debug.yaml ├── start-dapr.yaml ├── start-sample.bat ├── stop-sample.bat └── test │ └── start-dapr-debug.yaml └── src ├── Oxygen.Client ├── Oxygen.Client.ServerProxyFactory │ ├── Implements │ │ ├── EventBus.cs │ │ ├── ServiceProxyFactory.cs │ │ └── StateManager.cs │ ├── Interface │ │ ├── IEventBus.cs │ │ ├── IServiceProxyFactory.cs │ │ └── IStateManager.cs │ ├── Module.cs │ └── Oxygen.Client.ServerProxyFactory.csproj └── Oxygen.Client.ServerSymbol │ ├── Actors │ └── ActorSendDto.cs │ ├── Events │ ├── DefaultEventHandlerResponse.cs │ ├── EventHandleRequest.cs │ ├── EventHandleRequestData.cs │ ├── EventHandleRequestExtension.cs │ ├── EventHandlerAttribute.cs │ ├── IActorService.cs │ └── IEventHandler.cs │ ├── FuncType.cs │ ├── Oxygen.Client.ServerSymbol.csproj │ ├── RemoteFuncAttribute.cs │ ├── RemoteServiceAttribute.cs │ └── Store │ └── StateStore.cs ├── Oxygen.Mesh └── Oxygen.Mesh.Dapr │ ├── ActorServiceFactory.cs │ ├── BaseActorService.cs │ ├── BasicActor.cs │ ├── Model │ └── ActorStateModel.cs │ ├── Oxygen.Mesh.Dapr.csproj │ ├── OxygenActorStartup.cs │ └── ProxyCodeGeneratorTemplate.cs ├── Oxygen.Server └── Oxygen.Server.Kestrel │ ├── Implements │ ├── BaseRequestDelegate.cs │ ├── HttpMessageHandler.cs │ ├── KestrelServerHandler.cs │ ├── OxygenApplication.cs │ ├── OxygenHostService.cs │ ├── OxygenStartup.cs │ ├── RequestDelegate.cs │ └── RequestDelegateFactory.cs │ ├── Interface │ ├── IMessageHandler.cs │ ├── IServerHandler.cs │ ├── MessageType.cs │ └── Model │ │ └── SubscribeModel.cs │ ├── Module.cs │ └── Oxygen.Server.Kestrel.csproj └── Oxygen ├── Oxygen.Common ├── DaprConfig.cs ├── Implements │ ├── ConsoleLog.cs │ ├── HttpContextExtension.cs │ ├── InProcessEventBus │ │ ├── InProcessEventBusManager.cs │ │ ├── InProcessPipline.cs │ │ ├── InProcessPiplineFactory.cs │ │ └── SubscribeInProcessFactory.cs │ ├── JsonConverters │ │ └── TextJsonConverter.cs │ ├── OxygenHttpContextWapper.cs │ ├── OxygenIocContainer.cs │ ├── ReflectionHelper.cs │ └── SerializeImpl.cs ├── Interface │ ├── IInProcessEventBus.cs │ ├── ILogger.cs │ ├── ISerialize.cs │ └── ISubscribeInProcessFactory.cs ├── Module.cs ├── Oxygen.Common.csproj └── Properties │ └── launchSettings.json ├── Oxygen.IocModule ├── ContainerBuilderExtension.cs └── Oxygen.IocModule.csproj └── Oxygen.ProxyGenerator ├── Implements ├── LocalMethodAopProvider.cs ├── RemoteDispatchProxy.cs ├── RemoteMessageSender.cs ├── RemoteMessageSenderDelegate.cs └── RemoteProxyGenerator.cs ├── Interface ├── IRemoteMessageSender.cs ├── IRemoteMessageSenderDelegate.cs └── SendType.cs ├── Module.cs └── Oxygen.ProxyGenerator.csproj /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。 3 | ################################################################################ 4 | 5 | .vs 6 | */bin 7 | */obj 8 | *\pub 9 | bin 10 | Debug 11 | Release 12 | obj 13 | *.user 14 | /nugetpack 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 sd797994 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Oxygen.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.30413.136 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{53585DF5-6F35-488D-B2D9-43E58F77D9B9}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Oxygen", "Oxygen", "{45771243-E9BA-4190-89A5-61C65D8AA4C9}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Oxygen.Client", "Oxygen.Client", "{968ADFFE-171A-41DD-909B-B2861A30A9AF}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Oxygen.Server", "Oxygen.Server", "{CAD0B964-AD48-4C63-A8F0-6E1BED350BA8}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Oxygen.Mesh", "Oxygen.Mesh", "{540472F6-CDDB-4E09-886E-BE16EEC65A00}" 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{F8BAEF85-9B04-4D46-9E57-52DF40CC1185}" 17 | EndProject 18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oxygen.Server.Kestrel", "src\Oxygen.Server\Oxygen.Server.Kestrel\Oxygen.Server.Kestrel.csproj", "{838884C4-2D6C-4AF6-8EED-EE27947B7FE2}" 19 | EndProject 20 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oxygen.Common", "src\Oxygen\Oxygen.Common\Oxygen.Common.csproj", "{716437F1-0715-4D6A-8F39-03DDADFDF3A1}" 21 | EndProject 22 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oxygen.ProxyGenerator", "src\Oxygen\Oxygen.ProxyGenerator\Oxygen.ProxyGenerator.csproj", "{E4A9406E-C07D-477C-A1A9-52586725B25B}" 23 | EndProject 24 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oxygen.Client.ServerProxyFactory", "src\Oxygen.Client\Oxygen.Client.ServerProxyFactory\Oxygen.Client.ServerProxyFactory.csproj", "{BB642028-45C9-438F-BAE4-A22E582359C1}" 25 | EndProject 26 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oxygen.Client.ServerSymbol", "src\Oxygen.Client\Oxygen.Client.ServerSymbol\Oxygen.Client.ServerSymbol.csproj", "{58D8475D-C23D-4B4B-ABE0-32E3199FCBD0}" 27 | EndProject 28 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oxygen.Mesh.Dapr", "src\Oxygen.Mesh\Oxygen.Mesh.Dapr\Oxygen.Mesh.Dapr.csproj", "{F4748E0B-C033-4293-BCB1-7370A55BB02D}" 29 | EndProject 30 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RemoteInterface", "sample\RemoteInterface\RemoteInterface.csproj", "{B6E9A444-7A28-4964-83E5-F84CC1F6E945}" 31 | EndProject 32 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Client", "sample\Client\Client.csproj", "{3FB24A03-E88D-4FBC-B601-555D59389931}" 33 | EndProject 34 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server", "sample\Server\Server.csproj", "{6C5E0E28-5B9B-4AB9-A122-27DF9F4C2333}" 35 | EndProject 36 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Oxygen.IocModule", "src\Oxygen\Oxygen.IocModule\Oxygen.IocModule.csproj", "{5BE04D5E-F3C2-4043-A472-D1CE61C795A6}" 37 | EndProject 38 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DaprActorProxyGenerator", "sample\DaprActorProxyGenerator\DaprActorProxyGenerator.csproj", "{6B9F0D86-B745-4203-97C1-1E59CCFE2FD7}" 39 | EndProject 40 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ClienActorSample", "sample\ClienActorSample\ClienActorSample.csproj", "{DACFCFEB-B304-4A46-80DB-BE34048E3F1A}" 41 | EndProject 42 | Global 43 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 44 | Debug|Any CPU = Debug|Any CPU 45 | Release|Any CPU = Release|Any CPU 46 | EndGlobalSection 47 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 48 | {838884C4-2D6C-4AF6-8EED-EE27947B7FE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {838884C4-2D6C-4AF6-8EED-EE27947B7FE2}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {838884C4-2D6C-4AF6-8EED-EE27947B7FE2}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {838884C4-2D6C-4AF6-8EED-EE27947B7FE2}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {716437F1-0715-4D6A-8F39-03DDADFDF3A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {716437F1-0715-4D6A-8F39-03DDADFDF3A1}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {716437F1-0715-4D6A-8F39-03DDADFDF3A1}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {716437F1-0715-4D6A-8F39-03DDADFDF3A1}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {E4A9406E-C07D-477C-A1A9-52586725B25B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {E4A9406E-C07D-477C-A1A9-52586725B25B}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {E4A9406E-C07D-477C-A1A9-52586725B25B}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {E4A9406E-C07D-477C-A1A9-52586725B25B}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {BB642028-45C9-438F-BAE4-A22E582359C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {BB642028-45C9-438F-BAE4-A22E582359C1}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {BB642028-45C9-438F-BAE4-A22E582359C1}.Release|Any CPU.ActiveCfg = Release|Any CPU 63 | {BB642028-45C9-438F-BAE4-A22E582359C1}.Release|Any CPU.Build.0 = Release|Any CPU 64 | {58D8475D-C23D-4B4B-ABE0-32E3199FCBD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 65 | {58D8475D-C23D-4B4B-ABE0-32E3199FCBD0}.Debug|Any CPU.Build.0 = Debug|Any CPU 66 | {58D8475D-C23D-4B4B-ABE0-32E3199FCBD0}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {58D8475D-C23D-4B4B-ABE0-32E3199FCBD0}.Release|Any CPU.Build.0 = Release|Any CPU 68 | {F4748E0B-C033-4293-BCB1-7370A55BB02D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 69 | {F4748E0B-C033-4293-BCB1-7370A55BB02D}.Debug|Any CPU.Build.0 = Debug|Any CPU 70 | {F4748E0B-C033-4293-BCB1-7370A55BB02D}.Release|Any CPU.ActiveCfg = Release|Any CPU 71 | {F4748E0B-C033-4293-BCB1-7370A55BB02D}.Release|Any CPU.Build.0 = Release|Any CPU 72 | {B6E9A444-7A28-4964-83E5-F84CC1F6E945}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 73 | {B6E9A444-7A28-4964-83E5-F84CC1F6E945}.Debug|Any CPU.Build.0 = Debug|Any CPU 74 | {B6E9A444-7A28-4964-83E5-F84CC1F6E945}.Release|Any CPU.ActiveCfg = Release|Any CPU 75 | {B6E9A444-7A28-4964-83E5-F84CC1F6E945}.Release|Any CPU.Build.0 = Release|Any CPU 76 | {3FB24A03-E88D-4FBC-B601-555D59389931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 77 | {3FB24A03-E88D-4FBC-B601-555D59389931}.Debug|Any CPU.Build.0 = Debug|Any CPU 78 | {3FB24A03-E88D-4FBC-B601-555D59389931}.Release|Any CPU.ActiveCfg = Release|Any CPU 79 | {3FB24A03-E88D-4FBC-B601-555D59389931}.Release|Any CPU.Build.0 = Release|Any CPU 80 | {6C5E0E28-5B9B-4AB9-A122-27DF9F4C2333}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 81 | {6C5E0E28-5B9B-4AB9-A122-27DF9F4C2333}.Debug|Any CPU.Build.0 = Debug|Any CPU 82 | {6C5E0E28-5B9B-4AB9-A122-27DF9F4C2333}.Release|Any CPU.ActiveCfg = Release|Any CPU 83 | {6C5E0E28-5B9B-4AB9-A122-27DF9F4C2333}.Release|Any CPU.Build.0 = Release|Any CPU 84 | {5BE04D5E-F3C2-4043-A472-D1CE61C795A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 85 | {5BE04D5E-F3C2-4043-A472-D1CE61C795A6}.Debug|Any CPU.Build.0 = Debug|Any CPU 86 | {5BE04D5E-F3C2-4043-A472-D1CE61C795A6}.Release|Any CPU.ActiveCfg = Release|Any CPU 87 | {5BE04D5E-F3C2-4043-A472-D1CE61C795A6}.Release|Any CPU.Build.0 = Release|Any CPU 88 | {6B9F0D86-B745-4203-97C1-1E59CCFE2FD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 89 | {6B9F0D86-B745-4203-97C1-1E59CCFE2FD7}.Debug|Any CPU.Build.0 = Debug|Any CPU 90 | {6B9F0D86-B745-4203-97C1-1E59CCFE2FD7}.Release|Any CPU.ActiveCfg = Release|Any CPU 91 | {6B9F0D86-B745-4203-97C1-1E59CCFE2FD7}.Release|Any CPU.Build.0 = Release|Any CPU 92 | {DACFCFEB-B304-4A46-80DB-BE34048E3F1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 93 | {DACFCFEB-B304-4A46-80DB-BE34048E3F1A}.Debug|Any CPU.Build.0 = Debug|Any CPU 94 | {DACFCFEB-B304-4A46-80DB-BE34048E3F1A}.Release|Any CPU.ActiveCfg = Release|Any CPU 95 | {DACFCFEB-B304-4A46-80DB-BE34048E3F1A}.Release|Any CPU.Build.0 = Release|Any CPU 96 | EndGlobalSection 97 | GlobalSection(SolutionProperties) = preSolution 98 | HideSolutionNode = FALSE 99 | EndGlobalSection 100 | GlobalSection(NestedProjects) = preSolution 101 | {45771243-E9BA-4190-89A5-61C65D8AA4C9} = {53585DF5-6F35-488D-B2D9-43E58F77D9B9} 102 | {968ADFFE-171A-41DD-909B-B2861A30A9AF} = {53585DF5-6F35-488D-B2D9-43E58F77D9B9} 103 | {CAD0B964-AD48-4C63-A8F0-6E1BED350BA8} = {53585DF5-6F35-488D-B2D9-43E58F77D9B9} 104 | {540472F6-CDDB-4E09-886E-BE16EEC65A00} = {53585DF5-6F35-488D-B2D9-43E58F77D9B9} 105 | {838884C4-2D6C-4AF6-8EED-EE27947B7FE2} = {CAD0B964-AD48-4C63-A8F0-6E1BED350BA8} 106 | {716437F1-0715-4D6A-8F39-03DDADFDF3A1} = {45771243-E9BA-4190-89A5-61C65D8AA4C9} 107 | {E4A9406E-C07D-477C-A1A9-52586725B25B} = {45771243-E9BA-4190-89A5-61C65D8AA4C9} 108 | {BB642028-45C9-438F-BAE4-A22E582359C1} = {968ADFFE-171A-41DD-909B-B2861A30A9AF} 109 | {58D8475D-C23D-4B4B-ABE0-32E3199FCBD0} = {968ADFFE-171A-41DD-909B-B2861A30A9AF} 110 | {F4748E0B-C033-4293-BCB1-7370A55BB02D} = {540472F6-CDDB-4E09-886E-BE16EEC65A00} 111 | {B6E9A444-7A28-4964-83E5-F84CC1F6E945} = {F8BAEF85-9B04-4D46-9E57-52DF40CC1185} 112 | {3FB24A03-E88D-4FBC-B601-555D59389931} = {F8BAEF85-9B04-4D46-9E57-52DF40CC1185} 113 | {6C5E0E28-5B9B-4AB9-A122-27DF9F4C2333} = {F8BAEF85-9B04-4D46-9E57-52DF40CC1185} 114 | {5BE04D5E-F3C2-4043-A472-D1CE61C795A6} = {45771243-E9BA-4190-89A5-61C65D8AA4C9} 115 | {6B9F0D86-B745-4203-97C1-1E59CCFE2FD7} = {F8BAEF85-9B04-4D46-9E57-52DF40CC1185} 116 | {DACFCFEB-B304-4A46-80DB-BE34048E3F1A} = {F8BAEF85-9B04-4D46-9E57-52DF40CC1185} 117 | EndGlobalSection 118 | GlobalSection(ExtensibilityGlobals) = postSolution 119 | SolutionGuid = {B216A394-6D76-4027-9E89-9E4882077CC4} 120 | EndGlobalSection 121 | EndGlobal 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Oxygen-Dapr 2 | 一款基于dapr的.netRPC封装。统一了请求编程模型(服务调用/事件/状态&Actor)和服务(基于kestrel router/eventhandle/actorservice提供直接对应用服务的访问) 3 | -------------------------------------------------------------------------------- /sample/Basic.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: postgres 5 | namespace: infrastructure 6 | spec: 7 | selector: 8 | matchLabels: 9 | app: postgres 10 | replicas: 1 11 | template: 12 | metadata: 13 | labels: 14 | app: postgres 15 | spec: 16 | containers: 17 | - name: postgres 18 | image: postgres:latest 19 | imagePullPolicy: IfNotPresent 20 | ports: 21 | - containerPort: 5432 22 | name: web 23 | env: 24 | - name: POSTGRES_PASSWORD 25 | value: "Mytestpwd#123" 26 | - name: TZ 27 | value: "Asia/Shanghai" 28 | --- 29 | apiVersion: v1 30 | kind: Service 31 | metadata: 32 | name: postgres 33 | namespace: infrastructure 34 | spec: 35 | type: NodePort 36 | selector: 37 | app: postgres 38 | ports: 39 | - protocol: TCP 40 | port: 5432 41 | targetPort: 5432 42 | nodePort: 30432 43 | name: tcp-postgres 44 | --- 45 | apiVersion: apps/v1 46 | kind: Deployment 47 | metadata: 48 | name: redis 49 | namespace: infrastructure 50 | spec: 51 | selector: 52 | matchLabels: 53 | app: redis 54 | replicas: 1 55 | template: 56 | metadata: 57 | labels: 58 | app: redis 59 | spec: 60 | containers: 61 | - name: redis 62 | image: redis:latest 63 | imagePullPolicy: IfNotPresent 64 | ports: 65 | - containerPort: 6379 66 | name: web 67 | env: 68 | - name: TZ 69 | value: "Asia/Shanghai" 70 | --- 71 | apiVersion: v1 72 | kind: Service 73 | metadata: 74 | name: redis 75 | namespace: infrastructure 76 | spec: 77 | selector: 78 | app: redis 79 | ports: 80 | - protocol: TCP 81 | port: 6379 82 | targetPort: 6379 83 | name: tcp-redis 84 | --- 85 | apiVersion: dapr.io/v1alpha1 86 | kind: Component 87 | metadata: 88 | name: statestore 89 | namespace: default 90 | spec: 91 | type: state.redis 92 | version: v1 93 | metadata: 94 | - name: actorStateStore 95 | value: "true" 96 | - name: redisHost 97 | value: redis.infrastructure.svc.cluster.local:6379 98 | - name: keyPrefix 99 | value: none 100 | --- 101 | apiVersion: dapr.io/v1alpha1 102 | kind: Component 103 | metadata: 104 | name: pubsub 105 | namespace: default 106 | spec: 107 | type: pubsub.redis 108 | version: v1 109 | metadata: 110 | - name: redisHost 111 | value: redis.infrastructure.svc.cluster.local:6379 -------------------------------------------------------------------------------- /sample/ClienActorSample/ClienActorSample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /sample/ClienActorSample/HelloActorService.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Microsoft.Extensions.Logging; 3 | using Oxygen.Client.ServerProxyFactory.Interface; 4 | using Oxygen.Mesh.Dapr; 5 | using Oxygen.Mesh.Dapr.Model; 6 | using RemoteInterface; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | 13 | namespace ClienActorSample 14 | { 15 | public class HelloActorService : BaseActorService, IHelloActorService 16 | { 17 | private readonly ILogger logger; 18 | private readonly IStateManager stateManager; 19 | private readonly IHelloRepository helloRepository; 20 | public HelloActorService(ILogger logger, IStateManager stateManager, IHelloRepository helloRepository) 21 | { 22 | this.logger = logger; 23 | this.stateManager = stateManager; 24 | this.helloRepository = helloRepository; 25 | } 26 | public async Task GetUserInfoByActor(ActorInputDto input) 27 | { 28 | if (ActorData == null) 29 | ActorData = await helloRepository.GetData(); 30 | ActorData.Index++; 31 | if (ActorData.Index == 10) 32 | ActorData.DeleteModel(); 33 | return await Task.FromResult(new OutDto() { Word = $"hello {input.Name},your id is {ActorData.Index}" }); 34 | } 35 | 36 | public override async Task SaveData(MyActor data, ILifetimeScope scope) 37 | { 38 | if (data != null) 39 | await helloRepository.SaveData(data); 40 | await Task.CompletedTask; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /sample/ClienActorSample/HelloRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ClienActorSample 8 | { 9 | public class HelloRepository : IHelloRepository 10 | { 11 | public Guid? Id { get; set; } 12 | public HelloRepository() 13 | { 14 | Id = Id ?? Guid.NewGuid(); 15 | } 16 | public async Task SaveData(MyActor actor) 17 | { 18 | Console.WriteLine($"仓储实例ID:{Id},持久化对象:{actor?.Index}"); 19 | await Task.CompletedTask; 20 | } 21 | 22 | public async Task GetData() 23 | { 24 | return await Task.FromResult(new MyActor() { Index = 0, AutoSave = true }); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /sample/ClienActorSample/IHelloRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace ClienActorSample 8 | { 9 | public interface IHelloRepository 10 | { 11 | Task GetData(); 12 | Task SaveData(MyActor actor); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /sample/ClienActorSample/MyActor.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Mesh.Dapr.Model; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace ClienActorSample 9 | { 10 | public record MyActor : ActorStateModel 11 | { 12 | public int Index { get; set; } 13 | public override bool AutoSave { get; set; } 14 | public override int ReminderSeconds { get => 1; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /sample/Client/.dockerignore: -------------------------------------------------------------------------------- 1 | *.yaml 2 | *.bat 3 | *.sh -------------------------------------------------------------------------------- /sample/Client/CallServiceImpl.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Dapr.Actors; 3 | using Dapr.Actors.Client; 4 | using Microsoft.Extensions.Logging; 5 | using Oxygen.Client.ServerProxyFactory.Interface; 6 | using Oxygen.Common.Interface; 7 | using Oxygen.Mesh.Dapr; 8 | using Oxygen.Mesh.Dapr.Model; 9 | using RemoteInterface; 10 | using System; 11 | using System.Collections.Concurrent; 12 | using System.Collections.Generic; 13 | using System.Diagnostics; 14 | using System.IO; 15 | using System.Linq; 16 | using System.Net.Http; 17 | using System.Reflection; 18 | using System.Text; 19 | using System.Text.Json; 20 | using System.Text.Json.Serialization; 21 | using System.Threading; 22 | using System.Threading.Tasks; 23 | 24 | namespace Client 25 | { 26 | public class CallServiceImpl : ICallService 27 | { 28 | private readonly IServiceProxyFactory serviceProxyFactory; 29 | private readonly IEventBus eventBus; 30 | private readonly IStateManager stateManager; 31 | private readonly ISerialize serialize; 32 | public CallServiceImpl(IServiceProxyFactory serviceProxyFactory, ISerialize serialize, IEventBus eventBus, IStateManager stateManager) 33 | { 34 | this.serviceProxyFactory = serviceProxyFactory; 35 | this.eventBus = eventBus; 36 | this.stateManager = stateManager; 37 | this.serialize = serialize; 38 | } 39 | public async Task RemoteCallTest(InputDto input) 40 | { 41 | var helloService = serviceProxyFactory.CreateProxy(); 42 | var test = await helloService.GetHtml(); 43 | var helloactorService = serviceProxyFactory.CreateActorProxy(); 44 | await stateManager.SetState(new TestStateDto("mykey", true)); 45 | var getState = await stateManager.GetState(new TestStateDto("mykey")); 46 | var delState = await stateManager.DelState(new TestStateDto("mykey")); 47 | var invokeresult = await helloService.GetUserInfo(new InputDto() { name = "xiaoming" }); 48 | var invokenoinputresult = await helloService.Test(); 49 | var eventresult = await eventBus.SendEvent("test", new TestEventDto() { myword = "abc" }); 50 | var actorresult = await helloactorService.GetUserInfoByActor(new ActorInputDto() { Name = "xiaoming", ActorId = "1" }); 51 | return new InputDto() { name = $"RPC无参调用成功,回调:{JsonSerializer.Serialize(invokenoinputresult)},RPC有参调用成功,回调:{JsonSerializer.Serialize(invokeresult)},事件发送{(eventresult != null ? "成功" : "失败")},状态写入成功,值:{getState},actor调用成功,回调:{JsonSerializer.Serialize(actorresult)}" }; 52 | } 53 | public async Task MultipleTest(MultipleTestInput input) 54 | { 55 | var max = input.Times <= 0 ? 1 : input.Times; 56 | var succ = 0; 57 | var fail = 0; 58 | var _event = new AutoResetEvent(false); 59 | ConcurrentBag times = new ConcurrentBag(); 60 | Stopwatch _sw = new Stopwatch(); 61 | _sw.Start(); 62 | Parallel.For(0, max, async i => 63 | { 64 | var helloService = serviceProxyFactory.CreateProxy(); 65 | Stopwatch _sw_item = new Stopwatch(); 66 | _sw_item.Start(); 67 | var invokeresult = await helloService.GetUserInfo(new InputDto() { name = "小明" }); 68 | var eventresult = await eventBus.SendEvent("test", new TestEventDto() { myword = "abc" }); 69 | _sw_item.Stop(); 70 | if (invokeresult != null) 71 | { 72 | Interlocked.Increment(ref succ); 73 | times.Add(_sw_item.ElapsedMilliseconds); 74 | } 75 | else 76 | Interlocked.Increment(ref fail); 77 | if (succ + fail == max) 78 | _event.Set(); 79 | }); 80 | _event.WaitOne(); 81 | _sw.Stop(); 82 | return await Task.FromResult(new MultipleTestOutput() 83 | { 84 | AllTimes = input.Times, 85 | SuccTimes = succ, 86 | FailTimes = fail, 87 | CustTimes = _sw.ElapsedMilliseconds, 88 | Detail = string.Join(",", times.Where(x => x > 100).ToList()) 89 | }); 90 | } 91 | } 92 | 93 | } -------------------------------------------------------------------------------- /sample/Client/Client.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /sample/Client/Dockerfile: -------------------------------------------------------------------------------- 1 | from mcr.microsoft.com/dotnet/aspnet:8.0 2 | WORKDIR /app 3 | COPY /pub . 4 | RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone 5 | ENTRYPOINT ["dotnet", "Client.dll"] -------------------------------------------------------------------------------- /sample/Client/Dockerfile.Debug: -------------------------------------------------------------------------------- 1 | from mcr.microsoft.com/dotnet/aspnet:8.0 2 | WORKDIR /app 3 | RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone 4 | ENTRYPOINT ["dotnet", "Client.dll"] -------------------------------------------------------------------------------- /sample/Client/Program.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Autofac.Extensions.DependencyInjection; 3 | using ClienActorSample; 4 | using Client; 5 | using Microsoft.Extensions.Hosting; 6 | using Oxygen.IocModule; 7 | using Oxygen.Mesh.Dapr; 8 | using Oxygen.Server.Kestrel.Implements; 9 | using RemoteInterface; 10 | 11 | var builder = OxygenApplication.CreateBuilder(config => 12 | { 13 | config.Port = 80; 14 | config.PubSubCompentName = "pubsub"; 15 | config.StateStoreCompentName = "statestore"; 16 | config.TracingHeaders = "Authentication"; 17 | config.UseCors = true; 18 | }); 19 | OxygenActorStartup.ConfigureServices(builder.Services); 20 | builder.Host.ConfigureContainer(builder => 21 | { 22 | //注入oxygen依赖 23 | builder.RegisterOxygenModule(); 24 | //注入测试demo 25 | builder.RegisterType().As().InstancePerLifetimeScope(); 26 | builder.RegisterType().As().InstancePerLifetimeScope(); 27 | builder.RegisterType().As().InstancePerLifetimeScope(); 28 | }); 29 | builder.Services.AddAutofac(); 30 | builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); 31 | var app = builder.Build(); 32 | OxygenActorStartup.Configure(app, app.Services); 33 | await app.RunAsync(); -------------------------------------------------------------------------------- /sample/Client/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:51918/", 7 | "sslPort": 44384 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "Client": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /sample/Client/start.bat: -------------------------------------------------------------------------------- 1 | dotnet publish -c release 2 | cd bin/release/netcoreapp3.1/publish/ 3 | Client.exe -------------------------------------------------------------------------------- /sample/DaprActorProxyGenerator/DaprActorProxyGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | $(GetTargetPathDependsOn);GetDependencyTargetPaths 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /sample/DaprActorProxyGenerator/DefaultSourceGenerator.cs: -------------------------------------------------------------------------------- 1 | using ClienActorSample; 2 | using Microsoft.CodeAnalysis; 3 | using Microsoft.CodeAnalysis.Text; 4 | using Oxygen.Mesh.Dapr.ActorProxyGenerator; 5 | using RemoteInterface; 6 | using System.Diagnostics; 7 | using System.Text; 8 | 9 | namespace DaprActorProxyGenerator 10 | { 11 | [Generator] 12 | public class DefaultSourceGenerator : ISourceGenerator 13 | { 14 | public void Execute(GeneratorExecutionContext context) 15 | { 16 | var proxylist = ProxyCodeGeneratorTemplate.GetTemplate(); 17 | foreach (var item in proxylist) 18 | { 19 | context.AddSource(item.sourceName, SourceText.From(item.sourceCode, Encoding.UTF8)); 20 | } 21 | } 22 | 23 | public void Initialize(GeneratorInitializationContext context) 24 | { 25 | Debugger.Launch(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /sample/RemoteInterface/ICallService.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerSymbol; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Net.Http; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace RemoteInterface 9 | { 10 | [RemoteService("callservice", "call")] 11 | public interface ICallService 12 | { 13 | [RemoteFunc] 14 | Task RemoteCallTest(InputDto input); 15 | [RemoteFunc] 16 | Task MultipleTest(MultipleTestInput input); 17 | } 18 | public class MultipleTestInput 19 | { 20 | public int Times { get; set; } 21 | } 22 | public class MultipleTestOutput 23 | { 24 | public int AllTimes { get; set; } 25 | public int SuccTimes { get; set; } 26 | public int FailTimes { get; set; } 27 | public long CustTimes { get; set; } 28 | public string Detail { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /sample/RemoteInterface/IHelloService.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerSymbol; 2 | using Oxygen.Client.ServerSymbol.Actors; 3 | using Oxygen.Client.ServerSymbol.Events; 4 | using Oxygen.Client.ServerSymbol.Store; 5 | using Oxygen.Mesh.Dapr; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace RemoteInterface 12 | { 13 | [RemoteService("testservice", "hello")] 14 | public interface IHelloService 15 | { 16 | [RemoteFunc(FuncType.Invoke)] 17 | Task GetUserInfo(InputDto input); 18 | [RemoteFunc(FuncType.Invoke)] 19 | Task GetState(InputDto input); 20 | [RemoteFunc(FuncType.Invoke)] 21 | Task Test(); 22 | [RemoteFunc] 23 | Task GetHtml(); 24 | } 25 | [RemoteService("testservice", "helloactor")] 26 | public interface IHelloActorService : IActorService 27 | { 28 | [RemoteFunc(FuncType.Actor)] 29 | Task GetUserInfoByActor(ActorInputDto input); 30 | } 31 | public class ActorInputDto : ActorSendDto 32 | { 33 | public string Name { get; set; } 34 | public override string ActorId { get; set; } 35 | } 36 | public class InputDto 37 | { 38 | public string name { get; set; } 39 | public int id { get; set; } 40 | public bool getbool { get; set; } 41 | } 42 | public class OutDto 43 | { 44 | public string Word { get; set; } 45 | } 46 | public class TestEventDto 47 | { 48 | public string myword { get; set; } 49 | } 50 | public class TestStateDto : StateStore 51 | { 52 | public TestStateDto(string key) 53 | { 54 | this.Key = key; 55 | } 56 | public TestStateDto(string key, object data) 57 | { 58 | this.Key = key; 59 | this.Data = data; 60 | this.TtlInSeconds = -1;//默认不设置超时时间 61 | } 62 | public override string Key { get; set; } 63 | public override object Data { get; set; } 64 | } 65 | public class MyTestStateContent 66 | { 67 | public Guid Id { get; set; } 68 | public string Name { get; set; } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /sample/RemoteInterface/RemoteInterface.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /sample/RunBasic.bat: -------------------------------------------------------------------------------- 1 | kubectl create ns infrastructure 2 | kubectl apply -f Basic.yaml -------------------------------------------------------------------------------- /sample/Server/.dockerignore: -------------------------------------------------------------------------------- 1 | *.yaml 2 | *.bat 3 | *.sh -------------------------------------------------------------------------------- /sample/Server/Dockerfile: -------------------------------------------------------------------------------- 1 | from mcr.microsoft.com/dotnet/aspnet:8.0 2 | WORKDIR /app 3 | COPY /pub . 4 | RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone 5 | ENTRYPOINT ["dotnet", "Server.dll"] -------------------------------------------------------------------------------- /sample/Server/Dockerfile.Debug: -------------------------------------------------------------------------------- 1 | from mcr.microsoft.com/dotnet/aspnet:8.0 2 | WORKDIR /app 3 | RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo 'Asia/Shanghai' >/etc/timezone 4 | ENTRYPOINT ["dotnet", "Server.dll"] -------------------------------------------------------------------------------- /sample/Server/HelloEventHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | using Oxygen.Client.ServerSymbol; 3 | using Oxygen.Client.ServerSymbol.Events; 4 | using Oxygen.Server.Kestrel.Implements; 5 | using RemoteInterface; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Text; 9 | using System.Text.Encodings.Web; 10 | using System.Text.Json; 11 | using System.Text.Unicode; 12 | using System.Threading.Tasks; 13 | 14 | namespace Server 15 | { 16 | public class HelloEventHandler : IEventHandler 17 | { 18 | private readonly ILogger logger; 19 | public HelloEventHandler(ILogger logger) 20 | { 21 | this.logger = logger; 22 | } 23 | [EventHandlerFunc("test")] 24 | public async Task SubscribeByUserInfoEvent(EventHandleRequest input) 25 | { 26 | logger.LogInformation($"订阅器收到消息:{JsonSerializer.Serialize(input.GetData(), new JsonSerializerOptions() { Encoder = JavaScriptEncoder.Create(UnicodeRanges.All) })}"); 27 | return await Task.FromResult(DefaultEventHandlerResponse.Default()); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /sample/Server/HelloServiceImpl.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Microsoft.Extensions.Logging; 3 | using Oxygen.Client.ServerProxyFactory.Interface; 4 | using Oxygen.Mesh.Dapr; 5 | using Oxygen.Mesh.Dapr.Model; 6 | using RemoteInterface; 7 | using System; 8 | using System.Threading.Tasks; 9 | 10 | namespace Server 11 | { 12 | public class HelloServiceImpl : IHelloService 13 | { 14 | private readonly ILogger logger; 15 | private readonly IStateManager stateManager; 16 | public HelloServiceImpl(ILogger logger, IStateManager stateManager) 17 | { 18 | this.logger = logger; 19 | this.stateManager = stateManager; 20 | } 21 | public async Task GetUserInfo(InputDto input) 22 | { 23 | return await Task.FromResult(new OutDto() { Word = $"hello {input?.name}" }); 24 | } 25 | public async Task GetState(InputDto input) 26 | { 27 | var state = await stateManager.GetState(new TestStateDto(input.name)); 28 | return await Task.FromResult(new OutDto() { Word = state.ToString() }); 29 | } 30 | public async Task Test() 31 | { 32 | return await Task.FromResult(new OutDto() { Word = "noinput" }); 33 | } 34 | 35 | public async Task GetHtml() 36 | { 37 | HttpContextCurrent.GetCurrent().HttpContext.Response.Cookies.Append("aaa", "bbb"); 38 | HttpContextCurrent.GetCurrent().HttpContext.Response.Redirect("http://www.baidu.com"); 39 | return await Task.FromResult(""); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /sample/Server/Program.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Autofac.Extensions.DependencyInjection; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.Extensions.Hosting; 5 | using Oxygen.Common.Implements; 6 | using Oxygen.IocModule; 7 | using Oxygen.Mesh.Dapr; 8 | using Oxygen.ProxyGenerator.Implements; 9 | using Oxygen.Server.Kestrel.Implements; 10 | using RemoteInterface; 11 | using Server; 12 | using System.Text.Json; 13 | 14 | var builder = OxygenApplication.CreateBuilder(config => 15 | { 16 | config.Port = 80; 17 | config.PubSubCompentName = "pubsub"; 18 | config.StateStoreCompentName = "statestore"; 19 | config.TracingHeaders = "Authentication"; 20 | }); 21 | OxygenActorStartup.ConfigureServices(builder.Services); 22 | builder.Host.ConfigureContainer(builder => 23 | { 24 | //注入oxygen依赖 25 | builder.RegisterOxygenModule(); 26 | //注入测试demo 27 | builder.RegisterType().As().InstancePerLifetimeScope(); 28 | builder.RegisterType().As().InstancePerLifetimeScope(); 29 | }); 30 | builder.Services.AddAutofac(); 31 | builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); 32 | //注册全局拦截器 33 | LocalMethodAopProvider.RegisterPipelineHandler((methodctx) => { 34 | HttpContextCurrent.SetCurrent(methodctx); 35 | }, async (obj, methodctx) => 36 | { 37 | if (obj != null) 38 | Console.WriteLine($"这里是方法前拦截器,拦截到参数:{JsonSerializer.Serialize(obj)}"); 39 | await Task.CompletedTask; 40 | var s = HttpContextCurrent.GetCurrent(); 41 | 42 | }, async (result) => 43 | { 44 | Console.WriteLine($"这里是方法后拦截器,拦截到方法结果:{JsonSerializer.Serialize(result)}"); 45 | var s = HttpContextCurrent.GetCurrent(); 46 | await Task.CompletedTask; 47 | }, async (exp) => 48 | { 49 | Console.WriteLine($"这里是方法异常拦截器,拦截到异常:{exp.Message}"); 50 | return await Task.FromResult(new { Message = exp.Message }); 51 | }); 52 | var app = builder.Build(); 53 | OxygenActorStartup.Configure(app, app.Services); 54 | await app.RunAsync(); 55 | public static class HttpContextCurrent 56 | { 57 | private static AsyncLocal currentcontext = new AsyncLocal(); 58 | internal static void SetCurrent(OxygenHttpContextWapper httpContextWapper) 59 | { 60 | if (currentcontext.Value == null) 61 | currentcontext.Value = httpContextWapper; 62 | } 63 | internal static OxygenHttpContextWapper GetCurrent() 64 | { 65 | return currentcontext.Value; 66 | } 67 | } -------------------------------------------------------------------------------- /sample/Server/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Server": { 4 | "commandName": "Project" 5 | }, 6 | "Docker": { 7 | "commandName": "Docker" 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /sample/Server/Server.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net8.0 6 | Linux 7 | ..\.. 8 | enable 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /sample/Server/start.bat: -------------------------------------------------------------------------------- 1 | dotnet publish -c release 2 | cd bin/release/netcoreapp3.1/publish/ 3 | Server.exe -------------------------------------------------------------------------------- /sample/start-dapr-debug.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: oxygen-dapr-sample-client 5 | labels: 6 | app: oxygen-dapr-sample-client 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: oxygen-dapr-sample-client 12 | minReadySeconds: 5 13 | strategy: 14 | type: RollingUpdate 15 | rollingUpdate: 16 | maxUnavailable: 1 17 | maxSurge: 1 18 | template: 19 | metadata: 20 | labels: 21 | app: oxygen-dapr-sample-client 22 | annotations: 23 | dapr.io/enabled: "true" 24 | dapr.io/app-id: "callservice" 25 | dapr.io/app-port: "80" 26 | spec: 27 | containers: 28 | - name: web 29 | image: oxygen-dapr-sample-client:debug 30 | imagePullPolicy: Never 31 | env: 32 | - name: Logging__Console__FormatterName 33 | value: "" 34 | ports: 35 | - containerPort: 80 36 | volumeMounts: 37 | - mountPath: /app 38 | name: v1 39 | - mountPath: /remote_debugger:rw 40 | name: v2 41 | volumes: 42 | - name: v1 43 | hostPath: 44 | path: /run/desktop/mnt/host/e/dotnet_project/Oxygen-Dapr/sample/Client/bin/Debug/net8.0 45 | - name: v2 46 | hostPath: 47 | path: /run/desktop/mnt/host/c/Users/Administrator/vsdbg/vs2017u5 48 | --- 49 | apiVersion: apps/v1 50 | kind: Deployment 51 | metadata: 52 | name: oxygen-dapr-sample-server 53 | labels: 54 | app: oxygen-dapr-sample-server 55 | spec: 56 | replicas: 1 57 | selector: 58 | matchLabels: 59 | app: oxygen-dapr-sample-server 60 | minReadySeconds: 5 61 | strategy: 62 | type: RollingUpdate 63 | rollingUpdate: 64 | maxUnavailable: 1 65 | maxSurge: 1 66 | template: 67 | metadata: 68 | labels: 69 | app: oxygen-dapr-sample-server 70 | annotations: 71 | dapr.io/enabled: "true" 72 | dapr.io/app-id: "testservice" 73 | dapr.io/app-port: "80" 74 | spec: 75 | containers: 76 | - name: web 77 | image: oxygen-dapr-sample-server:debug 78 | imagePullPolicy: Never 79 | env: 80 | - name: Logging__Console__FormatterName 81 | value: "" 82 | ports: 83 | - containerPort: 80 84 | volumeMounts: 85 | - mountPath: /app 86 | name: v1 87 | - mountPath: /remote_debugger:rw 88 | name: v2 89 | volumes: 90 | - name: v1 91 | hostPath: 92 | path: /run/desktop/mnt/host/e/dotnet_project/Oxygen-Dapr/sample/Server/bin/Debug/net8.0 93 | - name: v2 94 | hostPath: 95 | path: /run/desktop/mnt/host/c/Users/Administrator/vsdbg/vs2017u5 96 | --- 97 | apiVersion: v1 98 | kind: Service 99 | metadata: 100 | name: oxygen-dapr-sample-server 101 | spec: 102 | selector: 103 | app: oxygen-dapr-sample-server 104 | ports: 105 | - protocol: TCP 106 | port: 80 107 | targetPort: 80 108 | --- 109 | apiVersion: v1 110 | kind: Service 111 | metadata: 112 | name: oxygen-dapr-sample-client 113 | spec: 114 | selector: 115 | app: oxygen-dapr-sample-client 116 | ports: 117 | - protocol: TCP 118 | port: 80 119 | targetPort: 80 120 | --- 121 | apiVersion: networking.k8s.io/v1 122 | kind: Ingress 123 | metadata: 124 | namespace: default 125 | name: oxygen-dapr 126 | annotations: 127 | kubernetes.io/ingress.class: "nginx" 128 | spec: 129 | rules: 130 | - host: api.oxygen-dapr.com 131 | http: 132 | paths: 133 | - path: / 134 | pathType: Prefix 135 | backend: 136 | service: 137 | name: oxygen-dapr-sample-client 138 | port: 139 | number: 80 -------------------------------------------------------------------------------- /sample/start-dapr.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: oxygen-dapr-sample-client 5 | labels: 6 | app: oxygen-dapr-sample-client 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: oxygen-dapr-sample-client 12 | minReadySeconds: 5 13 | strategy: 14 | type: RollingUpdate 15 | rollingUpdate: 16 | maxUnavailable: 1 17 | maxSurge: 1 18 | template: 19 | metadata: 20 | labels: 21 | app: oxygen-dapr-sample-client 22 | annotations: 23 | dapr.io/enabled: "true" 24 | dapr.io/app-id: "callservice" 25 | dapr.io/app-port: "80" 26 | spec: 27 | containers: 28 | - name: web 29 | image: oxygen-dapr-sample-client:latest 30 | imagePullPolicy: Never 31 | env: 32 | - name: Logging__Console__FormatterName 33 | value: "" 34 | ports: 35 | - containerPort: 80 36 | --- 37 | apiVersion: apps/v1 38 | kind: Deployment 39 | metadata: 40 | name: oxygen-dapr-sample-server 41 | labels: 42 | app: oxygen-dapr-sample-server 43 | spec: 44 | replicas: 1 45 | selector: 46 | matchLabels: 47 | app: oxygen-dapr-sample-server 48 | minReadySeconds: 5 49 | strategy: 50 | type: RollingUpdate 51 | rollingUpdate: 52 | maxUnavailable: 1 53 | maxSurge: 1 54 | template: 55 | metadata: 56 | labels: 57 | app: oxygen-dapr-sample-server 58 | annotations: 59 | dapr.io/enabled: "true" 60 | dapr.io/app-id: "testservice" 61 | dapr.io/app-port: "80" 62 | spec: 63 | containers: 64 | - name: web 65 | image: oxygen-dapr-sample-server:latest 66 | env: 67 | - name: Logging__Console__FormatterName 68 | value: "" 69 | imagePullPolicy: Never 70 | ports: 71 | - containerPort: 80 72 | --- 73 | apiVersion: networking.k8s.io/v1 74 | kind: Ingress 75 | metadata: 76 | namespace: default 77 | name: oxygen-dapr 78 | annotations: 79 | kubernetes.io/ingress.class: "nginx" 80 | spec: 81 | rules: 82 | - host: api.oxygen-dapr.com 83 | http: 84 | paths: 85 | - path: / 86 | pathType: Prefix 87 | backend: 88 | service: 89 | name: oxygen-dapr-sample-client 90 | port: 91 | number: 80 -------------------------------------------------------------------------------- /sample/start-sample.bat: -------------------------------------------------------------------------------- 1 | kubectl delete -f start-dapr.yaml 2 | set /p mode= 3 | if %mode% == 1 ( 4 | cd Client 5 | rd /S /Q pub 6 | dotnet clean 7 | dotnet publish -c Release -o pub 8 | docker build . -t oxygen-dapr-sample-client:latest 9 | cd ../Server 10 | rd /S /Q pub 11 | dotnet publish -c Release -o pub 12 | docker build . -t oxygen-dapr-sample-server:latest 13 | cd ../ 14 | kubectl delete -f start-dapr.yaml 15 | kubectl apply -f start-dapr.yaml 16 | ) ^ 17 | else ( 18 | cd ../ 19 | dotnet clean 20 | dotnet build Oxygen.sln 21 | cd sample/Client 22 | docker build . -t oxygen-dapr-sample-client:debug -f Dockerfile.Debug 23 | cd ../Server 24 | docker build . -t oxygen-dapr-sample-server:debug -f Dockerfile.Debug 25 | cd ../ 26 | kubectl apply -f start-dapr-debug.yaml 27 | ) 28 | docker system prune -f 29 | kubectl get po -w -------------------------------------------------------------------------------- /sample/stop-sample.bat: -------------------------------------------------------------------------------- 1 | kubectl delete -f start-dapr.yaml -------------------------------------------------------------------------------- /sample/test/start-dapr-debug.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: oxygen-dapr-sample-test 5 | labels: 6 | app: oxygen-dapr-sample-test 7 | spec: 8 | replicas: 1 9 | selector: 10 | matchLabels: 11 | app: oxygen-dapr-sample-test 12 | minReadySeconds: 5 13 | strategy: 14 | type: RollingUpdate 15 | rollingUpdate: 16 | maxUnavailable: 1 17 | maxSurge: 1 18 | template: 19 | metadata: 20 | labels: 21 | app: oxygen-dapr-sample-test 22 | spec: 23 | containers: 24 | - name: web 25 | image: oxygen-dapr-sample-server:latest 26 | imagePullPolicy: Never 27 | ports: 28 | - containerPort: 80 29 | volumeMounts: 30 | - mountPath: /app 31 | name: v1 32 | # - mountPath: /remote_debugger:rw 33 | # name: v2 34 | # - mountPath: /root/.vs-debugger 35 | # name: v3 36 | volumes: 37 | - name: v1 38 | hostPath: 39 | path: /e/dotnet_project/Oxygen-Dapr/sample/Server/bin/Debug/netcoreapp3.1 40 | # - name: v2 41 | # hostPath: 42 | # path: /c/Users/Administrator/vsdbg/vs2017u5 43 | # - name: v3 44 | # hostPath: 45 | # path: /e/dockerdebugger/.vs-debugger -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerProxyFactory/Implements/EventBus.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerProxyFactory.Interface; 2 | using Oxygen.Client.ServerSymbol.Events; 3 | using Oxygen.Common; 4 | using Oxygen.ProxyGenerator.Interface; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | namespace Oxygen.Client.ServerProxyFactory.Implements 12 | { 13 | public class EventBus : IEventBus 14 | { 15 | private readonly IRemoteMessageSender messageSender; 16 | public EventBus(IRemoteMessageSender messageSender) 17 | { 18 | this.messageSender = messageSender; 19 | } 20 | public async Task SendEvent(string topic, T input) 21 | { 22 | return await messageSender.SendMessage(DaprConfig.GetCurrent().PubSubCompentName, $"/{topic}", input, SendType.publish); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerProxyFactory/Implements/ServiceProxyFactory.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerProxyFactory.Interface; 2 | using Oxygen.Client.ServerSymbol.Events; 3 | using Oxygen.Common.Implements; 4 | using Oxygen.ProxyGenerator.Interface; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Oxygen.Client.ServerProxyFactory.Implements 11 | { 12 | public class ServiceProxyFactory : IServiceProxyFactory 13 | { 14 | public T CreateProxy() where T : class 15 | { 16 | return OxygenIocContainer.Resolve(); 17 | } 18 | public T CreateActorProxy() where T : class 19 | { 20 | return OxygenIocContainer.ResolveNamed($"{typeof(T).FullName}ActorProxy"); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerProxyFactory/Implements/StateManager.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerProxyFactory.Interface; 2 | using Oxygen.Client.ServerSymbol.Events; 3 | using Oxygen.Client.ServerSymbol.Store; 4 | using Oxygen.Common; 5 | using Oxygen.ProxyGenerator.Interface; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace Oxygen.Client.ServerProxyFactory.Implements 13 | { 14 | public class StateManager : IStateManager 15 | { 16 | private readonly IRemoteMessageSender messageSender; 17 | public StateManager(IRemoteMessageSender messageSender) 18 | { 19 | this.messageSender = messageSender; 20 | } 21 | public async Task DelState(StateStore input) 22 | { 23 | return await messageSender.SendMessage(DaprConfig.GetCurrent().StateStoreCompentName, $"/{input.Key}", null, SendType.delState); 24 | } 25 | public async Task GetState(StateStore input) where T : new() 26 | { 27 | return await messageSender.SendMessage(DaprConfig.GetCurrent().StateStoreCompentName, $"/{input.Key}", null, SendType.getState); 28 | } 29 | 30 | public async Task GetState(StateStore input, Type type) 31 | { 32 | return await messageSender.SendMessage(DaprConfig.GetCurrent().StateStoreCompentName, $"/{input.Key}", null, SendType.getState, type); 33 | } 34 | 35 | public async Task SetState(StateStore input) 36 | { 37 | return await messageSender.SendMessage(DaprConfig.GetCurrent().StateStoreCompentName, "", new[] { new { key = input.Key, value = input.Data, metadata = new { ttlInSeconds = input.TtlInSeconds <= 0 ? "-1" : $"{input.TtlInSeconds}" } } }, SendType.setState); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerProxyFactory/Interface/IEventBus.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerSymbol.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Oxygen.Client.ServerProxyFactory.Interface 9 | { 10 | public interface IEventBus 11 | { 12 | Task SendEvent(string topic, T input); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerProxyFactory/Interface/IServiceProxyFactory.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerSymbol.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Oxygen.Client.ServerProxyFactory.Interface 8 | { 9 | public interface IServiceProxyFactory 10 | { 11 | T CreateProxy() where T : class; 12 | T CreateActorProxy() where T : class; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerProxyFactory/Interface/IStateManager.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerSymbol.Events; 2 | using Oxygen.Client.ServerSymbol.Store; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Oxygen.Client.ServerProxyFactory.Interface 10 | { 11 | public interface IStateManager 12 | { 13 | Task SetState(StateStore input); 14 | Task DelState(StateStore input); 15 | Task GetState(StateStore input) where T : new(); 16 | Task GetState(StateStore input, Type type); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerProxyFactory/Module.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Oxygen.ProxyGenerator.Implements; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Linq; 7 | using Oxygen.Common.Implements; 8 | 9 | namespace Oxygen.Client.ServerProxyFactory 10 | { 11 | public class Module : Autofac.Module 12 | { 13 | protected override void Load(ContainerBuilder builder) 14 | { 15 | builder.RegisterAssemblyTypes(ThisAssembly).Where(x => !ReflectionHelper.IsSystemType(x)) 16 | .AsImplementedInterfaces() 17 | .InstancePerLifetimeScope(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerProxyFactory/Oxygen.Client.ServerProxyFactory.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/Actors/ActorSendDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.Client.ServerSymbol.Actors 6 | { 7 | /// 8 | /// 所有Actor服务入参必须继承此类型 9 | /// 10 | public abstract class ActorSendDto 11 | { 12 | public abstract string ActorId { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/Events/DefaultEventHandlerResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace Oxygen.Client.ServerSymbol.Events 7 | { 8 | /// 9 | /// 默认的事件处理回调类 10 | /// 11 | public class DefaultEventHandlerResponse 12 | { 13 | public string status { get => "SUCCESS"; set => status = value; } 14 | public static DefaultEventHandlerResponse Default() 15 | { 16 | return new DefaultEventHandlerResponse(); 17 | } 18 | } 19 | /// 20 | /// 默认的事件发送回调类 21 | /// 22 | public class DefaultResponse 23 | { 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/Events/EventHandleRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Oxygen.Client.ServerSymbol.Events 8 | { 9 | /// 10 | /// 所有dapr订阅者入参必须使用此类型,否则订阅入参无法正确反序列化 11 | /// 12 | /// 13 | public class EventHandleRequest where T : class 14 | { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/Events/EventHandleRequestData.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerSymbol.Events; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Oxygen.Client.ServerSymbol.Events 9 | { 10 | /// 11 | /// 订阅者入参预处理容器 12 | /// 13 | /// 14 | public class TempDataByEventHandleInput: EventHandleRequest where T : class 15 | { 16 | public string data { get; set; } 17 | public T value { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/Events/EventHandleRequestExtension.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerSymbol.Events; 2 | using Oxygen.Common.Implements; 3 | using Oxygen.Common.Interface; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Oxygen.Client.ServerSymbol.Events 11 | { 12 | public static class EventHandleRequestExtension 13 | { 14 | static Lazy serialize = new Lazy(() => 15 | { 16 | return OxygenIocContainer.Resolve(); 17 | }); 18 | public static T GetData(this EventHandleRequest handleRequest) where T : class 19 | { 20 | if (handleRequest == null) 21 | return default; 22 | var request = handleRequest as TempDataByEventHandleInput; 23 | if (request.value != null) 24 | { 25 | return request.value; 26 | } 27 | else if (!string.IsNullOrEmpty(request.data)) 28 | { 29 | request.value = serialize.Value.DeserializesJson(request.data); 30 | return request.value; 31 | } 32 | return default; 33 | } 34 | 35 | public static string GetDataJson(this EventHandleRequest handleRequest) where T : class 36 | { 37 | if (handleRequest == null) 38 | return ""; 39 | var request = handleRequest as TempDataByEventHandleInput; 40 | if (request.data != null) 41 | return request.data; 42 | return ""; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/Events/EventHandlerAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.Client.ServerSymbol.Events 6 | { 7 | /// 8 | /// 事件订阅器标记物 9 | /// 10 | [AttributeUsage(AttributeTargets.Method)] 11 | public class EventHandlerFuncAttribute : Attribute 12 | { 13 | public EventHandlerFuncAttribute(string topic) 14 | { 15 | this.Topic = topic; 16 | } 17 | public string Topic { get; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/Events/IActorService.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Oxygen.Client.ServerSymbol.Events 8 | { 9 | /// 10 | /// actor服务接口,需要actor接口集成 11 | /// 12 | public interface IActorService 13 | { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/Events/IEventHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.Client.ServerSymbol.Events 6 | { 7 | /// 8 | /// 事件订阅器标识,需要订阅器接口继承 9 | /// 10 | public interface IEventHandler 11 | { 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/FuncType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.Client.ServerSymbol 6 | { 7 | public enum FuncType 8 | { 9 | /// 10 | /// 普通web服务 11 | /// 12 | Invoke = 0, 13 | /// 14 | /// actor服务 15 | /// 16 | Actor = 1 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/Oxygen.Client.ServerSymbol.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/RemoteFuncAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace Oxygen.Client.ServerSymbol 7 | { 8 | /// 9 | /// 远程方法标记物 10 | /// 11 | [AttributeUsage(AttributeTargets.Method)] 12 | public class RemoteFuncAttribute : Attribute 13 | { 14 | public FuncType FuncType { get; set; } 15 | public string FuncDescription { get; set; } 16 | public RemoteFuncAttribute(FuncType funcType = FuncType.Invoke, string funcDescription = "") 17 | { 18 | FuncType = funcType; 19 | FuncDescription = funcDescription; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/RemoteServiceAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.Client.ServerSymbol 6 | { 7 | /// 8 | /// 远程服务接口标记 9 | /// 10 | [AttributeUsage(AttributeTargets.Interface)] 11 | public class RemoteServiceAttribute : Attribute 12 | { 13 | public RemoteServiceAttribute(string hostName, string servicename = "", string serverDescription = "") 14 | { 15 | HostName = hostName; 16 | ServerName = servicename; 17 | ServerDescription = serverDescription; 18 | } 19 | public string HostName { get; set; } 20 | public string ServerName { get; set; } 21 | public string ServerDescription { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Oxygen.Client/Oxygen.Client.ServerSymbol/Store/StateStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Oxygen.Client.ServerSymbol.Store 8 | { 9 | public abstract class StateStore 10 | { 11 | public abstract string Key { get; set; } 12 | public abstract object Data { get; set; } 13 | 14 | public int TtlInSeconds { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Oxygen.Mesh/Oxygen.Mesh.Dapr/ActorServiceFactory.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Dapr.Actors; 3 | using Dapr.Actors.Runtime; 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Hosting; 6 | using Microsoft.Extensions.Configuration; 7 | using Microsoft.Extensions.DependencyInjection; 8 | using Oxygen.Client.ServerSymbol; 9 | using Oxygen.Common.Implements; 10 | using Oxygen.Common.Interface; 11 | using Oxygen.Mesh.Dapr.Model; 12 | using System; 13 | using System.Collections.Generic; 14 | using System.Linq; 15 | using System.Reflection; 16 | using System.Threading.Tasks; 17 | 18 | namespace Oxygen.Mesh.Dapr 19 | { 20 | public class ActorServiceFactory 21 | { 22 | static ILifetimeScope _lifetimeScope = null; 23 | static MethodInfo daprRegisterMethodInfo = typeof(ActorRegistrationCollection).GetMethod("RegisterActor", new Type[] { typeof(Action) }); 24 | public static void UseActorService(IApplicationBuilder appBuilder, ILifetimeScope lifetimeScope) 25 | { 26 | if (lifetimeScope != null) 27 | _lifetimeScope = _lifetimeScope ?? lifetimeScope; 28 | appBuilder.UseRouting().UseEndpoints(endpoints => endpoints.MapActorsHandlers()); 29 | } 30 | public static void RegisterActorService(IServiceCollection services) 31 | { 32 | services.AddActors(options => CreateDelegate(options.Actors)); 33 | } 34 | internal static void CreateDelegate(ActorRegistrationCollection actorRegistrations) 35 | { 36 | foreach (var item in ReflectionHelper.GetTypesByNameSpace("Oxygen.Mesh.Dapr.ProxyImpl")) 37 | { 38 | daprRegisterMethodInfo.MakeGenericMethod(item).Invoke(actorRegistrations, new object[] { default(Action) }); 39 | dynamic func = item.GetField("ActorServiceSaveData").GetValue(null); 40 | _lifetimeScope.Resolve().RegisterEventHandler(item.BaseType.GetProperty("ActorData").PropertyType.FullName, _lifetimeScope, func); 41 | } 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/Oxygen.Mesh/Oxygen.Mesh.Dapr/BaseActorService.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Dapr.Actors.Runtime; 3 | using Oxygen.Mesh.Dapr.Model; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Oxygen.Mesh.Dapr 10 | { 11 | 12 | public abstract class BaseActorService where T: ActorStateModel 13 | { 14 | public T ActorData { get; set; } 15 | public abstract Task SaveData(T model, ILifetimeScope scope); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Oxygen.Mesh/Oxygen.Mesh.Dapr/BasicActor.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Dapr.Actors; 3 | using Dapr.Actors.Runtime; 4 | using Oxygen.Common.Implements; 5 | using Oxygen.Common.Interface; 6 | using Oxygen.Mesh.Dapr.Model; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Text; 10 | using System.Text.Json; 11 | using System.Threading; 12 | using System.Threading.Tasks; 13 | 14 | namespace Oxygen.Mesh.Dapr 15 | { 16 | public class BasicActor : Actor where T : ActorStateModel 17 | { 18 | public T ActorData { get; set; } 19 | public T RecordActorData { get; set; } 20 | private readonly IInProcessEventBus eventBus; 21 | public string Topic; 22 | public bool registerTimerState; 23 | public BasicActor(ActorHost host, ILifetimeScope lifetimeScope) : base(host) 24 | { 25 | Topic = typeof(T).FullName; 26 | registerTimerState = false; 27 | this.eventBus = lifetimeScope.Resolve(); 28 | } 29 | /// 30 | /// actor激活事件 31 | /// 32 | /// 33 | protected override async Task OnActivateAsync() 34 | { 35 | if (ActorData == null) 36 | { 37 | var result = await StateManager.TryGetStateAsync("ActorData"); 38 | if (result.HasValue) 39 | { 40 | ActorData = result.Value; 41 | if (ActorData != null) 42 | { 43 | //为actor注册定时器定时发送持久化消息 44 | if (ActorData.AutoSave == true && ActorData.ReminderSeconds > 0) 45 | { 46 | registerTimerState = true; 47 | await RegisterTimer(ActorData.ReminderSeconds); 48 | } 49 | } 50 | } 51 | } 52 | await Task.CompletedTask; 53 | } 54 | public async Task RegisterTimer(int reminderSeconds) 55 | { 56 | await RegisterTimerAsync("SaveActorDataTimer", nameof(this.TimerCallBack), null, TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(reminderSeconds)); 57 | } 58 | public async Task UnRegisterTimer() 59 | { 60 | await UnregisterReminderAsync("SaveActorDataTimer"); 61 | } 62 | public async Task TimerCallBack(object data) 63 | { 64 | await Task.CompletedTask; 65 | } 66 | protected override async Task OnPreActorMethodAsync(ActorMethodContext actorMethodContext) 67 | { 68 | if (ActorData != null && ActorData.AutoSave && actorMethodContext.CallType == ActorCallType.ActorInterfaceMethod) 69 | { 70 | RecordActorData = ActorData with { }; 71 | } 72 | await Task.CompletedTask; 73 | } 74 | /// 75 | /// actor业务处理后置事件 76 | /// 77 | /// 78 | /// 79 | protected override async Task OnPostActorMethodAsync(ActorMethodContext actorMethodContext) 80 | { 81 | if (ActorData != null && ActorData.AutoSave) 82 | { 83 | if (actorMethodContext.CallType == ActorCallType.ActorInterfaceMethod) 84 | { 85 | ActorData.UpdateVersion(RecordActorData);//方法调用后强制升级一次版本 86 | if (ActorData.IsDelete) 87 | { 88 | if (await StateManager.TryRemoveStateAsync("ActorData")) 89 | { 90 | ActorData = null; 91 | await UnRegisterTimer(); 92 | } 93 | } 94 | else 95 | { 96 | await StateManager.SetStateAsync("ActorData", ActorData); 97 | if (ActorData.ReminderSeconds == 0) 98 | { 99 | //如果开启自动保存,但是没有设置定期更新时间,则立即触发一次保存 100 | await SendEvent(ActorData); 101 | } 102 | else if (!registerTimerState) //当ReminderSeconds>0未注册Timer时,需要重新注册timer 103 | { 104 | registerTimerState = true; 105 | await RegisterTimer(ActorData.ReminderSeconds); 106 | } 107 | } 108 | } 109 | else 110 | { 111 | if (ActorData != null && ActorData.AutoSave) 112 | { 113 | if (ActorData.CheckVersionChange()) 114 | { 115 | await SendEvent(ActorData); 116 | } 117 | } 118 | } 119 | } 120 | await Task.CompletedTask; 121 | } 122 | /// 123 | /// actor销毁事件 124 | /// 125 | /// 126 | protected override async Task OnDeactivateAsync() 127 | { 128 | //actor被回收时需要发送持久化消息 129 | if (ActorData != null && ActorData.AutoSave) 130 | await SendEvent(ActorData); 131 | } 132 | protected async Task SendEvent(Tin input) where Tconv : class 133 | { 134 | await eventBus.SendEvent(Topic, input as Tconv); 135 | } 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/Oxygen.Mesh/Oxygen.Mesh.Dapr/Model/ActorStateModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading; 5 | 6 | namespace Oxygen.Mesh.Dapr.Model 7 | { 8 | public abstract record ActorStateModel 9 | { 10 | public abstract bool AutoSave { get; set; } 11 | public abstract int ReminderSeconds { get; } 12 | public bool IsDelete { get; set; } 13 | public void DeleteModel() 14 | { 15 | AutoSave = true; 16 | IsDelete = true; 17 | } 18 | private int oldVersion; 19 | private int newVersion; 20 | internal void UpdateVersion(ActorStateModel oldData) 21 | { 22 | if (oldData != this) //对比两个record如果没有变化,则忽略不增加版本 23 | Interlocked.Increment(ref newVersion); 24 | } 25 | internal bool CheckVersionChange(bool updateversion = true) 26 | { 27 | if (oldVersion != newVersion) 28 | { 29 | if (updateversion) 30 | oldVersion = newVersion; 31 | return true; 32 | } 33 | return false; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Oxygen.Mesh/Oxygen.Mesh.Dapr/Oxygen.Mesh.Dapr.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Oxygen.Mesh/Oxygen.Mesh.Dapr/OxygenActorStartup.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Oxygen.Common.Interface; 5 | using Oxygen.Server.Kestrel.Implements; 6 | using Oxygen.Server.Kestrel.Interface; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | 13 | namespace Oxygen.Mesh.Dapr 14 | { 15 | public class OxygenActorStartup : OxygenStartup 16 | { 17 | public static new void ConfigureServices(IServiceCollection service) 18 | { 19 | OxygenStartup.ConfigureServices(service); 20 | ActorServiceFactory.RegisterActorService(service); 21 | } 22 | public static new void Configure(IApplicationBuilder appBuilder, IServiceProvider serviceProvider) 23 | { 24 | OxygenStartup.Configure(appBuilder, serviceProvider); 25 | ActorServiceFactory.UseActorService(appBuilder, serviceProvider.GetService()); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Oxygen.Mesh/Oxygen.Mesh.Dapr/ProxyCodeGeneratorTemplate.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.CodeAnalysis; 2 | using Oxygen.Client.ServerSymbol; 3 | using Oxygen.Common.Implements; 4 | using System; 5 | using System.Collections; 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | using System.Linq; 9 | using System.Reflection; 10 | using System.Text; 11 | 12 | namespace Oxygen.Mesh.Dapr.ActorProxyGenerator 13 | { 14 | public class ProxyCodeGeneratorTemplate 15 | { 16 | public static IEnumerable<(string sourceName, string sourceCode)> GetTemplate() 17 | { 18 | //获取所有标记为remote的servie 19 | var remoteservice = ReflectionHelper.GetTypesByAttributes(typeof(TInterface), true, typeof(RemoteServiceAttribute)); 20 | //获取所有标记为remote的method构造具体的delegate 21 | foreach (var x in remoteservice) 22 | { 23 | var implType = ReflectionHelper.GetTypeByInterface(typeof(TImpl), x); 24 | if (implType != null) 25 | { 26 | var methods = new List(); 27 | ReflectionHelper.GetMethodByFilter(x, typeof(RemoteFuncAttribute)).ToList().ForEach(y => 28 | { 29 | var funcAttr = ReflectionHelper.GetAttributeProperyiesByMethodInfo(y); 30 | //生成服务调用代理 31 | if (funcAttr.FuncType == FuncType.Actor) 32 | { 33 | methods.Add(y); 34 | } 35 | }); 36 | if (methods.Any()) 37 | { 38 | yield return ($"{implType.Name}Actor.cs", FullTemplate(x, implType, methods.ToArray())); 39 | } 40 | } 41 | } 42 | } 43 | 44 | static string FullTemplate(Type intefaceType, Type implType, MethodInfo[] methods) 45 | { 46 | var baseAcotModelType = implType.BaseType.GetProperty("ActorData").PropertyType; 47 | var source = new StringBuilder(); 48 | source.Append(@"using System; 49 | using Autofac; 50 | using Dapr.Actors; 51 | using Dapr.Actors.Runtime; 52 | using Oxygen.Mesh.Dapr.Model; 53 | using System.Threading.Tasks; 54 | namespace Oxygen.Mesh.Dapr.ProxyImpl 55 | { 56 | public interface " + intefaceType.Name + @"Actor : IActor 57 | { 58 | "); 59 | foreach (var method in methods) 60 | { 61 | source.AppendLine(" Task<" + method.ReturnType.GetGenericArguments()[0] + "> " + method.Name + "(" + (method.GetParameters().Any() ? (method.GetParameters()[0].ParameterType + " " + method.GetParameters()[0].Name) : "") + ");"); 62 | } 63 | source.Append(@" 64 | } 65 | public class " + intefaceType.Name + @"ActorImpl : BasicActor<" + baseAcotModelType.FullName + @">, " + intefaceType.Name + @"Actor 66 | { 67 | private readonly " + intefaceType.FullName + @" _actorService; 68 | public static Func ActorServiceSaveData = (model, scope) => (scope.Resolve<" + intefaceType.FullName + @">() as BaseActorService<" + baseAcotModelType.FullName + @">).SaveData(model as " + baseAcotModelType.FullName + @", scope); 69 | public " + intefaceType.Name + @"ActorImpl(ActorHost actorHost, ILifetimeScope lifetimeScope, " + intefaceType.FullName + @" _actorService) : base(actorHost, lifetimeScope) 70 | { 71 | this._actorService = _actorService; 72 | 73 | }"); 74 | foreach (var method in methods) 75 | { 76 | source.Append(@" 77 | public async Task<" + method.ReturnType.GetGenericArguments()[0] + "> " + method.Name + "(" + (method.GetParameters().Any() ? (method.GetParameters()[0].ParameterType + " " + method.GetParameters()[0].Name) : "") + @") 78 | { 79 | (_actorService as BaseActorService<" + baseAcotModelType.FullName + @">).ActorData = this.ActorData; 80 | var result = await _actorService." + method.Name + @"(" + (method.GetParameters().Any() ? (method.GetParameters()[0].Name) : "") + @"); 81 | this.ActorData = (_actorService as BaseActorService<" + baseAcotModelType.FullName + @">).ActorData; 82 | return result; 83 | }"); 84 | } 85 | source.AppendLine(@" 86 | 87 | } 88 | }"); 89 | return source.ToString(); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Implements/BaseRequestDelegate.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Microsoft.AspNetCore.Http; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Reflection; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Oxygen.Server.Kestrel.Implements 10 | { 11 | internal abstract class BaseRequestDelegate 12 | { 13 | internal PathString Path { get; set; } 14 | internal abstract Task Excute(HttpContext ctx, ILifetimeScope lifetimeScope); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Implements/HttpMessageHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.IO; 3 | using Oxygen.Client.ServerSymbol.Events; 4 | using Oxygen.Common.Interface; 5 | using Oxygen.Server.Kestrel.Interface; 6 | using Oxygen.Server.Kestrel.Interface.Model; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Dynamic; 10 | using System.IO; 11 | using System.Net; 12 | using System.Text; 13 | using System.Threading.Tasks; 14 | 15 | namespace Oxygen.Server.Kestrel.Implements 16 | { 17 | internal class HttpMessageHandler : IMessageHandler 18 | { 19 | private static readonly RecyclableMemoryStreamManager manager = new RecyclableMemoryStreamManager(); 20 | private readonly ISerialize serialize; 21 | public HttpMessageHandler(ISerialize serialize) 22 | { 23 | this.serialize = serialize; 24 | } 25 | public byte[] BuildMessage(T data, MessageType messageType) 26 | { 27 | if (messageType == MessageType.Json) 28 | return Encoding.UTF8.GetBytes(serialize.SerializesJson(data)); 29 | else if (messageType == MessageType.Html) 30 | { 31 | if (data is string strdate) 32 | return Encoding.UTF8.GetBytes(strdate); 33 | return Encoding.UTF8.GetBytes(serialize.SerializesJson(data)); 34 | } 35 | else if (messageType == MessageType.MessagePack) 36 | return serialize.Serializes(data); 37 | else 38 | return default; 39 | } 40 | 41 | public async Task ParseMessage(HttpContext message, MessageType messageType) where T : class, new() 42 | { 43 | using (var buffer = manager.GetStream()) 44 | { 45 | await message.Request.Body.CopyToAsync(buffer); 46 | byte[] bytes = buffer.ToArray(); 47 | if (messageType == MessageType.Json) 48 | { 49 | if (typeof(T).IsGenericType && typeof(T).GetGenericTypeDefinition() == typeof(EventHandleRequest<>))//单独处理事件入参 50 | { 51 | dynamic result = serialize.DeserializesJson(typeof(TempDataByEventHandleInput<>).MakeGenericType(typeof(T).GetGenericArguments()[0]), Encoding.UTF8.GetString(bytes)); 52 | return result; 53 | } 54 | else 55 | return serialize.DeserializesJson(Encoding.UTF8.GetString(bytes)); 56 | } 57 | else if (messageType == MessageType.MessagePack) 58 | { 59 | return serialize.Deserializes(bytes); 60 | } 61 | else 62 | return new T(); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Implements/KestrelServerHandler.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Autofac.Core; 3 | using Autofac.Core.Lifetime; 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.AspNetCore.Internal; 7 | using Oxygen.Common.Implements; 8 | using Oxygen.Common.Interface; 9 | using Oxygen.Server.Kestrel.Interface; 10 | using Oxygen.Server.Kestrel.Interface.Model; 11 | using System; 12 | using System.Collections.Generic; 13 | using System.Linq; 14 | using System.Text; 15 | using System.Threading.Tasks; 16 | 17 | namespace Oxygen.Server.Kestrel.Implements 18 | { 19 | internal class KestrelServerHandler : IServerHandler 20 | { 21 | private readonly ILogger logger; 22 | private readonly IMessageHandler messageHandler; 23 | private static ISharingLifetimeScope Container; 24 | public KestrelServerHandler(ILogger logger, IMessageHandler messageHandler, ILifetimeScope container) 25 | { 26 | this.logger = logger; 27 | this.messageHandler = messageHandler; 28 | Container = ((LifetimeScope)container).RootLifetimeScope; 29 | } 30 | public void BuildHandler(IApplicationBuilder app, ISerialize serialize) 31 | { 32 | RequestDelegateFactory.CreateDelegate(logger, messageHandler, out List subDelegate).ForEach(x => 33 | { 34 | app.Map(x.Path, builder => 35 | { 36 | builder.Run(async ctx => 37 | { 38 | using var lifetimescope = Container.BeginLifetimeScope();//每次从静态根容器引用构造一个独立的生命周期范围 39 | await x.Excute(ctx, lifetimescope); 40 | }); 41 | }); 42 | }); 43 | if (subDelegate.Any()) 44 | { 45 | app.Map("/dapr/subscribe", handle => handle.Run(async ctx => 46 | { 47 | ctx.Response.ContentType = "application/json"; 48 | await ctx.Response.WriteAsync(serialize.SerializesJson(subDelegate)); 49 | })); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Implements/OxygenApplication.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Server.Kestrel.Core; 4 | using Oxygen.Common; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | 13 | namespace Oxygen.Server.Kestrel.Implements 14 | { 15 | public static class OxygenApplication 16 | { 17 | /// 18 | /// 注入web服务 19 | /// 20 | /// 21 | /// 22 | public static WebApplicationBuilder CreateBuilder(Action action) 23 | { 24 | action(DaprConfig.GetCurrent()); 25 | var option = new WebApplicationOptions() 26 | { 27 | ContentRootPath = Directory.GetCurrentDirectory(), 28 | WebRootPath = "wwwroot" 29 | }; 30 | var webHostBuilder =DaprConfig.GetCurrent().UseStaticFiles ? WebApplication.CreateBuilder() : WebApplication.CreateBuilder(option); 31 | webHostBuilder.WebHost 32 | .UseKestrel(options => //重写ConfigureWebHostDefaults中Kestrel配置 33 | { 34 | options.Listen(IPAddress.Any, DaprConfig.GetCurrent().Port, listenOptions => 35 | { 36 | listenOptions.Protocols = HttpProtocols.Http1; 37 | }); 38 | }); 39 | return webHostBuilder; 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Implements/OxygenHostService.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Microsoft.Extensions.Hosting; 3 | using Oxygen.Common.Implements; 4 | using Oxygen.ProxyGenerator.Implements; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace Oxygen.Server.Kestrel.Implements 13 | { 14 | internal class OxygenHostService : IHostedService 15 | { 16 | public OxygenHostService(ILifetimeScope lifetimeScope) 17 | { 18 | OxygenIocContainer.BuilderIocContainer(lifetimeScope); 19 | RemoteProxyGenerator.InitRemoteMessageSenderDelegate();//初始化消息发送代理 20 | } 21 | public async Task StartAsync(CancellationToken cancellationToken) 22 | { 23 | await Task.CompletedTask; 24 | } 25 | 26 | public async Task StopAsync(CancellationToken cancellationToken) 27 | { 28 | await Task.CompletedTask; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Implements/OxygenStartup.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Oxygen.Common; 5 | using Oxygen.Common.Interface; 6 | using Oxygen.Server.Kestrel.Interface; 7 | using System; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Text; 11 | using System.Threading.Tasks; 12 | namespace Oxygen.Server.Kestrel.Implements 13 | { 14 | public class OxygenStartup 15 | { 16 | public static void ConfigureServices(IServiceCollection service) 17 | { 18 | service.AddCors(); 19 | service.AddHostedService(); 20 | } 21 | public static void Configure(IApplicationBuilder appBuilder, IServiceProvider serviceProvider) 22 | { 23 | if (DaprConfig.GetCurrent().UseStaticFiles) 24 | appBuilder.UseStaticFiles(); 25 | if (DaprConfig.GetCurrent().UseCors) 26 | { 27 | appBuilder.UseCors(x => x.SetIsOriginAllowed(_ => true).AllowAnyHeader().AllowAnyMethod().AllowCredentials()); 28 | } 29 | serviceProvider.GetService().BuildHandler(appBuilder, serviceProvider.GetService()); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Implements/RequestDelegate.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Oxygen.Client.ServerSymbol; 5 | using Oxygen.Common.Implements; 6 | using Oxygen.Common.Interface; 7 | using Oxygen.ProxyGenerator.Implements; 8 | using Oxygen.Server.Kestrel.Interface; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Diagnostics; 12 | using System.IO; 13 | using System.Net; 14 | using System.Reflection; 15 | using System.Text; 16 | using System.Text.Unicode; 17 | using System.Threading; 18 | using System.Threading.Tasks; 19 | 20 | namespace Oxygen.Server.Kestrel.Implements 21 | { 22 | internal class RequestDelegate : BaseRequestDelegate where Tin : class, new() where Tout : class 23 | { 24 | private readonly ILogger logger; 25 | private readonly IMessageHandler messageHandler; 26 | private readonly bool noInput; 27 | public RequestDelegate(string serverName, MethodInfo method, ILogger logger, IMessageHandler messageHandler) 28 | { 29 | Path = new PathString($"/{serverName}/{method.Name}".ToLower()); 30 | if (typeof(Tin) == typeof(object)) 31 | { 32 | noInput = true; 33 | NoInputMethodDelegate = RequestDelegateFactory.CreateMethodDelegate>(method); 34 | } 35 | else 36 | { 37 | noInput = false; 38 | MethodDelegate = RequestDelegateFactory.CreateMethodDelegate>(method); 39 | } 40 | this.logger = logger; 41 | this.messageHandler = messageHandler; 42 | } 43 | internal Func> MethodDelegate { get; set; } 44 | internal Func> NoInputMethodDelegate { get; set; } 45 | internal override async Task Excute(HttpContext ctx, ILifetimeScope scope) 46 | { 47 | OxygenIocContainer.BuilderIocContainer(scope);//仅在当前请求内创建上下文模型 48 | byte[] result = new byte[0]; 49 | ctx.Response.ContentType = "application/json"; 50 | var messageType = MessageType.Json; 51 | try 52 | { 53 | if (ctx.Request.ContentType == "application/x-msgpack") 54 | { 55 | ctx.Response.ContentType = "application/x-msgpack"; 56 | messageType = MessageType.MessagePack; 57 | } 58 | if (ctx.Request.ContentType == null) 59 | { 60 | ctx.Response.ContentType = "text/html"; 61 | messageType = MessageType.Html; 62 | } 63 | HttpContextExtension.ContextWapper.Value = new OxygenHttpContextWapper(Path, scope, ctx); 64 | Tout localCallbackResult = null; 65 | if (noInput) 66 | { 67 | localCallbackResult = await LocalMethodAopProvider.UsePipelineHandler(scope, HttpContextExtension.ContextWapper.Value, NoInputMethodDelegate); 68 | } 69 | else 70 | { 71 | var messageobj = await messageHandler.ParseMessage(ctx, messageType); 72 | if (messageobj == default(Tin)) 73 | throw new FormatException($"参数反序列化失败,接口地址{Path},入参类型:{typeof(Tin).Name}"); 74 | localCallbackResult = await LocalMethodAopProvider.UsePipelineHandler(scope, messageobj, HttpContextExtension.ContextWapper.Value, MethodDelegate); 75 | } 76 | if (localCallbackResult != null) 77 | { 78 | result = messageHandler.BuildMessage(localCallbackResult, messageType); 79 | } 80 | } 81 | catch (Exception e) 82 | { 83 | logger.LogError($"服务端消息处理异常: {e.GetBaseException()?.Message ?? e.Message}"); 84 | ctx.Response.StatusCode = (int)HttpStatusCode.InternalServerError; 85 | if (e is FormatException) 86 | await ctx.Response.Body.WriteAsync(Encoding.UTF8.GetBytes(e.Message)); 87 | } 88 | finally 89 | { 90 | await ctx.Response.Body.WriteAsync(result, 0, result.Length); 91 | OxygenIocContainer.DisposeIocContainer();//注销上下文 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Implements/RequestDelegateFactory.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerSymbol; 2 | using Oxygen.Client.ServerSymbol.Events; 3 | using Oxygen.Common; 4 | using Oxygen.Common.Implements; 5 | using Oxygen.Common.Interface; 6 | using Oxygen.Server.Kestrel.Interface; 7 | using Oxygen.Server.Kestrel.Interface.Model; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using System.Linq.Expressions; 12 | using System.Reflection; 13 | using System.Text; 14 | using System.Threading.Tasks; 15 | 16 | namespace Oxygen.Server.Kestrel.Implements 17 | { 18 | internal static class RequestDelegateFactory 19 | { 20 | internal static List CreateDelegate(ILogger logger, IMessageHandler messageHandler, out List subDelegate) 21 | { 22 | var result = new List(); 23 | var _subDelegate = new List(); 24 | //获取所有标记为remote的servie 25 | var remoteservice = ReflectionHelper.GetTypesByAttributes(true, typeof(RemoteServiceAttribute)); 26 | //获取所有标记为remote的method构造具体的delegate 27 | remoteservice.ToList().ForEach(x => 28 | { 29 | var srvAttr = ReflectionHelper.GetAttributeProperyiesByType(x); 30 | if (ReflectionHelper.GetTypeByInterface(x) != null) 31 | { 32 | ReflectionHelper.GetMethodByFilter(x, typeof(RemoteFuncAttribute)).ToList().ForEach(y => 33 | { 34 | var funcAttr = ReflectionHelper.GetAttributeProperyiesByMethodInfo(y); 35 | //生成服务调用代理 36 | if (funcAttr.FuncType == FuncType.Invoke) 37 | { 38 | var requestDelegate = CreateRequestDelegate(x, srvAttr?.ServerName ?? x.Name, y, logger, messageHandler); 39 | if (requestDelegate != null) 40 | { 41 | result.Add(requestDelegate); 42 | } 43 | } 44 | }); 45 | } 46 | }); 47 | //为所有事件处理器生成代理并注册到dapr 48 | var eventhandlers = ReflectionHelper.GetImplTypeByInterface(); 49 | eventhandlers.ToList().ForEach(x => 50 | { 51 | x.GetMethods().ToList().ForEach(y => 52 | { 53 | if (y.ReturnType == typeof(Task) && y.GetParameters().Any() 54 | && y.GetParameters().FirstOrDefault().ParameterType.IsGenericType 55 | && y.GetParameters().FirstOrDefault().ParameterType.GetGenericTypeDefinition() == typeof(EventHandleRequest<>)) 56 | { 57 | var handlerAttr = ReflectionHelper.GetAttributeProperyiesByMethodInfo(y); 58 | var requestDelegate = CreateRequestDelegate(x, x.Name, y, logger, messageHandler); 59 | if (requestDelegate != null) 60 | { 61 | result.Add(requestDelegate); 62 | _subDelegate.Add(new SubscribeModel(DaprConfig.GetCurrent().PubSubCompentName, handlerAttr.Topic, requestDelegate.Path)); 63 | } 64 | } 65 | }); 66 | }); 67 | subDelegate = _subDelegate; 68 | return result; 69 | } 70 | static Type DelegateType = typeof(RequestDelegate<,,>); 71 | static BaseRequestDelegate CreateRequestDelegate(Type t, string serverName, MethodInfo m, ILogger logger, IMessageHandler messageHandler) 72 | { 73 | //所有rpc默认只能处理一个入参 74 | var inputType = m.GetParameters().FirstOrDefault()?.ParameterType ?? typeof(object); 75 | //ReturnType必须是一个task 76 | var outputType = m.ReturnType.GetGenericArguments().FirstOrDefault(); 77 | var genericdelegateType = DelegateType.MakeGenericType(t, inputType, outputType); 78 | //if (ReflectionHelper.GetTypeByInterface(t) == null) 79 | // return null; 80 | //else 81 | return Activator.CreateInstance(genericdelegateType, new object[] { serverName, m, logger, messageHandler }) as BaseRequestDelegate; 82 | } 83 | public static Func CreateMethodDelegate(MethodInfo method) 84 | { 85 | var mParameter = Expression.Parameter(typeof(TObj), "m"); 86 | var pParameter = Expression.Parameter(typeof(Tin), "p"); 87 | var mcExpression = Expression.Call(mParameter, method, Expression.Convert(pParameter, typeof(Tin))); 88 | var reExpression = Expression.Convert(mcExpression, typeof(Tout)); 89 | return Expression.Lambda>(reExpression, mParameter, pParameter).Compile(); 90 | } 91 | public static Func CreateMethodDelegate(MethodInfo method) 92 | { 93 | var mParameter = Expression.Parameter(typeof(TObj), "m"); 94 | var mcExpression = Expression.Call(mParameter, method); 95 | var reExpression = Expression.Convert(mcExpression, typeof(Tout)); 96 | return Expression.Lambda>(reExpression, mParameter).Compile(); 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Interface/IMessageHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Net; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Oxygen.Server.Kestrel.Interface 9 | { 10 | public interface IMessageHandler 11 | { 12 | /// 13 | /// 解析来自客户端的请求消息 14 | /// 15 | /// 16 | /// 17 | /// 18 | Task ParseMessage(HttpContext message, MessageType messageType) where T : class, new(); 19 | /// 20 | /// 构造返回消息 21 | /// 22 | /// 23 | /// 24 | /// 25 | /// 26 | byte[] BuildMessage(T data, MessageType messageType); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Interface/IServerHandler.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Oxygen.Common.Interface; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | 7 | namespace Oxygen.Server.Kestrel.Interface 8 | { 9 | public interface IServerHandler 10 | { 11 | void BuildHandler(IApplicationBuilder app, ISerialize serialize); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Interface/MessageType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.Server.Kestrel.Interface 6 | { 7 | public enum MessageType 8 | { 9 | Json = 0, 10 | MessagePack = 1, 11 | Html = 2 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Interface/Model/SubscribeModel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.Server.Kestrel.Interface.Model 6 | { 7 | internal class SubscribeModel 8 | { 9 | public SubscribeModel(string pubsubname,string topic,string route) 10 | { 11 | this.pubsubname = pubsubname; 12 | this.topic = topic; 13 | this.route = route; 14 | } 15 | public string pubsubname { get; set; } 16 | public string topic { get; set; } 17 | public string route { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Module.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Oxygen.Common.Implements; 3 | using Oxygen.Server.Kestrel.Implements; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | using System.Linq; 8 | 9 | namespace Oxygen.Server.Kestrel 10 | { 11 | public class Module : Autofac.Module 12 | { 13 | protected override void Load(ContainerBuilder builder) 14 | { 15 | builder.RegisterAssemblyTypes(ThisAssembly).Where(x => !ReflectionHelper.IsSystemType(x)) 16 | .AsImplementedInterfaces() 17 | .InstancePerLifetimeScope(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Oxygen.Server/Oxygen.Server.Kestrel/Oxygen.Server.Kestrel.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/DaprConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Oxygen.Common 8 | { 9 | 10 | public class DaprConfig 11 | { 12 | static DaprConfig Currnet { get; set; } 13 | public int Port { get; set; } 14 | public string PubSubCompentName { get; set; } 15 | public string StateStoreCompentName { get; set; } 16 | public string TracingHeaders { get; set; } 17 | public bool UseStaticFiles { get; set; } 18 | public bool UseCors { get; set; } 19 | public static DaprConfig GetCurrent() 20 | { 21 | if (Currnet == null) 22 | Currnet = new DaprConfig(); 23 | return Currnet; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/ConsoleLog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Oxygen.Common.Implements 4 | { 5 | internal class ConsoleLog : Interface.ILogger 6 | { 7 | /// 8 | /// 普通信息 9 | /// 10 | /// 11 | public void LogInfo(string message) 12 | { 13 | var color = Console.ForegroundColor; 14 | Console.ForegroundColor = ConsoleColor.Green; 15 | Console.WriteLine($"{DateTime.Now}|OXYGEN_INFO|{message}"); 16 | Console.ForegroundColor = color; 17 | } 18 | /// 19 | /// 告警信息 20 | /// 21 | /// 22 | public void LogWarn(string message) 23 | { 24 | var color = Console.ForegroundColor; 25 | Console.ForegroundColor = ConsoleColor.Yellow; 26 | Console.WriteLine($"{DateTime.Now}|OXYGEN_WARN|{message}"); 27 | Console.ForegroundColor = color; 28 | } 29 | /// 30 | /// 异常信息 31 | /// 32 | /// 33 | public void LogError(string message) 34 | { 35 | var color = Console.ForegroundColor; 36 | Console.ForegroundColor = ConsoleColor.Red; 37 | Console.WriteLine($"{DateTime.Now}|OXYGEN_ERROR|{message}"); 38 | Console.ForegroundColor = color; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/HttpContextExtension.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading; 6 | using System.Threading.Tasks; 7 | 8 | namespace Oxygen.Common.Implements 9 | { 10 | public static class HttpContextExtension 11 | { 12 | public static AsyncLocal ContextWapper = new AsyncLocal(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/InProcessEventBus/InProcessEventBusManager.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Common.Interface; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Oxygen.Common.Implements 9 | { 10 | public class InProcessEventBusManager: IInProcessEventBus 11 | { 12 | 13 | public async Task SendEvent(string topic, T input) 14 | { 15 | var channel = InProcessPiplineFactory.Get(topic); 16 | if (channel != default) 17 | { 18 | await channel.Pipline.Writer.WriteAsync(input); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/InProcessEventBus/InProcessPipline.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Autofac.Core; 3 | using Autofac.Core.Lifetime; 4 | using Oxygen.Common.Interface; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Threading.Channels; 10 | using System.Threading.Tasks; 11 | 12 | namespace Oxygen.Common.Implements 13 | { 14 | public abstract class InProcessPiplineBase 15 | { 16 | public virtual Channel Pipline { get; set; } 17 | public virtual Func EventHandler { get; set; } 18 | } 19 | 20 | public class InProcessPipline : InProcessPiplineBase 21 | { 22 | public InProcessPipline() { } 23 | private readonly ILogger logger; 24 | private static ISharingLifetimeScope Container; 25 | public InProcessPipline(ILifetimeScope lifetimeScope, Func eventHandler) 26 | { 27 | this.Pipline = Channel.CreateUnbounded(); 28 | this.EventHandler = eventHandler; 29 | Container = ((LifetimeScope)lifetimeScope).RootLifetimeScope; 30 | logger = lifetimeScope.Resolve(); 31 | _ = SubscribeHandleInvoke(); 32 | } 33 | public async Task SubscribeHandleInvoke() 34 | { 35 | await foreach (var message in Pipline.Reader.ReadAllAsync()) 36 | { 37 | try 38 | { 39 | using var lifescope = Container.BeginLifetimeScope(); 40 | await EventHandler(message, lifescope); 41 | } 42 | catch (Exception e) 43 | { 44 | logger.LogError($"进程内订阅器消息处理异常:{e.Message},调用堆栈:{e.StackTrace}"); 45 | } 46 | } 47 | } 48 | public new Channel Pipline { get; set; } 49 | public new Func EventHandler { get; set; } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/InProcessEventBus/InProcessPiplineFactory.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using System; 3 | using System.Collections.Concurrent; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Oxygen.Common.Implements 10 | { 11 | public static class InProcessPiplineFactory 12 | { 13 | static ConcurrentDictionary PiplineList = new ConcurrentDictionary(); 14 | public static bool Add(string topic, ILifetimeScope lifetimeScope, Func eventHandler) 15 | { 16 | return PiplineList.TryAdd(topic, new InProcessPipline(lifetimeScope, eventHandler)); 17 | } 18 | public static InProcessPipline Get(string topic) 19 | { 20 | if(PiplineList.TryGetValue(topic,out InProcessPiplineBase inProcess)) 21 | { 22 | return inProcess as InProcessPipline; 23 | } 24 | return default; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/InProcessEventBus/SubscribeInProcessFactory.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Oxygen.Common.Interface; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Oxygen.Common.Implements 11 | { 12 | public class SubscribeInProcessFactory : ISubscribeInProcessFactory 13 | { 14 | public bool RegisterEventHandler(string topic, ILifetimeScope lifetimeScope, Func eventHandler) 15 | { 16 | return InProcessPiplineFactory.Add(topic, lifetimeScope, eventHandler); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/JsonConverters/TextJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Text.Json; 6 | using System.Text.Json.Serialization; 7 | using System.Threading.Tasks; 8 | 9 | namespace Oxygen.Common.Implements.JsonConverters 10 | { 11 | public class TextJsonConverter 12 | { 13 | public class DateTimeParse : JsonConverter 14 | { 15 | public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 16 | { 17 | return CommonNumberConvter(reader, DateTime.Parse); 18 | } 19 | 20 | public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) 21 | { 22 | writer.WriteStringValue(value.ToString("yyyy-MM-dd HH:mm:ss")); 23 | } 24 | } 25 | public class IntParse : JsonConverter 26 | { 27 | public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 28 | { 29 | try 30 | { 31 | if (reader.TryGetInt32(out int value)) 32 | return value; 33 | return default(int); 34 | } 35 | catch (Exception) 36 | { 37 | return CommonNumberConvter(reader, int.Parse); 38 | } 39 | } 40 | 41 | public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options) 42 | { 43 | writer.WriteNumberValue(value); 44 | } 45 | } 46 | public class DecimalParse : JsonConverter 47 | { 48 | public override decimal Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 49 | { 50 | try 51 | { 52 | if (reader.TryGetDecimal(out decimal value)) 53 | return value; 54 | return default(decimal); 55 | } 56 | catch (Exception) 57 | { 58 | return CommonNumberConvter(reader, decimal.Parse); 59 | } 60 | } 61 | 62 | public override void Write(Utf8JsonWriter writer, decimal value, JsonSerializerOptions options) 63 | { 64 | writer.WriteNumberValue(value); 65 | } 66 | } 67 | public class DoubleParse : JsonConverter 68 | { 69 | public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 70 | { 71 | try 72 | { 73 | if (reader.TryGetDouble(out double value)) 74 | return value; 75 | else 76 | return default(double); 77 | } 78 | catch (Exception) 79 | { 80 | return CommonNumberConvter(reader, double.Parse); 81 | } 82 | } 83 | 84 | public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options) 85 | { 86 | writer.WriteNumberValue(value); 87 | } 88 | } 89 | public class FloatParse : JsonConverter 90 | { 91 | public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 92 | { 93 | try 94 | { 95 | if (reader.TryGetDouble(out double value)) 96 | return (float)value; 97 | else 98 | return default(float); 99 | } 100 | catch (Exception) 101 | { 102 | return CommonNumberConvter(reader, float.Parse); 103 | } 104 | } 105 | 106 | public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options) 107 | { 108 | writer.WriteNumberValue(value); 109 | } 110 | } 111 | public class GuidParse : JsonConverter 112 | { 113 | public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 114 | { 115 | try 116 | { 117 | if (reader.TryGetGuid(out Guid value)) 118 | return value; 119 | return Guid.Empty; 120 | } 121 | catch (Exception) 122 | { 123 | return CommonNumberConvter(reader, Guid.Parse); 124 | } 125 | } 126 | 127 | public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options) 128 | { 129 | writer.WriteStringValue(value); 130 | } 131 | } 132 | public class BoolParse : JsonConverter 133 | { 134 | public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 135 | { 136 | try 137 | { 138 | return reader.GetBoolean(); 139 | } 140 | catch (Exception) 141 | { 142 | return CommonNumberConvter(reader, bool.Parse); 143 | } 144 | } 145 | 146 | public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options) 147 | { 148 | writer.WriteBooleanValue(value); 149 | } 150 | } 151 | static T CommonNumberConvter(Utf8JsonReader reader, Func func) 152 | { 153 | try 154 | { 155 | var str = reader.GetString(); 156 | if (!string.IsNullOrEmpty(str)) 157 | return func(str); 158 | } 159 | catch (Exception) 160 | { 161 | 162 | } 163 | return default; 164 | } 165 | } 166 | 167 | } 168 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/OxygenHttpContextWapper.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Microsoft.AspNetCore.Http; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Oxygen.Common.Implements 11 | { 12 | public class OxygenHttpContextWapper 13 | { 14 | public string RoutePath { get; set; } 15 | public ILifetimeScope RequestService { get; set; } 16 | public HttpContext HttpContext { get; set; } 17 | public OxygenHttpContextWapper(string routePath, ILifetimeScope requestService, HttpContext httpContext) 18 | { 19 | RoutePath = routePath; 20 | RequestService = requestService; 21 | HttpContext = httpContext; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/OxygenIocContainer.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Oxygen.Common.Interface; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Text; 6 | using System.Threading; 7 | 8 | namespace Oxygen.Common.Implements 9 | { 10 | public class OxygenIocContainer 11 | { 12 | private static AsyncLocal Current = new AsyncLocal(); 13 | private static ILogger logger; 14 | public static void BuilderIocContainer(ILifetimeScope container) 15 | { 16 | Current.Value = container; 17 | logger = container.Resolve(); 18 | } 19 | public static void DisposeIocContainer() 20 | { 21 | Current.Value = null; 22 | } 23 | public static T Resolve() where T : class 24 | { 25 | try 26 | { 27 | if (Current.Value == null) 28 | { 29 | logger.LogError("IOC容器实例尚未初始化!"); 30 | return default; 31 | } 32 | else 33 | { 34 | if (Current.Value.TryResolve(out T instance)) 35 | return instance; 36 | else 37 | { 38 | logger.LogError($"IOC容器实例化失败,没有找到类型{typeof(T).Name}!"); 39 | return null; 40 | } 41 | } 42 | } 43 | catch (Exception ex) 44 | { 45 | logger.LogError(ex.Message); 46 | return null; 47 | } 48 | } 49 | public static T ResolveNamed(string name) where T : class 50 | { 51 | try 52 | { 53 | if (Current.Value == null) 54 | { 55 | logger.LogError("IOC容器实例尚未初始化!"); 56 | return default; 57 | } 58 | else 59 | { 60 | var instance = Current.Value.ResolveNamed(name); 61 | if (instance != null) 62 | return instance; 63 | else 64 | { 65 | logger.LogError($"IOC容器实例化失败,没有找到类型{typeof(T).Name}!"); 66 | return null; 67 | } 68 | } 69 | } 70 | catch (Exception ex) 71 | { 72 | logger.LogError(ex.Message); 73 | return null; 74 | } 75 | } 76 | public static object Resolve(Type type) 77 | { 78 | try 79 | { 80 | if (Current.Value == null) 81 | { 82 | logger.LogError("IOC容器实例化出错!"); 83 | return null; 84 | } 85 | else 86 | { 87 | if (Current.Value.TryResolve(type, out object instance)) 88 | return instance; 89 | else 90 | { 91 | logger.LogError($"IOC容器实例化失败,没有找到类型{type.Name}!"); 92 | return null; 93 | } 94 | } 95 | } 96 | catch (Exception ex) 97 | { 98 | logger.LogError(ex.Message); 99 | return null; 100 | } 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/ReflectionHelper.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyModel; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Runtime.Loader; 7 | using System.Text; 8 | 9 | namespace Oxygen.Common.Implements 10 | { 11 | public static class ReflectionHelper 12 | { 13 | static Lazy> Assemblies = new Lazy>(() => DependencyContext.Default.CompileLibraries.Where(lib => !lib.Serviceable && lib.Type != "package" && lib.Type != "referenceassembly").Select(lib => AssemblyLoadContext.Default.LoadFromAssemblyName(new AssemblyName(lib.Name)))); 14 | public static IEnumerable GetTypesByAttributes(bool isInterface, params Type[] attributes) 15 | { 16 | return Assemblies.Value.SelectMany(a => a.GetTypes().Where(t => (isInterface ? t.IsInterface : !t.IsInterface) && t.GetCustomAttributes().Select(x => x.GetType()).Intersect(attributes).Count() == attributes.Count())).ToArray(); 17 | } 18 | public static IEnumerable GetTypesByAttributes(Type type, bool isInterface, params Type[] attributes) 19 | { 20 | return type.Assembly.GetTypes().Where(t => (isInterface ? t.IsInterface : !t.IsInterface) && t.GetCustomAttributes().Select(x => x.GetType()).Intersect(attributes).Count() == attributes.Count()).ToArray(); 21 | } 22 | public static T GetAttributeProperyiesByType(Type type) where T : Attribute 23 | { 24 | return type.GetCustomAttributes().FirstOrDefault(x => x is T) as T; 25 | } 26 | public static T GetAttributeProperyiesByMethodInfo(MethodInfo method) where T : Attribute 27 | { 28 | return method.GetCustomAttributes().FirstOrDefault(x => x is T) as T; 29 | } 30 | public static Type GetTypeByInterface(Type interfaceType) 31 | { 32 | return Assemblies.Value.SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Any() && t.GetInterfaces().Contains(interfaceType))).FirstOrDefault(); 33 | } 34 | public static Type GetTypeByInterface(Type implType, Type interfaceType) 35 | { 36 | return implType.Assembly.GetTypes().Where(t => t.GetInterfaces().Any() && t.GetInterfaces().Contains(interfaceType)).FirstOrDefault(); 37 | } 38 | public static IEnumerable GetImplTypeByInterface() where T : class 39 | { 40 | var impls = GetTypesByAttributes(false); 41 | if (impls.Any()) 42 | { 43 | foreach(var impl in impls) 44 | { 45 | if (impl.GetInterfaces().Any(x => x == typeof(T))) 46 | yield return impl; 47 | } 48 | } 49 | } 50 | public static IEnumerable GetMethodByFilter(Type type, params Type[] attributes) 51 | { 52 | return type.GetMethods().Where(x => x.GetCustomAttributes().Select(x => x.GetType()).Intersect(attributes).Count() == attributes.Count()); 53 | } 54 | public static IEnumerable GetMethodByFilter(IEnumerable type, params Type[] attributes) 55 | { 56 | return type.SelectMany(x=>x.GetMethods().Where(x => x.GetCustomAttributes().Select(x => x.GetType()).Intersect(attributes).Count() == attributes.Count())); 57 | } 58 | 59 | public static Assembly GetAssemblyByInterface() 60 | { 61 | return Assemblies.Value.Where(a => a.GetTypes().Any(t => t.GetInterfaces().Any() && t.GetInterfaces().Contains(typeof(T)))).FirstOrDefault(); 62 | } 63 | public static IEnumerable GetTypesByNameSpace(string name) 64 | { 65 | foreach (var item in Assemblies.Value) 66 | { 67 | foreach (var type in item.GetTypes()) 68 | { 69 | if (type.Namespace == name && !type.IsInterface && type.MemberType == MemberTypes.TypeInfo) 70 | yield return type; 71 | } 72 | } 73 | } 74 | 75 | static string[] SystemAssemblyQualifiedName = new string[] { "Microsoft", "System" }; 76 | public static bool IsSystemType(Type type, bool checkBaseType = true, bool checkInterfaces = true) 77 | { 78 | if (SystemAssemblyQualifiedName.Any(x => type.AssemblyQualifiedName.StartsWith(x))) 79 | return true; 80 | else 81 | { 82 | if (checkBaseType && type.BaseType != null && type.BaseType != typeof(object) && SystemAssemblyQualifiedName.Any(x => type.BaseType.AssemblyQualifiedName.StartsWith(x))) 83 | return true; 84 | if (checkInterfaces && type.GetInterfaces().Any()) 85 | if (type.GetInterfaces().Any(i => SystemAssemblyQualifiedName.Any(x => i.AssemblyQualifiedName.StartsWith(x)))) 86 | return true; 87 | } 88 | return false; 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Implements/SerializeImpl.cs: -------------------------------------------------------------------------------- 1 | using MessagePack; 2 | using MessagePack.Resolvers; 3 | using Oxygen.Common.Implements.JsonConverters; 4 | using Oxygen.Common.Interface; 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Text.Json; 10 | using System.Text.Json.Serialization; 11 | 12 | namespace Oxygen.Common.Implements 13 | { 14 | internal class SerializeImpl : ISerialize 15 | { 16 | private readonly ILogger _logger; 17 | public static Lazy LoadMessagePackDefaultOptions = new Lazy(() => 18 | { 19 | StaticCompositeResolver.Instance.Register(NativeDateTimeResolver.Instance, ContractlessStandardResolverAllowPrivate.Instance); 20 | var options = MessagePackSerializerOptions.Standard.WithResolver(StaticCompositeResolver.Instance); 21 | options.WithCompression(MessagePackCompression.Lz4BlockArray); 22 | MessagePackSerializer.DefaultOptions = options; 23 | return true; 24 | }); 25 | public static Lazy JsonSerializerOptions = new Lazy(() => 26 | { 27 | var options = new JsonSerializerOptions(); 28 | options.PropertyNameCaseInsensitive = true;//忽略大小写 29 | //基础类型处理通过客户端自定义重载 30 | options.Converters.Add(new TextJsonConverter.DateTimeParse()); 31 | options.Converters.Add(new TextJsonConverter.IntParse()); 32 | options.Converters.Add(new TextJsonConverter.DoubleParse()); 33 | options.Converters.Add(new TextJsonConverter.DecimalParse()); 34 | options.Converters.Add(new TextJsonConverter.FloatParse()); 35 | options.Converters.Add(new TextJsonConverter.GuidParse()); 36 | options.Converters.Add(new TextJsonConverter.BoolParse()); 37 | options.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; //响应驼峰命名 38 | options.Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping;//中文乱码 39 | options.AllowTrailingCommas = true;//允许数组末尾多余的逗号 40 | return options; 41 | }); 42 | public SerializeImpl(ILogger logger) 43 | { 44 | _ = LoadMessagePackDefaultOptions.Value;//加载MessagePack序列化器全局配置 45 | _logger = logger; 46 | } 47 | /// 48 | /// 序列化 49 | /// 50 | /// 51 | /// 52 | /// 53 | public byte[] Serializes(T input) 54 | { 55 | if (input == null) 56 | return default(byte[]); 57 | try 58 | { 59 | return MessagePackSerializer.Serialize(input); 60 | } 61 | catch (Exception e) 62 | { 63 | _logger.LogError($"序列化对象失败:{e.Message}"); 64 | } 65 | return default(byte[]); 66 | } 67 | /// 68 | /// 序列化T为JSON字符串 69 | /// 70 | /// 71 | /// 72 | /// 73 | public string SerializesJson(T input, bool IngoreOptions = false) 74 | { 75 | if (input == null) 76 | return default(string); 77 | try 78 | { 79 | if(IngoreOptions) 80 | return JsonSerializer.Serialize(input); 81 | else 82 | return JsonSerializer.Serialize(input, JsonSerializerOptions.Value); 83 | } 84 | catch (Exception e) 85 | { 86 | _logger.LogError($"序列化对象失败:{e.Message}"); 87 | } 88 | return default(string); 89 | } 90 | /// 91 | /// 序列化json字符串为Byte[] 92 | /// 93 | /// 94 | /// 95 | public byte[] SerializesJsonString(string jsonStr) 96 | { 97 | if (jsonStr == null) 98 | return default(byte[]); 99 | try 100 | { 101 | return MessagePackSerializer.ConvertFromJson(jsonStr); 102 | } 103 | catch (Exception e) 104 | { 105 | _logger.LogError($"序列化对象失败:{e.Message}"); 106 | } 107 | return default(byte[]); 108 | } 109 | 110 | /// 111 | /// 反序列化 112 | /// 113 | /// 114 | /// 115 | /// 116 | public T Deserializes(byte[] input) 117 | { 118 | if (input == null || !input.Any()) 119 | return default(T); 120 | try 121 | { 122 | return MessagePackSerializer.Deserialize(input); 123 | } 124 | catch (Exception e) 125 | { 126 | _logger.LogError($"反序化对象失败:{e.Message}"); 127 | } 128 | return default(T); 129 | } 130 | 131 | /// 132 | /// 反序列化JSON字符串为T 133 | /// 134 | /// 135 | /// 136 | /// 137 | public T DeserializesJson(string input) 138 | { 139 | if (input == null || !input.Any()) 140 | return default(T); 141 | try 142 | { 143 | return JsonSerializer.Deserialize(input, JsonSerializerOptions.Value); 144 | } 145 | catch (Exception e) 146 | { 147 | _logger.LogError($"反序化对象失败:{e.Message},消息体:{input}"); 148 | } 149 | return default(T); 150 | } 151 | /// 152 | /// 序列化JSON字符串为object 153 | /// 154 | /// 155 | /// 156 | /// 157 | public object DeserializesJson(Type type, string input) 158 | { 159 | if (input == null || !input.Any()) 160 | return default; 161 | try 162 | { 163 | return JsonSerializer.Deserialize(input, type, JsonSerializerOptions.Value); 164 | } 165 | catch (Exception e) 166 | { 167 | _logger.LogError($"反序化对象失败:{e.Message},消息体:{input}"); 168 | } 169 | return default; 170 | } 171 | /// 172 | /// 序列化 173 | /// 174 | /// 175 | /// 176 | /// 177 | public byte[] Serializes(Type type, object input) 178 | { 179 | if (input == null) 180 | return default(byte[]); 181 | try 182 | { 183 | return MessagePackSerializer.Serialize(type, input); 184 | } 185 | catch (Exception e) 186 | { 187 | _logger.LogError($"序列化对象失败:{e.Message}"); 188 | } 189 | return default(byte[]); 190 | } 191 | 192 | public object Deserializes(Type type, byte[] input) 193 | { 194 | if (input == null || !input.Any()) 195 | return null; 196 | try 197 | { 198 | return MessagePackSerializer.Deserialize(type, input); 199 | } 200 | catch (Exception e) 201 | { 202 | _logger.LogError($"反序化对象失败:{e.Message}"); 203 | } 204 | return null; 205 | } 206 | } 207 | } 208 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Interface/IInProcessEventBus.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Oxygen.Common.Interface 8 | { 9 | public interface IInProcessEventBus 10 | { 11 | Task SendEvent(string topic, T input); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Interface/ILogger.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.Common.Interface 6 | { 7 | public interface ILogger 8 | { 9 | /// 10 | /// 异常日志 11 | /// 12 | /// 13 | void LogError(string message); 14 | /// 15 | /// 警告日志 16 | /// 17 | /// 18 | void LogWarn(string message); 19 | /// 20 | /// 信息日志 21 | /// 22 | /// 23 | void LogInfo(string message); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Interface/ISerialize.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.Common.Interface 6 | { 7 | /// 8 | /// 序列化接口 9 | /// 10 | public interface ISerialize 11 | { 12 | /// 13 | /// 序列化 14 | /// 15 | /// 16 | /// 17 | /// 18 | byte[] Serializes(T input); 19 | 20 | /// 21 | /// 序列化T为JSON字符串 22 | /// 23 | /// 24 | /// 25 | /// 26 | string SerializesJson(T input, bool IngoreOptions = false); 27 | /// 28 | /// 序列化json字符串为Byte[] 29 | /// 30 | /// 31 | /// 32 | byte[] SerializesJsonString(string jsonStr); 33 | 34 | /// 35 | /// 反序列化 36 | /// 37 | /// 38 | /// 39 | /// 40 | T Deserializes(byte[] input); 41 | 42 | /// 43 | /// 反序列化JSON字符串为T 44 | /// 45 | /// 46 | /// 47 | /// 48 | T DeserializesJson(string input); 49 | /// 50 | /// 反序列化JSON字符串为object 51 | /// 52 | /// 53 | /// 54 | /// 55 | object DeserializesJson(Type type, string input); 56 | 57 | /// 58 | /// 序列化 59 | /// 60 | /// 61 | /// 62 | /// 63 | byte[] Serializes(Type type, object input); 64 | /// 65 | /// 反序列化 66 | /// 67 | /// 68 | /// 69 | /// 70 | object Deserializes(Type type, byte[] input); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Interface/ISubscribeInProcessFactory.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Oxygen.Common.Interface 9 | { 10 | public interface ISubscribeInProcessFactory 11 | { 12 | bool RegisterEventHandler(string topic, ILifetimeScope lifetimeScope, Func eventHandler); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Module.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Oxygen.Common.Implements; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Oxygen.Common 9 | { 10 | public class Module : Autofac.Module 11 | { 12 | protected override void Load(ContainerBuilder builder) 13 | { 14 | builder.RegisterAssemblyTypes(ThisAssembly).Where(x => !ReflectionHelper.IsSystemType(x)) 15 | .AsImplementedInterfaces() 16 | .InstancePerLifetimeScope(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Oxygen.Common.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.Common/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Oxygen.Common": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | }, 9 | "applicationUrl": "https://localhost:60560;http://localhost:60561" 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.IocModule/ContainerBuilderExtension.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.AspNetCore.Server.Kestrel.Core; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Oxygen.Common; 7 | using Oxygen.Mesh.Dapr; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Net; 11 | using System.Text; 12 | using System.Threading.Tasks; 13 | 14 | namespace Oxygen.IocModule 15 | { 16 | public static class ContainerBuilderExtension 17 | { 18 | /// 19 | /// 依赖注入IOC模块 20 | /// 21 | /// 22 | /// 23 | public static ContainerBuilder RegisterOxygenModule(this ContainerBuilder builder) 24 | { 25 | //注入通用服务 26 | builder.RegisterModule(new Common.Module()); 27 | builder.RegisterModule(new Server.Kestrel.Module()); 28 | builder.RegisterModule(new ProxyGenerator.Module()); 29 | builder.RegisterModule(new Client.ServerProxyFactory.Module()); 30 | return builder; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.IocModule/Oxygen.IocModule.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.ProxyGenerator/Implements/LocalMethodAopProvider.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Oxygen.Common.Implements; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Oxygen.ProxyGenerator.Implements 11 | { 12 | /// 13 | /// 本地管道AOP提供者 14 | /// 15 | public class LocalMethodAopProvider 16 | { 17 | static Func BeforeFunc; 18 | static Func AfterFunc; 19 | static Func> ExceptionFunc; 20 | static Action ContextRegister; 21 | /// 22 | /// 为管道注册匿名委托 23 | /// 24 | /// 25 | /// 26 | /// 27 | public static void RegisterPipelineHandler(Action contextRegister, Func beforeFunc = null, Func afterFunc = null, Func> exceptionFunc = null) 28 | { 29 | if (contextRegister != null) 30 | ContextRegister = contextRegister; 31 | if (beforeFunc != null) 32 | BeforeFunc = beforeFunc; 33 | if (afterFunc != null) 34 | AfterFunc = afterFunc; 35 | if (exceptionFunc != null) 36 | ExceptionFunc = exceptionFunc; 37 | } 38 | /// 39 | /// 调用方法前后异常匿名委托 40 | /// 41 | /// 42 | /// 43 | /// 44 | /// 45 | /// 46 | public static async Task UsePipelineHandler(ILifetimeScope scope, Tin param, OxygenHttpContextWapper wapper, Func> method) where Tin : new() where Tout : class 47 | { 48 | try 49 | { 50 | Tout result = default; 51 | if (ContextRegister != null) 52 | ContextRegister(wapper); 53 | if (BeforeFunc != null) 54 | await BeforeFunc(param, wapper); 55 | result = await method(scope.Resolve().GetServices().FirstOrDefault(), param); 56 | if (AfterFunc != null) 57 | await AfterFunc(result); 58 | return result; 59 | } 60 | catch (Exception e) 61 | { 62 | if (ExceptionFunc != null) 63 | return await ExceptionFunc(e); 64 | else 65 | throw; 66 | } 67 | } 68 | public static async Task UsePipelineHandler(ILifetimeScope scope, OxygenHttpContextWapper wapper, Func> method) where Tout : class 69 | { 70 | try 71 | { 72 | Tout result = default; 73 | if (ContextRegister != null) 74 | ContextRegister(wapper); 75 | if (BeforeFunc != null) 76 | await BeforeFunc(null, wapper); 77 | result = await method(scope.Resolve().GetServices().FirstOrDefault()); 78 | if (AfterFunc != null) 79 | await AfterFunc(result); 80 | return result; 81 | } 82 | catch (Exception e) 83 | { 84 | if (ExceptionFunc != null) 85 | return await ExceptionFunc(e); 86 | else 87 | throw; 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.ProxyGenerator/Implements/RemoteDispatchProxy.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerSymbol; 2 | using Oxygen.Common.Implements; 3 | using Oxygen.ProxyGenerator.Interface; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Net.Http; 8 | using System.Reflection; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace Oxygen.ProxyGenerator.Implements 13 | { 14 | public class RemoteDispatchProxy : RemoteDispatchProxyBase 15 | { 16 | protected override object Invoke(MethodInfo targetMethod, object[] args) 17 | { 18 | var router = RemoteRouters.FirstOrDefault(x => x.Key.Equals(targetMethod.Name)); 19 | if (router != null) 20 | { 21 | if (args.Any()) 22 | return router.SenderDelegate.Excute(router.HostName, router.RouterName, args[0], router.SendType); 23 | else 24 | return router.SenderDelegate.Excute(router.HostName, router.RouterName, null, router.SendType); 25 | } 26 | else 27 | { 28 | return null; 29 | } 30 | } 31 | } 32 | public abstract class RemoteDispatchProxyBase : DispatchProxy 33 | { 34 | internal void InitRemoteRouters(Type interfaceType, string hostName, string routerName, IEnumerable remoteMethods) 35 | { 36 | RemoteRouters = new List(); 37 | remoteMethods.ToList().ForEach(x => 38 | { 39 | if (x.ReturnParameter.ParameterType.GenericTypeArguments[0] == typeof(string)) 40 | throw new Exception($"由于string类型不包含无参构造函数,无法为返回类型为Task的方法创建代理,请改用Task,接口:{x.DeclaringType.Name},方法名:{x.Name}"); 41 | var funcAttr = ReflectionHelper.GetAttributeProperyiesByMethodInfo(x); 42 | //生成服务调用代理 43 | if (funcAttr.FuncType == FuncType.Actor || funcAttr.FuncType == FuncType.Invoke) 44 | { 45 | RemoteRouters.Add(new RemoteRouter() 46 | { 47 | Key = x.Name, 48 | HostName = funcAttr.FuncType == FuncType.Actor ? $"{interfaceType.Name}ActorImpl" : hostName, 49 | RouterName = funcAttr.FuncType == FuncType.Actor ? $"/{x.Name}" : $"/{routerName}/{x.Name}".ToLower(), 50 | InputType = x.GetParameters().FirstOrDefault()?.ParameterType, 51 | SendType = funcAttr.FuncType == FuncType.Invoke ? SendType.invoke : funcAttr.FuncType == FuncType.Actor ? SendType.actors : SendType.invoke, 52 | MethodInfo = typeof(IRemoteMessageSender).GetMethod("SendMessage", new Type[] { typeof(string), typeof(string), typeof(object), typeof(SendType) }).MakeGenericMethod(x.ReturnParameter.ParameterType.GenericTypeArguments[0]), 53 | }); 54 | } 55 | }); 56 | } 57 | internal void InitSenderDelegate() 58 | { 59 | RemoteRouters.ForEach(x => x.SenderDelegate = BuildSenderDelegate(x.MethodInfo,x.InputType)); 60 | } 61 | protected class RemoteRouter 62 | { 63 | internal string Key { get; set; } 64 | internal string HostName { get; set; } 65 | internal string RouterName { get; set; } 66 | internal Type InputType { get; set; } 67 | internal MethodInfo MethodInfo { get; set; } 68 | internal SendType SendType { get; set; } 69 | internal IRemoteMessageSenderDelegate SenderDelegate { get; set; } 70 | } 71 | protected List RemoteRouters { get; set; } 72 | 73 | IRemoteMessageSenderDelegate BuildSenderDelegate(MethodInfo methodInfo, Type inputType) 74 | { 75 | return (IRemoteMessageSenderDelegate)Activator.CreateInstance(typeof(RemoteMessageSenderDelegate<,>).MakeGenericType(inputType ?? typeof(object), methodInfo.ReturnType), methodInfo, OxygenIocContainer.Resolve()); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.ProxyGenerator/Implements/RemoteMessageSender.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.Client.ServerSymbol; 2 | using Oxygen.Client.ServerSymbol.Actors; 3 | using Oxygen.Client.ServerSymbol.Events; 4 | using Oxygen.Common; 5 | using Oxygen.Common.Implements; 6 | using Oxygen.Common.Interface; 7 | using Oxygen.ProxyGenerator.Interface; 8 | using System; 9 | using System.Collections.Generic; 10 | using System.Diagnostics; 11 | using System.Net.Http; 12 | using System.Net.Http.Headers; 13 | using System.Text; 14 | using System.Threading; 15 | using System.Threading.Tasks; 16 | 17 | namespace Oxygen.ProxyGenerator.Implements 18 | { 19 | internal class RemoteMessageSender: IRemoteMessageSender 20 | { 21 | private readonly ISerialize serialize; 22 | private readonly ILogger logger; 23 | static Lazy HttpClient = new Lazy(() => 24 | { 25 | var client = new HttpClient(); 26 | client.DefaultRequestHeaders.Connection.Add("keep-alive"); 27 | return client; 28 | }); 29 | public RemoteMessageSender(ISerialize serialize, ILogger logger) 30 | { 31 | this.serialize = serialize; 32 | this.logger = logger; 33 | } 34 | //检测dapr sidecar存活 35 | static bool Readyless = false; 36 | async Task ReadylessCheck() 37 | { 38 | int reTry = 0; 39 | if (!Readyless) 40 | { 41 | while (reTry < 3) 42 | { 43 | try 44 | { 45 | if (!Readyless) 46 | Readyless = (await HttpClient.Value.GetAsync("http://localhost:3500/v1.0/healthz")).IsSuccessStatusCode; 47 | if (Readyless) 48 | break; 49 | else 50 | { 51 | logger.LogWarn($"Dapr尚未准备就绪!"); 52 | await Task.Delay(100); 53 | } 54 | } 55 | catch (Exception e) 56 | { 57 | logger.LogError($"Dapr尚未准备就绪,{e.Message}"); 58 | break; 59 | } 60 | finally { Interlocked.Increment(ref reTry); } 61 | } 62 | } 63 | return Readyless; 64 | } 65 | public async Task SendMessage(string hostName, string serverName, object input, SendType sendType) where T : new() 66 | { 67 | T result = default; 68 | if (await ReadylessCheck()) 69 | { 70 | try 71 | { 72 | var sendMessage = BuildMessage(hostName, serverName, input, sendType); 73 | var responseMessage = await HttpClient.Value.SendAsync(sendMessage); 74 | if (responseMessage.IsSuccessStatusCode) 75 | { 76 | if (sendType == SendType.publish || sendType == SendType.setState || sendType == SendType.delState) 77 | return new T();//事件和状态操作只要返回200代表发送成功 78 | return ReceiveMessage(sendType, await responseMessage.Content.ReadAsByteArrayAsync()); 79 | } 80 | else 81 | { 82 | logger.LogError($"客户端调用http请求异常,状态码:{responseMessage?.StatusCode},请求内容:{sendMessage},回调内容:{await responseMessage.Content.ReadAsStringAsync()}"); 83 | } 84 | } 85 | catch (Exception e) 86 | { 87 | logger.LogError($"客户端调用异常:{e.Message},接口地址:{serverName},调用堆栈{e.StackTrace}"); 88 | } 89 | } 90 | return result; 91 | } 92 | internal HttpRequestMessage BuildMessage(string host, string url, object data, SendType sendType) 93 | { 94 | //集群内地址:localhost:3500 95 | //todo: 由于event和actor会被dapr拦截使用Text.Json进行序列化封装,导致无法使用messagepack序列/反序列化,所以暂时只能采用json 96 | var basepath = $"http://localhost:3500/"; 97 | //basepath = "http://api.oxygen-dapr.com:30882/"; 98 | HttpRequestMessage request; 99 | switch (sendType) 100 | { 101 | case SendType.invoke: 102 | url = $"{basepath}v1.0/invoke/{host}/method{url}"; 103 | request = new HttpRequestMessage(HttpMethod.Post, url) { Version = new Version(1, 1) }; 104 | var bytedata = serialize.Serializes(data ?? new byte[0]); 105 | request.Content = new ByteArrayContent(bytedata); 106 | request.Content.Headers.ContentType = new MediaTypeHeaderValue($"application/x-msgpack"); 107 | AddTraceHeader(request); 108 | return request; 109 | case SendType.publish: 110 | url = $"{basepath}v1.0/publish/{host}{url}"; 111 | request = new HttpRequestMessage(HttpMethod.Post, url) { Version = new Version(1, 1) }; 112 | var stringjson = serialize.SerializesJson(data); 113 | request.Content = new StringContent(stringjson); 114 | return request; 115 | case SendType.actors: 116 | url = $"{basepath}v1.0/actors/{host}/{((ActorSendDto)data).ActorId}/method{url}"; 117 | request = new HttpRequestMessage(HttpMethod.Post, url) { Version = new Version(1, 1) }; 118 | stringjson = serialize.SerializesJson(data, true);//actor json原样发送 119 | request.Content = new StringContent(stringjson); 120 | AddTraceHeader(request); 121 | return request; 122 | case SendType.setState: 123 | url = $"{basepath}v1.0/state/{host}"; 124 | request = new HttpRequestMessage(HttpMethod.Post, url) { Version = new Version(1, 1) }; 125 | stringjson = serialize.SerializesJson(data); 126 | request.Content = new StringContent(stringjson); 127 | return request; 128 | case SendType.getState: 129 | url = $"{basepath}v1.0/state/{host}{url}"; 130 | request = new HttpRequestMessage(HttpMethod.Get, url) { Version = new Version(1, 1) }; 131 | return request; 132 | case SendType.delState: 133 | url = $"{basepath}v1.0/state/{host}{url}"; 134 | request = new HttpRequestMessage(HttpMethod.Delete, url) { Version = new Version(1, 1) }; 135 | return request; 136 | } 137 | return default; 138 | } 139 | 140 | internal T ReceiveMessage(SendType sendType, byte[] data) where T : new() 141 | { 142 | if (sendType == SendType.invoke) 143 | return serialize.Deserializes(data) ?? new T(); 144 | else 145 | return serialize.DeserializesJson(Encoding.UTF8.GetString(data)); 146 | } 147 | internal object? ReceiveMessage(SendType sendType, byte[] data, Type type) 148 | { 149 | if (sendType == SendType.invoke) 150 | return serialize.Deserializes(type, data) ?? null; 151 | else 152 | return serialize.DeserializesJson(type, Encoding.UTF8.GetString(data)); 153 | } 154 | internal void AddTraceHeader(HttpRequestMessage httpRequest) 155 | { 156 | if (!string.IsNullOrEmpty(DaprConfig.GetCurrent().TracingHeaders)) 157 | { 158 | foreach(var headername in DaprConfig.GetCurrent().TracingHeaders.Split(",")) 159 | { 160 | foreach(var currentHeader in HttpContextExtension.ContextWapper.Value.HttpContext.Request.Headers) 161 | { 162 | if (currentHeader.Key == headername) 163 | httpRequest.Headers.Add(headername, currentHeader.Value.ToArray()); 164 | } 165 | } 166 | } 167 | } 168 | 169 | public async Task SendMessage(string hostName, string serverName, object input, SendType sendType, Type type) 170 | { 171 | object result = default; 172 | if (await ReadylessCheck()) 173 | { 174 | try 175 | { 176 | var sendMessage = BuildMessage(hostName, serverName, input, sendType); 177 | var responseMessage = await HttpClient.Value.SendAsync(sendMessage); 178 | if (responseMessage.IsSuccessStatusCode) 179 | { 180 | if (sendType == SendType.publish || sendType == SendType.setState || sendType == SendType.delState) 181 | return new object();//事件和状态操作只要返回200代表发送成功 182 | return ReceiveMessage(sendType, await responseMessage.Content.ReadAsByteArrayAsync(), type); 183 | } 184 | else 185 | { 186 | logger.LogError($"客户端调用http请求异常,状态码:{responseMessage?.StatusCode},请求内容:{sendMessage},回调内容:{await responseMessage.Content.ReadAsStringAsync()}"); 187 | } 188 | } 189 | catch (Exception e) 190 | { 191 | logger.LogError($"客户端调用异常:{e.Message},接口地址:{serverName},调用堆栈{e.StackTrace}"); 192 | } 193 | } 194 | return result; 195 | } 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.ProxyGenerator/Implements/RemoteMessageSenderDelegate.cs: -------------------------------------------------------------------------------- 1 | using Oxygen.ProxyGenerator.Interface; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Reflection; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Oxygen.ProxyGenerator.Implements 9 | { 10 | internal class RemoteMessageSenderDelegate : IRemoteMessageSenderDelegate where Tout : Task 11 | { 12 | private Func proxyfunc; 13 | public RemoteMessageSenderDelegate(MethodInfo method, object instence) 14 | { 15 | proxyfunc = (Func)method.CreateDelegate(typeof(Func), instence); 16 | } 17 | public object Excute(string hostName, string serviceName, object val, SendType sendType) 18 | { 19 | if (val != null) 20 | return proxyfunc(hostName, serviceName, (Tin)val, sendType); 21 | else 22 | return proxyfunc(hostName, serviceName, default, sendType); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.ProxyGenerator/Implements/RemoteProxyGenerator.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Oxygen.Client.ServerSymbol; 3 | using Oxygen.Client.ServerSymbol.Events; 4 | using Oxygen.Common.Implements; 5 | using Oxygen.ProxyGenerator.Interface; 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using System.Net; 10 | using System.Reflection; 11 | using System.Text; 12 | 13 | namespace Oxygen.ProxyGenerator.Implements 14 | { 15 | public class RemoteProxyGenerator 16 | { 17 | static Type ThisType = typeof(RemoteProxyGenerator); 18 | static object ThisObj = Activator.CreateInstance(ThisType); 19 | static List Proxies = new List(); 20 | /// 21 | /// 注册所有的远程服务代理 22 | /// 23 | public static void CreateRemoteProxyAndRegisterInIocContainer(ContainerBuilder builder) 24 | { 25 | //获取所有标记为remote的servie 26 | var remoteservice = ReflectionHelper.GetTypesByAttributes(true, typeof(RemoteServiceAttribute)); 27 | //获取所有标记为remote的method构造具体的proxy 28 | remoteservice.ToList().ForEach(x => { 29 | var attr = ReflectionHelper.GetAttributeProperyiesByType(x); 30 | var proxyInstance = ThisType.GetMethod(nameof(CreateProxyInstance)).MakeGenericMethod(x).Invoke(ThisObj, null) as RemoteDispatchProxyBase; 31 | if (ReflectionHelper.GetTypeByInterface(x) == null || x.GetInterface(nameof(IActorService)) != null) 32 | { 33 | if (x.GetInterface(nameof(IActorService)) != null) 34 | builder.RegisterInstance(proxyInstance).As(x).Named($"{x.FullName}ActorProxy", x); 35 | else 36 | builder.RegisterInstance(proxyInstance).As(x); 37 | proxyInstance.InitRemoteRouters(x, attr.HostName, attr.ServerName ?? x.Name, ReflectionHelper.GetMethodByFilter(x, typeof(RemoteFuncAttribute))); 38 | Proxies.Add(proxyInstance); 39 | } 40 | }); 41 | } 42 | public static void InitRemoteMessageSenderDelegate() 43 | { 44 | Proxies.ForEach(x => x.InitSenderDelegate()); 45 | } 46 | public T CreateProxyInstance() 47 | { 48 | return DispatchProxy.Create>(); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.ProxyGenerator/Interface/IRemoteMessageSender.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Threading.Tasks; 5 | 6 | namespace Oxygen.ProxyGenerator.Interface 7 | { 8 | public interface IRemoteMessageSender 9 | { 10 | Task SendMessage(string hostName, string serverName, object input, SendType sendType) where T : new(); 11 | Task SendMessage(string hostName, string serverName, object input, SendType sendType,Type type); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.ProxyGenerator/Interface/IRemoteMessageSenderDelegate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.ProxyGenerator.Interface 6 | { 7 | public interface IRemoteMessageSenderDelegate 8 | { 9 | object Excute(string hostName, string serviceName, object val, SendType sendType); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.ProxyGenerator/Interface/SendType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace Oxygen.ProxyGenerator.Interface 6 | { 7 | public enum SendType 8 | { 9 | invoke = 0, 10 | publish = 1, 11 | actors = 2, 12 | setState = 3, 13 | getState = 4, 14 | delState = 5 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.ProxyGenerator/Module.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Oxygen.ProxyGenerator.Implements; 3 | using Oxygen.ProxyGenerator.Interface; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Text; 7 | using System.Linq; 8 | using Oxygen.Common.Implements; 9 | 10 | namespace Oxygen.ProxyGenerator 11 | { 12 | public class Module : Autofac.Module 13 | { 14 | protected override void Load(ContainerBuilder builder) 15 | { 16 | builder.RegisterAssemblyTypes(ThisAssembly).Where(x => !ReflectionHelper.IsSystemType(x)) 17 | .AsImplementedInterfaces().Where(x =>!(x is IRemoteMessageSenderDelegate)) 18 | .InstancePerLifetimeScope(); 19 | RemoteProxyGenerator.CreateRemoteProxyAndRegisterInIocContainer(builder); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Oxygen/Oxygen.ProxyGenerator/Oxygen.ProxyGenerator.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | --------------------------------------------------------------------------------