├── .github
└── workflows
│ ├── Publish_NuGet_Manual.yml
│ └── continuous.yml
├── .gitignore
├── .nuke
├── build.schema.json
└── parameters.json
├── LICENSE
├── LuYao.LightRpc.Demo.sln
├── LuYao.LightRpc.Test.sln
├── LuYao.LightRpc.sln
├── README.md
├── build.cmd
├── build.ps1
├── build.sh
├── build
├── .editorconfig
├── Build.Paths.cs
├── Build.Publish.cs
├── Build.Test.cs
├── Build.cs
├── Configuration.cs
├── Directory.Build.props
├── Directory.Build.targets
├── _build.csproj
└── _build.csproj.DotSettings
├── demo
├── LuYao.LightRpc.Demo.Client
│ ├── LuYao.LightRpc.Demo.Client.csproj
│ ├── Program.cs
│ ├── RpcClient.cs
│ ├── RpcTunnel.cs
│ └── rd.xml
├── LuYao.LightRpc.Demo.MinimalApi
│ ├── .config
│ │ └── dotnet-tools.json
│ ├── LuYao.LightRpc.Demo.MinimalApi.csproj
│ ├── MainServer.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── RpcHttpResult.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── LuYao.LightRpc.Demo
│ ├── LuYao.LightRpc.Demo.csproj
│ ├── MainServer.cs
│ └── TestController.cs
└── fc
│ ├── LuYao.LightRpc.Demo.Functions.InAliyun
│ ├── LuYao.LightRpc.Demo.Functions.InAliyun.csproj
│ ├── MainServer.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── RpcHttpResult.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
│ └── LuYao.LightRpc.Demo.Functions.InAzure
│ ├── .gitignore
│ ├── Handler.cs
│ ├── LuYao.LightRpc.Demo.Functions.InAzure.csproj
│ ├── MainServer.cs
│ ├── Program.cs
│ ├── Properties
│ ├── launchSettings.json
│ ├── serviceDependencies.json
│ └── serviceDependencies.local.json
│ └── host.json
├── src
├── LuYao.LightRpc.Newtonsoft
│ ├── FodyWeavers.xml
│ ├── JObjectDataPackage.cs
│ ├── LuYao.LightRpc.Newtonsoft.csproj
│ └── NewtonsoftDataConverter.cs
├── LuYao.LightRpc.SourceGenerators
│ ├── CSharpStringBuilder.cs
│ ├── ControllerDescriptorGenerator.cs
│ ├── DisposeAction.cs
│ ├── FodyWeavers.xml
│ ├── Helpers.cs
│ ├── LuYao.LightRpc.SourceGenerators.csproj
│ ├── Models
│ │ ├── BuildControllerDescriptor
│ │ │ ├── ActionModel.cs
│ │ │ ├── ActionParameterModel.cs
│ │ │ └── ControllerModel.cs
│ │ └── BuildRpcClientAgent
│ │ │ ├── ActionModel.cs
│ │ │ ├── ActionParameterModel.cs
│ │ │ ├── ActionTypeParameterModel.cs
│ │ │ └── ClientModel.cs
│ ├── Renders
│ │ ├── BuildControllerDescriptor
│ │ │ └── ControllerDescriptorRender.cs
│ │ └── BuildRpcClientAgent
│ │ │ └── RpcClientAgentRender.cs
│ └── RpcClientAgentGenerator.cs
└── LuYao.LightRpc
│ ├── Attributes
│ ├── ControllerAttribute.cs
│ ├── ControllerDescriptorAttribute.cs
│ ├── IgnoreAttribute.cs
│ ├── RemoteActionAttribute.cs
│ └── RpcClientAgentAttribute.cs
│ ├── Descriptors
│ ├── ActionDescriptor.cs
│ ├── IActionDescriptor.cs
│ └── IControllerDescriptor.cs
│ ├── EmptyDataPackage.cs
│ ├── Http
│ └── HttpJsonRpcTunnel.cs
│ ├── IDataConverter.cs
│ ├── IDataPackage.cs
│ ├── IRpcTunnel.cs
│ ├── InvokeContext.cs
│ ├── LuYao.LightRpc.csproj
│ ├── RpcClient.cs
│ ├── RpcException.cs
│ ├── RpcResult.cs
│ ├── RpcResultCode.cs
│ ├── RpcServer.cs
│ └── RpcService.cs
└── tests
├── LuYao.LightRpc.Test.Client
├── BaseClass.cs
├── LuYao.LightRpc.Test.Client.csproj
├── MainClient.cs
├── MainTunnel.cs
└── Program.cs
├── LuYao.LightRpc.Test.MinimalApi
├── LuYao.LightRpc.Test.MinimalApi.csproj
├── MainServer.cs
├── Program.cs
├── Properties
│ └── launchSettings.json
├── RpcHttpResult.cs
├── appsettings.Development.json
└── appsettings.json
├── LuYao.LightRpc.Test
├── LuYao.LightRpc.Test.csproj
├── MainServer.cs
└── TestController.cs
└── LuYao.LightRpc.UnitTests
└── LuYao.LightRpc.UnitTests.csproj
/.github/workflows/Publish_NuGet_Manual.yml:
--------------------------------------------------------------------------------
1 | # ------------------------------------------------------------------------------
2 | #
3 | #
4 | # This code was generated.
5 | #
6 | # - To turn off auto-generation set:
7 | #
8 | # [GitHubActions (AutoGenerate = false)]
9 | #
10 | # - To trigger manual generation invoke:
11 | #
12 | # nuke --generate-configuration GitHubActions_Publish_NuGet_Manual --host GitHubActions
13 | #
14 | #
15 | # ------------------------------------------------------------------------------
16 |
17 | name: Publish_NuGet_Manual
18 |
19 | on: [workflow_dispatch]
20 |
21 | jobs:
22 | windows-2022:
23 | name: windows-2022
24 | runs-on: windows-2022
25 | steps:
26 | - uses: actions/checkout@v4
27 | with:
28 | fetch-depth: 0
29 | - name: 'Cache: .nuke/temp, ~/.nuget/packages'
30 | uses: actions/cache@v4
31 | with:
32 | path: |
33 | .nuke/temp
34 | ~/.nuget/packages
35 | key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props') }}
36 | - name: 'Run: Push'
37 | run: ./build.cmd Push
38 | env:
39 | NuGetApiKey: ${{ secrets.NUGET_API_KEY }}
40 | - name: 'Publish: packages'
41 | uses: actions/upload-artifact@v4
42 | with:
43 | name: packages
44 | path: output/packages
45 |
--------------------------------------------------------------------------------
/.github/workflows/continuous.yml:
--------------------------------------------------------------------------------
1 | # ------------------------------------------------------------------------------
2 | #
3 | #
4 | # This code was generated.
5 | #
6 | # - To turn off auto-generation set:
7 | #
8 | # [GitHubActions (AutoGenerate = false)]
9 | #
10 | # - To trigger manual generation invoke:
11 | #
12 | # nuke --generate-configuration GitHubActions_continuous --host GitHubActions
13 | #
14 | #
15 | # ------------------------------------------------------------------------------
16 |
17 | name: continuous
18 |
19 | on: [push]
20 |
21 | jobs:
22 | windows-2022:
23 | name: windows-2022
24 | runs-on: windows-2022
25 | steps:
26 | - uses: actions/checkout@v4
27 | with:
28 | fetch-depth: 0
29 | - name: 'Cache: .nuke/temp, ~/.nuget/packages'
30 | uses: actions/cache@v4
31 | with:
32 | path: |
33 | .nuke/temp
34 | ~/.nuget/packages
35 | key: ${{ runner.os }}-${{ hashFiles('**/global.json', '**/*.csproj', '**/Directory.Packages.props') }}
36 | - name: 'Run: Compile'
37 | run: ./build.cmd Compile
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
298 | *.vbp
299 |
300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
301 | *.dsw
302 | *.dsp
303 |
304 | # Visual Studio 6 technical files
305 | *.ncb
306 | *.aps
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # Visual Studio History (VSHistory) files
365 | .vshistory/
366 |
367 | # BeatPulse healthcheck temp database
368 | healthchecksdb
369 |
370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
371 | MigrationBackup/
372 |
373 | # Ionide (cross platform F# VS Code tools) working folder
374 | .ionide/
375 |
376 | # Fody - auto-generated XML schema
377 | FodyWeavers.xsd
378 |
379 | # VS Code files for those working on multiple tools
380 | .vscode/*
381 | !.vscode/settings.json
382 | !.vscode/tasks.json
383 | !.vscode/launch.json
384 | !.vscode/extensions.json
385 | *.code-workspace
386 |
387 | # Local History for Visual Studio Code
388 | .history/
389 |
390 | # Windows Installer files from build outputs
391 | *.cab
392 | *.msi
393 | *.msix
394 | *.msm
395 | *.msp
396 |
397 | # JetBrains Rider
398 | *.sln.iml
399 |
--------------------------------------------------------------------------------
/.nuke/build.schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/draft-04/schema#",
3 | "properties": {
4 | "Configuration": {
5 | "type": "string",
6 | "description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
7 | "enum": [
8 | "Debug",
9 | "Release"
10 | ]
11 | },
12 | "NuGetApiKey": {
13 | "type": "string",
14 | "description": "Api key to use when pushing the package"
15 | },
16 | "PackageSource": {
17 | "type": "string",
18 | "description": "NuGet artifact target uri - Defaults to https://api.nuget.org/v3/index.json"
19 | },
20 | "Solution": {
21 | "type": "string",
22 | "description": "Path to a solution file that is automatically loaded"
23 | }
24 | },
25 | "definitions": {
26 | "Host": {
27 | "type": "string",
28 | "enum": [
29 | "AppVeyor",
30 | "AzurePipelines",
31 | "Bamboo",
32 | "Bitbucket",
33 | "Bitrise",
34 | "GitHubActions",
35 | "GitLab",
36 | "Jenkins",
37 | "Rider",
38 | "SpaceAutomation",
39 | "TeamCity",
40 | "Terminal",
41 | "TravisCI",
42 | "VisualStudio",
43 | "VSCode"
44 | ]
45 | },
46 | "ExecutableTarget": {
47 | "type": "string",
48 | "enum": [
49 | "Clean",
50 | "Compile",
51 | "Pack",
52 | "Print",
53 | "Push",
54 | "Restore"
55 | ]
56 | },
57 | "Verbosity": {
58 | "type": "string",
59 | "description": "",
60 | "enum": [
61 | "Verbose",
62 | "Normal",
63 | "Minimal",
64 | "Quiet"
65 | ]
66 | },
67 | "NukeBuild": {
68 | "properties": {
69 | "Continue": {
70 | "type": "boolean",
71 | "description": "Indicates to continue a previously failed build attempt"
72 | },
73 | "Help": {
74 | "type": "boolean",
75 | "description": "Shows the help text for this build assembly"
76 | },
77 | "Host": {
78 | "description": "Host for execution. Default is 'automatic'",
79 | "$ref": "#/definitions/Host"
80 | },
81 | "NoLogo": {
82 | "type": "boolean",
83 | "description": "Disables displaying the NUKE logo"
84 | },
85 | "Partition": {
86 | "type": "string",
87 | "description": "Partition to use on CI"
88 | },
89 | "Plan": {
90 | "type": "boolean",
91 | "description": "Shows the execution plan (HTML)"
92 | },
93 | "Profile": {
94 | "type": "array",
95 | "description": "Defines the profiles to load",
96 | "items": {
97 | "type": "string"
98 | }
99 | },
100 | "Root": {
101 | "type": "string",
102 | "description": "Root directory during build execution"
103 | },
104 | "Skip": {
105 | "type": "array",
106 | "description": "List of targets to be skipped. Empty list skips all dependencies",
107 | "items": {
108 | "$ref": "#/definitions/ExecutableTarget"
109 | }
110 | },
111 | "Target": {
112 | "type": "array",
113 | "description": "List of targets to be invoked. Default is '{default_target}'",
114 | "items": {
115 | "$ref": "#/definitions/ExecutableTarget"
116 | }
117 | },
118 | "Verbosity": {
119 | "description": "Logging verbosity during build execution. Default is 'Normal'",
120 | "$ref": "#/definitions/Verbosity"
121 | }
122 | }
123 | }
124 | },
125 | "$ref": "#/definitions/NukeBuild"
126 | }
127 |
--------------------------------------------------------------------------------
/.nuke/parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "build.schema.json",
3 | "Solution": "LuYao.LightRpc.sln"
4 | }
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 码农很忙
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 |
--------------------------------------------------------------------------------
/LuYao.LightRpc.Demo.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.11.35312.102
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuYao.LightRpc.Demo", "demo\LuYao.LightRpc.Demo\LuYao.LightRpc.Demo.csproj", "{FC06BAE2-28EA-47AA-B688-B065A461CC60}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "functions", "functions", "{8ED26275-E307-4D36-875E-EC09D652A629}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuYao.LightRpc.Demo.Functions.InAzure", "demo\fc\LuYao.LightRpc.Demo.Functions.InAzure\LuYao.LightRpc.Demo.Functions.InAzure.csproj", "{BEC53184-0817-4915-A2F5-4F2C62754ABB}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuYao.LightRpc.Demo.Functions.InAliyun", "demo\fc\LuYao.LightRpc.Demo.Functions.InAliyun\LuYao.LightRpc.Demo.Functions.InAliyun.csproj", "{858FB197-CC4C-4A4A-BA3C-11186101797F}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuYao.LightRpc.Demo.Client", "demo\LuYao.LightRpc.Demo.Client\LuYao.LightRpc.Demo.Client.csproj", "{7D193906-C35B-4E75-8270-66A37498E85A}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuYao.LightRpc.Demo.MinimalApi", "demo\LuYao.LightRpc.Demo.MinimalApi\LuYao.LightRpc.Demo.MinimalApi.csproj", "{59B320CC-49D5-4AA9-9D8C-17528C0A155A}"
17 | EndProject
18 | Global
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Any CPU = Debug|Any CPU
21 | Release|Any CPU = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {FC06BAE2-28EA-47AA-B688-B065A461CC60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {FC06BAE2-28EA-47AA-B688-B065A461CC60}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {FC06BAE2-28EA-47AA-B688-B065A461CC60}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {FC06BAE2-28EA-47AA-B688-B065A461CC60}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {BEC53184-0817-4915-A2F5-4F2C62754ABB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {BEC53184-0817-4915-A2F5-4F2C62754ABB}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {BEC53184-0817-4915-A2F5-4F2C62754ABB}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {BEC53184-0817-4915-A2F5-4F2C62754ABB}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {858FB197-CC4C-4A4A-BA3C-11186101797F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {858FB197-CC4C-4A4A-BA3C-11186101797F}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {858FB197-CC4C-4A4A-BA3C-11186101797F}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {858FB197-CC4C-4A4A-BA3C-11186101797F}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {7D193906-C35B-4E75-8270-66A37498E85A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {7D193906-C35B-4E75-8270-66A37498E85A}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {7D193906-C35B-4E75-8270-66A37498E85A}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {7D193906-C35B-4E75-8270-66A37498E85A}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {59B320CC-49D5-4AA9-9D8C-17528C0A155A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {59B320CC-49D5-4AA9-9D8C-17528C0A155A}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {59B320CC-49D5-4AA9-9D8C-17528C0A155A}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {59B320CC-49D5-4AA9-9D8C-17528C0A155A}.Release|Any CPU.Build.0 = Release|Any CPU
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | GlobalSection(NestedProjects) = preSolution
49 | {BEC53184-0817-4915-A2F5-4F2C62754ABB} = {8ED26275-E307-4D36-875E-EC09D652A629}
50 | {858FB197-CC4C-4A4A-BA3C-11186101797F} = {8ED26275-E307-4D36-875E-EC09D652A629}
51 | EndGlobalSection
52 | GlobalSection(ExtensibilityGlobals) = postSolution
53 | SolutionGuid = {3D869020-D838-4F7B-9CC3-A537443D7B65}
54 | EndGlobalSection
55 | EndGlobal
56 |
--------------------------------------------------------------------------------
/LuYao.LightRpc.Test.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31912.275
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuYao.LightRpc", "src\LuYao.LightRpc\LuYao.LightRpc.csproj", "{1029D930-4556-4FE6-BA64-F9E9F9B87A55}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E65A796D-A9BE-4C66-9A17-C9A8E2BD8347}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuYao.LightRpc.Newtonsoft", "src\LuYao.LightRpc.Newtonsoft\LuYao.LightRpc.Newtonsoft.csproj", "{F593163C-1AAB-4A15-9C55-F8DE467B2146}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuYao.LightRpc.SourceGenerators", "src\LuYao.LightRpc.SourceGenerators\LuYao.LightRpc.SourceGenerators.csproj", "{01643FC8-921C-4460-9E46-0BDAFCA420E5}"
13 | EndProject
14 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuYao.LightRpc.Test", "tests\LuYao.LightRpc.Test\LuYao.LightRpc.Test.csproj", "{F1D431B8-5DBA-45B3-9648-8B2B0CD01F63}"
15 | EndProject
16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuYao.LightRpc.Test.MinimalApi", "tests\LuYao.LightRpc.Test.MinimalApi\LuYao.LightRpc.Test.MinimalApi.csproj", "{1AEC67DD-0562-4800-94CF-152CCF179F3D}"
17 | EndProject
18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuYao.LightRpc.Test.Client", "tests\LuYao.LightRpc.Test.Client\LuYao.LightRpc.Test.Client.csproj", "{E4F2787B-B5F8-4339-9227-EE8FD6C4AF34}"
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Release|Any CPU = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {1029D930-4556-4FE6-BA64-F9E9F9B87A55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {1029D930-4556-4FE6-BA64-F9E9F9B87A55}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {1029D930-4556-4FE6-BA64-F9E9F9B87A55}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {1029D930-4556-4FE6-BA64-F9E9F9B87A55}.Release|Any CPU.Build.0 = Release|Any CPU
30 | {F593163C-1AAB-4A15-9C55-F8DE467B2146}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
31 | {F593163C-1AAB-4A15-9C55-F8DE467B2146}.Debug|Any CPU.Build.0 = Debug|Any CPU
32 | {F593163C-1AAB-4A15-9C55-F8DE467B2146}.Release|Any CPU.ActiveCfg = Release|Any CPU
33 | {F593163C-1AAB-4A15-9C55-F8DE467B2146}.Release|Any CPU.Build.0 = Release|Any CPU
34 | {01643FC8-921C-4460-9E46-0BDAFCA420E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {01643FC8-921C-4460-9E46-0BDAFCA420E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {01643FC8-921C-4460-9E46-0BDAFCA420E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {01643FC8-921C-4460-9E46-0BDAFCA420E5}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {F1D431B8-5DBA-45B3-9648-8B2B0CD01F63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {F1D431B8-5DBA-45B3-9648-8B2B0CD01F63}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {F1D431B8-5DBA-45B3-9648-8B2B0CD01F63}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {F1D431B8-5DBA-45B3-9648-8B2B0CD01F63}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {1AEC67DD-0562-4800-94CF-152CCF179F3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {1AEC67DD-0562-4800-94CF-152CCF179F3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {1AEC67DD-0562-4800-94CF-152CCF179F3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {1AEC67DD-0562-4800-94CF-152CCF179F3D}.Release|Any CPU.Build.0 = Release|Any CPU
46 | {E4F2787B-B5F8-4339-9227-EE8FD6C4AF34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {E4F2787B-B5F8-4339-9227-EE8FD6C4AF34}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {E4F2787B-B5F8-4339-9227-EE8FD6C4AF34}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {E4F2787B-B5F8-4339-9227-EE8FD6C4AF34}.Release|Any CPU.Build.0 = Release|Any CPU
50 | EndGlobalSection
51 | GlobalSection(SolutionProperties) = preSolution
52 | HideSolutionNode = FALSE
53 | EndGlobalSection
54 | GlobalSection(NestedProjects) = preSolution
55 | {1029D930-4556-4FE6-BA64-F9E9F9B87A55} = {E65A796D-A9BE-4C66-9A17-C9A8E2BD8347}
56 | {F593163C-1AAB-4A15-9C55-F8DE467B2146} = {E65A796D-A9BE-4C66-9A17-C9A8E2BD8347}
57 | {01643FC8-921C-4460-9E46-0BDAFCA420E5} = {E65A796D-A9BE-4C66-9A17-C9A8E2BD8347}
58 | EndGlobalSection
59 | GlobalSection(ExtensibilityGlobals) = postSolution
60 | SolutionGuid = {DA69B1C3-F6B9-4AF9-859B-D680E03B79F2}
61 | EndGlobalSection
62 | EndGlobal
63 |
--------------------------------------------------------------------------------
/LuYao.LightRpc.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.0.31912.275
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "_build", "build\_build.csproj", "{52B999D2-BA6F-46D9-AAEB-895D6756C0C7}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuYao.LightRpc", "src\LuYao.LightRpc\LuYao.LightRpc.csproj", "{1029D930-4556-4FE6-BA64-F9E9F9B87A55}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{E65A796D-A9BE-4C66-9A17-C9A8E2BD8347}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{60037AE3-ACEB-4609-94C1-39B22A64EF73}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuYao.LightRpc.UnitTests", "tests\LuYao.LightRpc.UnitTests\LuYao.LightRpc.UnitTests.csproj", "{153BF677-B274-46EE-B45F-8AAD1AD0ADFE}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuYao.LightRpc.Newtonsoft", "src\LuYao.LightRpc.Newtonsoft\LuYao.LightRpc.Newtonsoft.csproj", "{F593163C-1AAB-4A15-9C55-F8DE467B2146}"
17 | EndProject
18 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LuYao.LightRpc.SourceGenerators", "src\LuYao.LightRpc.SourceGenerators\LuYao.LightRpc.SourceGenerators.csproj", "{01643FC8-921C-4460-9E46-0BDAFCA420E5}"
19 | EndProject
20 | Global
21 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
22 | Debug|Any CPU = Debug|Any CPU
23 | Release|Any CPU = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
26 | {52B999D2-BA6F-46D9-AAEB-895D6756C0C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {52B999D2-BA6F-46D9-AAEB-895D6756C0C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
28 | {1029D930-4556-4FE6-BA64-F9E9F9B87A55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {1029D930-4556-4FE6-BA64-F9E9F9B87A55}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {1029D930-4556-4FE6-BA64-F9E9F9B87A55}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {1029D930-4556-4FE6-BA64-F9E9F9B87A55}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {153BF677-B274-46EE-B45F-8AAD1AD0ADFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {153BF677-B274-46EE-B45F-8AAD1AD0ADFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {153BF677-B274-46EE-B45F-8AAD1AD0ADFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {153BF677-B274-46EE-B45F-8AAD1AD0ADFE}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {F593163C-1AAB-4A15-9C55-F8DE467B2146}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {F593163C-1AAB-4A15-9C55-F8DE467B2146}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {F593163C-1AAB-4A15-9C55-F8DE467B2146}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {F593163C-1AAB-4A15-9C55-F8DE467B2146}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {01643FC8-921C-4460-9E46-0BDAFCA420E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {01643FC8-921C-4460-9E46-0BDAFCA420E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {01643FC8-921C-4460-9E46-0BDAFCA420E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
43 | {01643FC8-921C-4460-9E46-0BDAFCA420E5}.Release|Any CPU.Build.0 = Release|Any CPU
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | GlobalSection(NestedProjects) = preSolution
49 | {1029D930-4556-4FE6-BA64-F9E9F9B87A55} = {E65A796D-A9BE-4C66-9A17-C9A8E2BD8347}
50 | {153BF677-B274-46EE-B45F-8AAD1AD0ADFE} = {60037AE3-ACEB-4609-94C1-39B22A64EF73}
51 | {F593163C-1AAB-4A15-9C55-F8DE467B2146} = {E65A796D-A9BE-4C66-9A17-C9A8E2BD8347}
52 | {01643FC8-921C-4460-9E46-0BDAFCA420E5} = {E65A796D-A9BE-4C66-9A17-C9A8E2BD8347}
53 | EndGlobalSection
54 | GlobalSection(ExtensibilityGlobals) = postSolution
55 | SolutionGuid = {DA69B1C3-F6B9-4AF9-859B-D680E03B79F2}
56 | EndGlobalSection
57 | EndGlobal
58 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # luyao-light-rpc
2 | A lightweight RPC framework that supports AOT.
3 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | :; set -eo pipefail
2 | :; SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
3 | :; ${SCRIPT_DIR}/build.sh "$@"
4 | :; exit $?
5 |
6 | @ECHO OFF
7 | powershell -ExecutionPolicy ByPass -NoProfile -File "%~dp0build.ps1" %*
8 |
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | [CmdletBinding()]
2 | Param(
3 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
4 | [string[]]$BuildArguments
5 | )
6 |
7 | Write-Output "PowerShell $($PSVersionTable.PSEdition) version $($PSVersionTable.PSVersion)"
8 |
9 | Set-StrictMode -Version 2.0; $ErrorActionPreference = "Stop"; $ConfirmPreference = "None"; trap { Write-Error $_ -ErrorAction Continue; exit 1 }
10 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
11 |
12 | ###########################################################################
13 | # CONFIGURATION
14 | ###########################################################################
15 |
16 | $BuildProjectFile = "$PSScriptRoot\build\_build.csproj"
17 | $TempDirectory = "$PSScriptRoot\\.nuke\temp"
18 |
19 | $DotNetGlobalFile = "$PSScriptRoot\\global.json"
20 | $DotNetInstallUrl = "https://dot.net/v1/dotnet-install.ps1"
21 | $DotNetChannel = "STS"
22 |
23 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = 1
24 | $env:DOTNET_NOLOGO = 1
25 |
26 | ###########################################################################
27 | # EXECUTION
28 | ###########################################################################
29 |
30 | function ExecSafe([scriptblock] $cmd) {
31 | & $cmd
32 | if ($LASTEXITCODE) { exit $LASTEXITCODE }
33 | }
34 |
35 | # If dotnet CLI is installed globally and it matches requested version, use for execution
36 | if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
37 | $(dotnet --version) -and $LASTEXITCODE -eq 0) {
38 | $env:DOTNET_EXE = (Get-Command "dotnet").Path
39 | }
40 | else {
41 | # Download install script
42 | $DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
43 | New-Item -ItemType Directory -Path $TempDirectory -Force | Out-Null
44 | [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
45 | (New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
46 |
47 | # If global.json exists, load expected version
48 | if (Test-Path $DotNetGlobalFile) {
49 | $DotNetGlobal = $(Get-Content $DotNetGlobalFile | Out-String | ConvertFrom-Json)
50 | if ($DotNetGlobal.PSObject.Properties["sdk"] -and $DotNetGlobal.sdk.PSObject.Properties["version"]) {
51 | $DotNetVersion = $DotNetGlobal.sdk.version
52 | }
53 | }
54 |
55 | # Install by channel or version
56 | $DotNetDirectory = "$TempDirectory\dotnet-win"
57 | if (!(Test-Path variable:DotNetVersion)) {
58 | ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Channel $DotNetChannel -NoPath }
59 | } else {
60 | ExecSafe { & powershell $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
61 | }
62 | $env:DOTNET_EXE = "$DotNetDirectory\dotnet.exe"
63 | $env:PATH = "$DotNetDirectory;$env:PATH"
64 | }
65 |
66 | Write-Output "Microsoft (R) .NET SDK version $(& $env:DOTNET_EXE --version)"
67 |
68 | if (Test-Path env:NUKE_ENTERPRISE_TOKEN) {
69 | & $env:DOTNET_EXE nuget remove source "nuke-enterprise" > $null
70 | & $env:DOTNET_EXE nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password $env:NUKE_ENTERPRISE_TOKEN > $null
71 | }
72 |
73 | ExecSafe { & $env:DOTNET_EXE build $BuildProjectFile /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet }
74 | ExecSafe { & $env:DOTNET_EXE run --project $BuildProjectFile --no-build -- $BuildArguments }
75 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | bash --version 2>&1 | head -n 1
4 |
5 | set -eo pipefail
6 | SCRIPT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
7 |
8 | ###########################################################################
9 | # CONFIGURATION
10 | ###########################################################################
11 |
12 | BUILD_PROJECT_FILE="$SCRIPT_DIR/build/_build.csproj"
13 | TEMP_DIRECTORY="$SCRIPT_DIR//.nuke/temp"
14 |
15 | DOTNET_GLOBAL_FILE="$SCRIPT_DIR//global.json"
16 | DOTNET_INSTALL_URL="https://dot.net/v1/dotnet-install.sh"
17 | DOTNET_CHANNEL="STS"
18 |
19 | export DOTNET_CLI_TELEMETRY_OPTOUT=1
20 | export DOTNET_NOLOGO=1
21 |
22 | ###########################################################################
23 | # EXECUTION
24 | ###########################################################################
25 |
26 | function FirstJsonValue {
27 | perl -nle 'print $1 if m{"'"$1"'": "([^"]+)",?}' <<< "${@:2}"
28 | }
29 |
30 | # If dotnet CLI is installed globally and it matches requested version, use for execution
31 | if [ -x "$(command -v dotnet)" ] && dotnet --version &>/dev/null; then
32 | export DOTNET_EXE="$(command -v dotnet)"
33 | else
34 | # Download install script
35 | DOTNET_INSTALL_FILE="$TEMP_DIRECTORY/dotnet-install.sh"
36 | mkdir -p "$TEMP_DIRECTORY"
37 | curl -Lsfo "$DOTNET_INSTALL_FILE" "$DOTNET_INSTALL_URL"
38 | chmod +x "$DOTNET_INSTALL_FILE"
39 |
40 | # If global.json exists, load expected version
41 | if [[ -f "$DOTNET_GLOBAL_FILE" ]]; then
42 | DOTNET_VERSION=$(FirstJsonValue "version" "$(cat "$DOTNET_GLOBAL_FILE")")
43 | if [[ "$DOTNET_VERSION" == "" ]]; then
44 | unset DOTNET_VERSION
45 | fi
46 | fi
47 |
48 | # Install by channel or version
49 | DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"
50 | if [[ -z ${DOTNET_VERSION+x} ]]; then
51 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --channel "$DOTNET_CHANNEL" --no-path
52 | else
53 | "$DOTNET_INSTALL_FILE" --install-dir "$DOTNET_DIRECTORY" --version "$DOTNET_VERSION" --no-path
54 | fi
55 | export DOTNET_EXE="$DOTNET_DIRECTORY/dotnet"
56 | export PATH="$DOTNET_DIRECTORY:$PATH"
57 | fi
58 |
59 | echo "Microsoft (R) .NET SDK version $("$DOTNET_EXE" --version)"
60 |
61 | if [[ ! -z ${NUKE_ENTERPRISE_TOKEN+x} && "$NUKE_ENTERPRISE_TOKEN" != "" ]]; then
62 | "$DOTNET_EXE" nuget remove source "nuke-enterprise" &>/dev/null || true
63 | "$DOTNET_EXE" nuget add source "https://f.feedz.io/nuke/enterprise/nuget" --name "nuke-enterprise" --username "PAT" --password "$NUKE_ENTERPRISE_TOKEN" --store-password-in-clear-text &>/dev/null || true
64 | fi
65 |
66 | "$DOTNET_EXE" build "$BUILD_PROJECT_FILE" /nodeReuse:false /p:UseSharedCompilation=false -nologo -clp:NoSummary --verbosity quiet
67 | "$DOTNET_EXE" run --project "$BUILD_PROJECT_FILE" --no-build -- "$@"
68 |
--------------------------------------------------------------------------------
/build/.editorconfig:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/coderbusy/luyao-light-rpc/bc6f99ddc7ac63562d5e04eee6a8dbed966614c6/build/.editorconfig
--------------------------------------------------------------------------------
/build/Build.Paths.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common.IO;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | partial class Build
9 | {
10 | AbsolutePath SourceDirectory => RootDirectory / "src";
11 | AbsolutePath TestDirectory => RootDirectory / "tests";
12 | AbsolutePath OutputDirectory => RootDirectory / "output";
13 | AbsolutePath PackageDirectory => OutputDirectory / "packages";
14 | }
15 |
--------------------------------------------------------------------------------
/build/Build.Publish.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common;
2 | using Nuke.Common.CI.GitHubActions;
3 | using Nuke.Common.Tools.DotNet;
4 | using Nuke.Common.Tools.GitVersion;
5 |
6 | [GitHubActions("Publish NuGet Manual",
7 | GitHubActionsImage.WindowsServer2022,
8 | On = new[] { GitHubActionsTrigger.WorkflowDispatch },
9 | PublishArtifacts = true,
10 | ImportSecrets = new[] { nameof(NuGetApiKey) },
11 | InvokedTargets = new[] { nameof(Push) },
12 | FetchDepth = 0
13 | )]
14 | partial class Build
15 | {
16 | [Parameter("Api key to use when pushing the package")]
17 | readonly string NuGetApiKey = string.Empty;
18 |
19 | [Parameter("NuGet artifact target uri - Defaults to https://api.nuget.org/v3/index.json")]
20 | readonly string PackageSource = "https://api.nuget.org/v3/index.json";
21 |
22 | Target Pack => _ => _
23 | .DependsOn(Clean, Compile)
24 | .Produces(PackageDirectory / "*nupkg")
25 | .Executes(() =>
26 | {
27 | DotNetTasks.DotNetPack(s => s
28 | .SetProject(Solution)
29 | .SetTreatWarningsAsErrors(true)
30 | .EnableNoBuild()
31 | .SetConfiguration(Configuration)
32 | .SetVersion(GitVersion.FullSemVer)
33 | .SetOutputDirectory(PackageDirectory));
34 | });
35 |
36 | Target Push => _ => _
37 | .Consumes(Pack)
38 | .DependsOn(Pack)
39 | .Requires(() => NuGetApiKey)
40 | .Requires(() => PackageSource)
41 | .Executes(() =>
42 | {
43 | DotNetTasks.DotNetNuGetPush(s => s
44 | .SetTargetPath(PackageDirectory / $"*.nupkg")
45 | .SetApiKey(NuGetApiKey)
46 | .SetSource(PackageSource));
47 | });
48 | }
49 |
--------------------------------------------------------------------------------
/build/Build.Test.cs:
--------------------------------------------------------------------------------
1 | using Nuke.Common;
2 | using Serilog;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | partial class Build
10 | {
11 | Target Print => _ => _
12 | .Executes(() =>
13 | {
14 | Log.Information("GitVersion.Major = {Value}", GitVersion.Major);
15 | Log.Information("GitVersion.Minor = {Value}", GitVersion.Minor);
16 | Log.Information("GitVersion.Patch = {Value}", GitVersion.Patch);
17 | Log.Information("GitVersion.PreReleaseTag = {Value}", GitVersion.PreReleaseTag);
18 | Log.Information("GitVersion.PreReleaseTagWithDash = {Value}", GitVersion.PreReleaseTagWithDash);
19 | Log.Information("GitVersion.PreReleaseLabel = {Value}", GitVersion.PreReleaseLabel);
20 | Log.Information("GitVersion.PreReleaseLabelWithDash = {Value}", GitVersion.PreReleaseLabelWithDash);
21 | Log.Information("GitVersion.PreReleaseNumber = {Value}", GitVersion.PreReleaseNumber);
22 | Log.Information("GitVersion.WeightedPreReleaseNumber = {Value}", GitVersion.WeightedPreReleaseNumber);
23 | Log.Information("GitVersion.BuildMetaData = {Value}", GitVersion.BuildMetaData);
24 | Log.Information("GitVersion.BuildMetaDataPadded = {Value}", GitVersion.BuildMetaDataPadded);
25 | Log.Information("GitVersion.FullBuildMetaData = {Value}", GitVersion.FullBuildMetaData);
26 | Log.Information("GitVersion.MajorMinorPatch = {Value}", GitVersion.MajorMinorPatch);
27 | Log.Information("GitVersion.SemVer = {Value}", GitVersion.SemVer);
28 | Log.Information("GitVersion.LegacySemVer = {Value}", GitVersion.LegacySemVer);
29 | Log.Information("GitVersion.LegacySemVerPadded = {Value}", GitVersion.LegacySemVerPadded);
30 | Log.Information("GitVersion.AssemblySemVer = {Value}", GitVersion.AssemblySemVer);
31 | Log.Information("GitVersion.AssemblySemFileVer = {Value}", GitVersion.AssemblySemFileVer);
32 | Log.Information("GitVersion.FullSemVer = {Value}", GitVersion.FullSemVer);
33 | Log.Information("GitVersion.InformationalVersion = {Value}", GitVersion.InformationalVersion);
34 | Log.Information("GitVersion.BranchName = {Value}", GitVersion.BranchName);
35 | Log.Information("GitVersion.EscapedBranchName = {Value}", GitVersion.EscapedBranchName);
36 | Log.Information("GitVersion.Sha = {Value}", GitVersion.Sha);
37 | Log.Information("GitVersion.ShortSha = {Value}", GitVersion.ShortSha);
38 | Log.Information("GitVersion.NuGetVersionV2 = {Value}", GitVersion.NuGetVersionV2);
39 | Log.Information("GitVersion.NuGetVersion = {Value}", GitVersion.NuGetVersion);
40 | Log.Information("GitVersion.NuGetPreReleaseTagV2 = {Value}", GitVersion.NuGetPreReleaseTagV2);
41 | Log.Information("GitVersion.NuGetPreReleaseTag = {Value}", GitVersion.NuGetPreReleaseTag);
42 | Log.Information("GitVersion.VersionSourceSha = {Value}", GitVersion.VersionSourceSha);
43 | Log.Information("GitVersion.CommitsSinceVersionSource = {Value}", GitVersion.CommitsSinceVersionSource);
44 | Log.Information("GitVersion.CommitsSinceVersionSourcePadded = {Value}", GitVersion.CommitsSinceVersionSourcePadded);
45 | Log.Information("GitVersion.UncommittedChanges = {Value}", GitVersion.UncommittedChanges);
46 | Log.Information("GitVersion.CommitDate = {Value}", GitVersion.CommitDate);
47 | });
48 | }
49 |
--------------------------------------------------------------------------------
/build/Build.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using Nuke.Common;
4 | using Nuke.Common.CI;
5 | using Nuke.Common.CI.GitHubActions;
6 | using Nuke.Common.Execution;
7 | using Nuke.Common.IO;
8 | using Nuke.Common.ProjectModel;
9 | using Nuke.Common.Tooling;
10 | using Nuke.Common.Tools.DotNet;
11 | using Nuke.Common.Tools.GitVersion;
12 | using Nuke.Common.Utilities.Collections;
13 | using static Nuke.Common.EnvironmentInfo;
14 | using static Nuke.Common.IO.FileSystemTasks;
15 | using static Nuke.Common.IO.PathConstruction;
16 | using static Nuke.Common.Tools.DotNet.DotNetTasks;
17 |
18 | [ShutdownDotNetAfterServerBuild]
19 | [GitHubActions(
20 | "continuous",
21 | GitHubActionsImage.WindowsServer2022,
22 | On = new[] { GitHubActionsTrigger.Push },
23 | FetchDepth = 0,
24 | InvokedTargets = new[] { nameof(Compile) })]
25 | partial class Build : NukeBuild
26 | {
27 | /// Support plugins are available for:
28 | /// - JetBrains ReSharper https://nuke.build/resharper
29 | /// - JetBrains Rider https://nuke.build/rider
30 | /// - Microsoft VisualStudio https://nuke.build/visualstudio
31 | /// - Microsoft VSCode https://nuke.build/vscode
32 |
33 | public static int Main() => Execute(x => x.Compile);
34 |
35 | [Solution] readonly Solution Solution;
36 |
37 | [Parameter("Configuration to build - Default is 'Debug' (local) or 'Release' (server)")]
38 | readonly Configuration Configuration = IsLocalBuild ? Configuration.Debug : Configuration.Release;
39 |
40 | [GitVersion(NoFetch = true)] readonly GitVersion GitVersion;
41 | GitHubActions GitHubActions => GitHubActions.Instance;
42 | Target Clean => _ => _
43 | .Before(Restore)
44 | .Executes(() =>
45 | {
46 | SourceDirectory.GlobDirectories("**/bin", "**/obj").ForEach(dir => dir.DeleteDirectory());
47 | TestDirectory.GlobDirectories("**/bin", "**/obj").ForEach(dir => dir.DeleteDirectory());
48 | OutputDirectory.CreateOrCleanDirectory();
49 | });
50 |
51 | Target Restore => _ => _
52 | .Executes(() =>
53 | {
54 | DotNetRestore(dotNetRestoreSettings => dotNetRestoreSettings
55 | .SetProjectFile(Solution));
56 | });
57 |
58 | Target Compile => _ => _
59 | .DependsOn(Restore)
60 | .Executes(() =>
61 | {
62 | DotNetBuild(dotNetBuildSettings => dotNetBuildSettings
63 | .SetProjectFile(Solution)
64 | .SetConfiguration(Configuration)
65 | .SetVersion(GitVersion.FullSemVer)
66 | .EnableNoRestore());
67 | });
68 | }
69 |
--------------------------------------------------------------------------------
/build/Configuration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Linq;
4 | using Nuke.Common.Tooling;
5 |
6 | [TypeConverter(typeof(TypeConverter))]
7 | public class Configuration : Enumeration
8 | {
9 | public static Configuration Debug = new Configuration { Value = nameof(Debug) };
10 | public static Configuration Release = new Configuration { Value = nameof(Release) };
11 |
12 | public static implicit operator string(Configuration configuration)
13 | {
14 | return configuration.Value;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/build/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build/Directory.Build.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/build/_build.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 |
7 | CS0649;CS0169;CA1050;CA1822;CA2211;IDE1006
8 | ..
9 | ..
10 | 1
11 | false
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/build/_build.csproj.DotSettings:
--------------------------------------------------------------------------------
1 |
2 | DO_NOT_SHOW
3 | DO_NOT_SHOW
4 | DO_NOT_SHOW
5 | DO_NOT_SHOW
6 | DO_NOT_SHOW
7 | Implicit
8 | Implicit
9 | ExpressionBody
10 | 0
11 | NEXT_LINE
12 | True
13 | False
14 | 120
15 | IF_OWNER_IS_SINGLE_LINE
16 | WRAP_IF_LONG
17 | False
18 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
19 | <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
20 | True
21 | True
22 | True
23 | True
24 | True
25 | True
26 | True
27 | True
28 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.Client/LuYao.LightRpc.Demo.Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 | true
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.Client/Program.cs:
--------------------------------------------------------------------------------
1 | // See https://aka.ms/new-console-template for more information
2 |
3 | using LuYao.LightRpc.Demo.Client;
4 | using System.Diagnostics;
5 |
6 | //var endpoint = "http://localhost:5297/";// in aliyun
7 | //var endpoint = "http://localhost:5094/";//minimal api
8 | var endpoint = "http://localhost:5000/";//release
9 | var client = new RpcClient(endpoint);
10 | var sum = await client.SumAsync(1, 2);
11 | Console.WriteLine($"sum is : {sum}");
12 | var st = new Stopwatch();
13 | st.Start();
14 | for (int i = 0; i < 1_0000; i++)
15 | {
16 | await client.SumAsync(1, 2);
17 | }
18 | st.Stop();
19 | Console.WriteLine($"10k times sum cost {st.ElapsedMilliseconds} ms");
20 | Console.ReadLine();
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.Client/RpcClient.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Attributes;
2 |
3 | namespace LuYao.LightRpc.Demo.Client;
4 |
5 | [RpcClientAgent]
6 | public partial class RpcClient : LuYao.LightRpc.RpcClient
7 | {
8 | public RpcClient(string endpoint) : base(new RpcTunnel(endpoint))
9 | {
10 |
11 | }
12 |
13 | [RemoteAction("test/sum")]
14 | public partial Task SumAsync(int a, int b);
15 | }
16 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.Client/RpcTunnel.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Http;
2 |
3 | namespace LuYao.LightRpc.Demo.Client;
4 |
5 | public class RpcTunnel : HttpJsonRpcTunnel
6 | {
7 | private static readonly SocketsHttpHandler _handler = new SocketsHttpHandler();
8 | public RpcTunnel(string endpoint) : base(endpoint, new NewtonsoftDataConverter())
9 | {
10 | }
11 |
12 | protected override HttpClient CreateHttpClient()
13 | {
14 | return new HttpClient(_handler, false);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.Client/rd.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.MinimalApi/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "dotnet-ef": {
6 | "version": "8.0.8",
7 | "commands": [
8 | "dotnet-ef"
9 | ],
10 | "rollForward": false
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.MinimalApi/LuYao.LightRpc.Demo.MinimalApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 | true
8 | true
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.MinimalApi/MainServer.cs:
--------------------------------------------------------------------------------
1 | namespace LuYao.LightRpc.Demo.MinimalApi;
2 |
3 | public class MainServer : MainServer
4 | {
5 | public MainServer() : base(new NewtonsoftDataConverter())
6 | {
7 |
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.MinimalApi/Program.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc;
2 | using LuYao.LightRpc.Demo;
3 | using LuYao.LightRpc.Demo.MinimalApi;
4 | using Microsoft.AspNetCore.Mvc;
5 |
6 | var builder = WebApplication.CreateSlimBuilder(args);
7 |
8 | // Add services to the container.
9 | builder.Services.AddSingleton();
10 |
11 | var app = builder.Build();
12 |
13 | app.Map("/", async (
14 | HttpContext context,
15 | [FromQuery(Name = "cmd")] string? action,
16 | [FromServices] MainServer server
17 | ) =>
18 | {
19 | if (action is null) action = string.Empty;
20 | string json = string.Empty;
21 | var request = context.Request;
22 | using (var reader = new StreamReader(request.Body))
23 | {
24 | json = await reader.ReadToEndAsync();
25 | }
26 | var input = server.DataConverter.Deserialize(json) ?? EmptyDataPackage.Instance;
27 | var result = await server.InvokeAsync(action, input);
28 | var ret = new RpcHttpResult(result);
29 | return ret;
30 | });
31 |
32 | app.Run();
33 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.MinimalApi/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "http": {
5 | "commandName": "Project",
6 | "dotnetRunMessages": true,
7 | "launchBrowser": true,
8 | "applicationUrl": "http://localhost:5094",
9 | "environmentVariables": {
10 | "ASPNETCORE_ENVIRONMENT": "Development"
11 | }
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.MinimalApi/RpcHttpResult.cs:
--------------------------------------------------------------------------------
1 | namespace LuYao.LightRpc.Demo.MinimalApi;
2 |
3 | public class RpcHttpResult : IResult
4 | {
5 | public RpcResult RpcResult { get; }
6 |
7 | public RpcHttpResult(RpcResult rpcResult)
8 | {
9 | RpcResult = rpcResult;
10 | }
11 |
12 | public async Task ExecuteAsync(HttpContext httpContext)
13 | {
14 | var response = httpContext.Response;
15 | response.StatusCode = (int)this.RpcResult.Code;
16 | if (this.RpcResult.Code == RpcResultCode.Ok)
17 | {
18 | if (this.RpcResult.Data is not null)
19 | {
20 | var server = httpContext.RequestServices.GetRequiredService();
21 | var output = server.DataConverter.Serialize(this.RpcResult.Data);
22 | await response.WriteAsync(output);
23 | }
24 | }
25 | else
26 | {
27 | if (!string.IsNullOrWhiteSpace(this.RpcResult.Message))
28 | {
29 | await response.WriteAsync(this.RpcResult.Message);
30 | }
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.MinimalApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo.MinimalApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo/LuYao.LightRpc.Demo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | 10.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo/MainServer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuYao.LightRpc.Demo;
6 |
7 | public class MainServer : RpcServer
8 | {
9 | public MainServer(IDataConverter dataConverter) : base(dataConverter)
10 | {
11 | this.Register();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo/LuYao.LightRpc.Demo/TestController.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Attributes;
2 | using System;
3 |
4 | namespace LuYao.LightRpc.Demo;
5 |
6 | [Controller]
7 | public partial class TestController
8 | {
9 | public int Sum(int a, int b)
10 | {
11 | return a + b;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAliyun/LuYao.LightRpc.Demo.Functions.InAliyun.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAliyun/MainServer.cs:
--------------------------------------------------------------------------------
1 | namespace LuYao.LightRpc.Demo.Functions.InAliyun;
2 |
3 | public class MainServer : MainServer
4 | {
5 | public MainServer() : base(new NewtonsoftDataConverter())
6 | {
7 |
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAliyun/Program.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc;
2 | using LuYao.LightRpc.Demo;
3 | using LuYao.LightRpc.Demo.Functions.InAliyun;
4 | using Microsoft.AspNetCore.Mvc;
5 |
6 | var builder = WebApplication.CreateBuilder(args);
7 |
8 | // Add services to the container.
9 | builder.Services.AddSingleton();
10 |
11 | var app = builder.Build();
12 |
13 | app.MapPost("/initialize", () =>
14 | {
15 | return "initialize succ";
16 | });
17 |
18 | app.MapPost("/invoke", ([FromHeader(Name = "x-fc-request-id")] string requestId) =>
19 | {
20 | return "get reqeuestId from header:" + requestId;
21 | });
22 |
23 | app.Map("/", async (
24 | [FromQuery(Name = "cmd")] string? action,
25 | [FromBody] dynamic? body,
26 | [FromServices] MainServer server
27 | ) =>
28 | {
29 | if (action is null) action = string.Empty;
30 | string json = body is not null ? body.ToString() : string.Empty;
31 | var input = server.DataConverter.Deserialize(json) ?? EmptyDataPackage.Instance;
32 | var result = await server.InvokeAsync(action, input);
33 | var ret = new RpcHttpResult(result);
34 | return ret;
35 | });
36 |
37 | app.Run();
38 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAliyun/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:38408",
8 | "sslPort": 0
9 | }
10 | },
11 | "profiles": {
12 | "LuYao.LightRpc.Demo.Functions.InAliyun": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "applicationUrl": "http://localhost:5297",
17 | "environmentVariables": {
18 | "ASPNETCORE_ENVIRONMENT": "Development"
19 | }
20 | },
21 | "IIS Express": {
22 | "commandName": "IISExpress",
23 | "launchBrowser": true,
24 | "environmentVariables": {
25 | "ASPNETCORE_ENVIRONMENT": "Development"
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAliyun/RpcHttpResult.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 |
3 | namespace LuYao.LightRpc.Demo.Functions.InAliyun;
4 |
5 | public class RpcHttpResult : IResult
6 | {
7 | public RpcResult RpcResult { get; }
8 |
9 | public RpcHttpResult(RpcResult rpcResult)
10 | {
11 | RpcResult = rpcResult;
12 | }
13 |
14 | public async Task ExecuteAsync(HttpContext httpContext)
15 | {
16 | var response = httpContext.Response;
17 | response.StatusCode = (int)this.RpcResult.Code;
18 | if (this.RpcResult.Code == RpcResultCode.Ok)
19 | {
20 | if (this.RpcResult.Data is not null)
21 | {
22 | var server = httpContext.RequestServices.GetRequiredService();
23 | var output = server.DataConverter.Serialize(this.RpcResult.Data);
24 | await response.WriteAsync(output);
25 | }
26 | }
27 | else
28 | {
29 | if (!string.IsNullOrWhiteSpace(this.RpcResult.Message))
30 | {
31 | await response.WriteAsync(this.RpcResult.Message);
32 | }
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAliyun/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAliyun/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAzure/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # Azure Functions localsettings file
5 | local.settings.json
6 |
7 | # User-specific files
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Build results
17 | [Dd]ebug/
18 | [Dd]ebugPublic/
19 | [Rr]elease/
20 | [Rr]eleases/
21 | x64/
22 | x86/
23 | bld/
24 | [Bb]in/
25 | [Oo]bj/
26 | [Ll]og/
27 |
28 | # Visual Studio 2015 cache/options directory
29 | .vs/
30 | # Uncomment if you have tasks that create the project's static files in wwwroot
31 | #wwwroot/
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | # NUNIT
38 | *.VisualState.xml
39 | TestResult.xml
40 |
41 | # Build Results of an ATL Project
42 | [Dd]ebugPS/
43 | [Rr]eleasePS/
44 | dlldata.c
45 |
46 | # DNX
47 | project.lock.json
48 | project.fragment.lock.json
49 | artifacts/
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # NCrunch
117 | _NCrunch_*
118 | .*crunch*.local.xml
119 | nCrunchTemp_*
120 |
121 | # MightyMoose
122 | *.mm.*
123 | AutoTest.Net/
124 |
125 | # Web workbench (sass)
126 | .sass-cache/
127 |
128 | # Installshield output folder
129 | [Ee]xpress/
130 |
131 | # DocProject is a documentation generator add-in
132 | DocProject/buildhelp/
133 | DocProject/Help/*.HxT
134 | DocProject/Help/*.HxC
135 | DocProject/Help/*.hhc
136 | DocProject/Help/*.hhk
137 | DocProject/Help/*.hhp
138 | DocProject/Help/Html2
139 | DocProject/Help/html
140 |
141 | # Click-Once directory
142 | publish/
143 |
144 | # Publish Web Output
145 | *.[Pp]ublish.xml
146 | *.azurePubxml
147 | # TODO: Comment the next line if you want to checkin your web deploy settings
148 | # but database connection strings (with potential passwords) will be unencrypted
149 | #*.pubxml
150 | *.publishproj
151 |
152 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
153 | # checkin your Azure Web App publish settings, but sensitive information contained
154 | # in these scripts will be unencrypted
155 | PublishScripts/
156 |
157 | # NuGet Packages
158 | *.nupkg
159 | # The packages folder can be ignored because of Package Restore
160 | **/packages/*
161 | # except build/, which is used as an MSBuild target.
162 | !**/packages/build/
163 | # Uncomment if necessary however generally it will be regenerated when needed
164 | #!**/packages/repositories.config
165 | # NuGet v3's project.json files produces more ignoreable files
166 | *.nuget.props
167 | *.nuget.targets
168 |
169 | # Microsoft Azure Build Output
170 | csx/
171 | *.build.csdef
172 |
173 | # Microsoft Azure Emulator
174 | ecf/
175 | rcf/
176 |
177 | # Windows Store app package directories and files
178 | AppPackages/
179 | BundleArtifacts/
180 | Package.StoreAssociation.xml
181 | _pkginfo.txt
182 |
183 | # Visual Studio cache files
184 | # files ending in .cache can be ignored
185 | *.[Cc]ache
186 | # but keep track of directories ending in .cache
187 | !*.[Cc]ache/
188 |
189 | # Others
190 | ClientBin/
191 | ~$*
192 | *~
193 | *.dbmdl
194 | *.dbproj.schemaview
195 | *.jfm
196 | *.pfx
197 | *.publishsettings
198 | node_modules/
199 | orleans.codegen.cs
200 |
201 | # Since there are multiple workflows, uncomment next line to ignore bower_components
202 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
203 | #bower_components/
204 |
205 | # RIA/Silverlight projects
206 | Generated_Code/
207 |
208 | # Backup & report files from converting an old project file
209 | # to a newer Visual Studio version. Backup files are not needed,
210 | # because we have git ;-)
211 | _UpgradeReport_Files/
212 | Backup*/
213 | UpgradeLog*.XML
214 | UpgradeLog*.htm
215 |
216 | # SQL Server files
217 | *.mdf
218 | *.ldf
219 |
220 | # Business Intelligence projects
221 | *.rdl.data
222 | *.bim.layout
223 | *.bim_*.settings
224 |
225 | # Microsoft Fakes
226 | FakesAssemblies/
227 |
228 | # GhostDoc plugin setting file
229 | *.GhostDoc.xml
230 |
231 | # Node.js Tools for Visual Studio
232 | .ntvs_analysis.dat
233 |
234 | # Visual Studio 6 build log
235 | *.plg
236 |
237 | # Visual Studio 6 workspace options file
238 | *.opt
239 |
240 | # Visual Studio LightSwitch build output
241 | **/*.HTMLClient/GeneratedArtifacts
242 | **/*.DesktopClient/GeneratedArtifacts
243 | **/*.DesktopClient/ModelManifest.xml
244 | **/*.Server/GeneratedArtifacts
245 | **/*.Server/ModelManifest.xml
246 | _Pvt_Extensions
247 |
248 | # Paket dependency manager
249 | .paket/paket.exe
250 | paket-files/
251 |
252 | # FAKE - F# Make
253 | .fake/
254 |
255 | # JetBrains Rider
256 | .idea/
257 | *.sln.iml
258 |
259 | # CodeRush
260 | .cr/
261 |
262 | # Python Tools for Visual Studio (PTVS)
263 | __pycache__/
264 | *.pyc
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAzure/Handler.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.Functions.Worker;
2 | using Microsoft.Azure.Functions.Worker.Http;
3 | using Microsoft.Extensions.Logging;
4 |
5 | namespace LuYao.LightRpc.Demo.Functions.InAzure;
6 |
7 | public class Handler
8 | {
9 | private readonly ILogger _logger;
10 | private readonly MainServer _mainServer;
11 |
12 | public Handler(ILogger logger, MainServer mainServer)
13 | {
14 | _logger = logger;
15 | _mainServer = mainServer;
16 | }
17 |
18 | [Function("Handler")]
19 | public async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req)
20 | {
21 | string action = req.Query["cmd"]?.ToString() ?? String.Empty;
22 | string json = await req.ReadAsStringAsync() ?? string.Empty;
23 | var response = req.CreateResponse();
24 | response.Headers.Add("Content-Type", "application/json");
25 | var input = this._mainServer.DataConverter.Deserialize(json) ?? EmptyDataPackage.Instance;
26 | var result = await this._mainServer.InvokeAsync(action, input);
27 | response.StatusCode = System.Net.HttpStatusCode.OK;
28 | if (result != null)
29 | {
30 | response.StatusCode = (System.Net.HttpStatusCode)result.Code;
31 | if (result.Code == RpcResultCode.Ok)
32 | {
33 | if (result.Data != null)
34 | {
35 | var output = _mainServer.DataConverter.Serialize(result.Data);
36 | await response.WriteStringAsync(output);
37 | }
38 | }
39 | else
40 | {
41 | if (!string.IsNullOrWhiteSpace(result.Message))
42 | {
43 | await response.WriteStringAsync(result.Message);
44 | }
45 | }
46 | }
47 |
48 | return response;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAzure/LuYao.LightRpc.Demo.Functions.InAzure.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net8.0
4 | v4
5 | Exe
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | PreserveNewest
23 |
24 |
25 | PreserveNewest
26 | Never
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAzure/MainServer.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 LuYao.LightRpc.Demo.Functions.InAzure;
8 |
9 | public class MainServer : MainServer
10 | {
11 | public MainServer() : base(new NewtonsoftDataConverter())
12 | {
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAzure/Program.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Demo;
2 | using LuYao.LightRpc.Demo.Functions.InAzure;
3 | using Microsoft.Azure.Functions.Worker;
4 | using Microsoft.Extensions.DependencyInjection;
5 | using Microsoft.Extensions.Hosting;
6 |
7 | var host = new HostBuilder()
8 | .ConfigureFunctionsWorkerDefaults()
9 | .ConfigureServices(services =>
10 | {
11 | services.AddApplicationInsightsTelemetryWorkerService();
12 | services.ConfigureFunctionsApplicationInsights();
13 | services.AddSingleton();
14 | })
15 | .Build();
16 |
17 | host.Run();
18 |
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAzure/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "LuYao.LightRpc.Demo.Functions.InAzure": {
4 | "commandName": "Project",
5 | "commandLineArgs": "--port 7073",
6 | "launchBrowser": false
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAzure/Properties/serviceDependencies.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "appInsights1": {
4 | "type": "appInsights"
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAzure/Properties/serviceDependencies.local.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "appInsights1": {
4 | "type": "appInsights.sdk"
5 | }
6 | }
7 | }
--------------------------------------------------------------------------------
/demo/fc/LuYao.LightRpc.Demo.Functions.InAzure/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "logging": {
4 | "applicationInsights": {
5 | "samplingSettings": {
6 | "isEnabled": true,
7 | "excludedTypes": "Request"
8 | },
9 | "enableLiveMetricsFilters": true
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.Newtonsoft/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.Newtonsoft/JObjectDataPackage.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json.Linq;
2 | using System.Collections.Generic;
3 |
4 | namespace LuYao.LightRpc;
5 |
6 | internal class JObjectDataPackage : SortedDictionary, IDataPackage
7 | {
8 | public void Set(string key, T? value)
9 | {
10 | if (value is null)
11 | {
12 | this.Remove(key);
13 | }
14 | else
15 | {
16 | this[key] = JToken.FromObject(value);
17 | }
18 | }
19 |
20 | public bool TryGetValue(string key, out T? value)
21 | {
22 | if (this.TryGetValue(key, out var token))
23 | {
24 | value = token.ToObject();
25 | return true;
26 | }
27 | value = default;
28 | return false;
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.Newtonsoft/LuYao.LightRpc.Newtonsoft.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net45;net461;netstandard2.0;netstandard2.1;net6.0;net8.0
4 | enable
5 | latest
6 | LuYao.LightRpc
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.Newtonsoft/NewtonsoftDataConverter.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System;
3 |
4 | namespace LuYao.LightRpc;
5 |
6 | public class NewtonsoftDataConverter : IDataConverter
7 | {
8 | public IDataPackage CreatePackage() => new JObjectDataPackage();
9 |
10 | public IDataPackage? Deserialize(string? data)
11 | {
12 | if (string.IsNullOrWhiteSpace(data)) return EmptyDataPackage.Instance;
13 | return JsonConvert.DeserializeObject(data!);
14 | }
15 |
16 | public string Serialize(IDataPackage data) => JsonConvert.SerializeObject(data);
17 | }
18 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/CSharpStringBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuYao.LightRpc;
6 |
7 | public class CSharpStringBuilder
8 | {
9 | private readonly StringBuilder _builder = new StringBuilder();
10 |
11 | public override string ToString() => _builder.ToString();
12 | public void AppendLine(string value)
13 | {
14 | _builder.Append(this._tabString);
15 | _builder.AppendLine(value);
16 | }
17 | public void AppendLine() => _builder.AppendLine();
18 | private string _tabString = string.Empty;
19 | private int _tabs;
20 | private void SetTabs()
21 | {
22 | if (_tabs > 0)
23 | {
24 | _tabString = new string(' ', _tabs);
25 | }
26 | else
27 | {
28 | _tabString = string.Empty;
29 | }
30 | }
31 |
32 | private void AddTab()
33 | {
34 | _tabs += 4;
35 | SetTabs();
36 | }
37 | private void RemoveTab()
38 | {
39 | _tabs -= 4;
40 | if (_tabs < 0) _tabs = 0;
41 | SetTabs();
42 | }
43 | public IDisposable Tab()
44 | {
45 | this.AddTab();
46 | return new DisposeAction(() => this.RemoveTab());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/ControllerDescriptorGenerator.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Models.BuildControllerDescriptor;
2 | using LuYao.LightRpc.Renders.BuildControllerDescriptor;
3 | using Microsoft.CodeAnalysis;
4 | using Microsoft.CodeAnalysis.CSharp.Syntax;
5 | using Microsoft.CodeAnalysis.Text;
6 | using System.Collections.Immutable;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 |
11 | namespace LuYao.LightRpc;
12 |
13 | [Generator]
14 | public class ControllerDescriptorGenerator : IIncrementalGenerator
15 | {
16 | public void Initialize(IncrementalGeneratorInitializationContext context)
17 | {
18 | var classDeclarations = context.SyntaxProvider.ForAttributeWithMetadataName(
19 | "LuYao.LightRpc.Attributes.ControllerAttribute",
20 | predicate: static (node, cancel) => node is ClassDeclarationSyntax,
21 | transform: static (ctx, cancel) => GetSemanticTargetForGeneration(ctx, cancel)
22 | ).Where(m => m.Item1 is not null && m.Item2 is not null);
23 |
24 |
25 | var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());
26 | context.RegisterSourceOutput(compilationAndClasses, Execute);
27 | }
28 |
29 | private static (ClassDeclarationSyntax, AttributeData) GetSemanticTargetForGeneration(GeneratorAttributeSyntaxContext context, CancellationToken ct)
30 | {
31 | if (context.TargetNode is not ClassDeclarationSyntax classDeclaration)
32 | {
33 | return (null, null);
34 | }
35 | AttributeData attribute = context.Attributes.FirstOrDefault(a => a.AttributeClass?.Name == "ControllerAttribute");
36 |
37 | return (classDeclaration, attribute);
38 | }
39 |
40 | private void Execute(SourceProductionContext context, (Compilation Left, ImmutableArray<(ClassDeclarationSyntax, AttributeData)> Right) args)
41 | {
42 | if (!args.Right.Any()) return;
43 | var compilation = args.Left;
44 | foreach ((ClassDeclarationSyntax Syntax, AttributeData Attr) item in args.Right)
45 | {
46 | if (item.Syntax is null || item.Attr is null) continue;
47 |
48 |
49 | string className = item.Syntax.Identifier.ValueText;
50 | string ns = Helpers.GetNamespace(item.Syntax);
51 |
52 | var semanticModel = compilation.GetSemanticModel(item.Syntax.SyntaxTree);
53 | var model = new ControllerModel
54 | {
55 | Name = className,
56 | FullName = $"{ns}.{className}",
57 | Namespace = ns,
58 | };
59 |
60 | BuildModel(context, item, semanticModel, model);
61 |
62 | var render = new ControllerDescriptorRender(model);
63 | var code = render.Render();
64 |
65 | var sourceText = SourceText.From(code, Encoding.UTF8);
66 | context.AddSource($"{ns}.{className}.g.cs", sourceText);
67 | }
68 | }
69 |
70 | private static void BuildModel(SourceProductionContext context, (ClassDeclarationSyntax Syntax, AttributeData Attr) item, SemanticModel semanticModel, ControllerModel model)
71 | {
72 | foreach (var n in item.Attr.NamedArguments)
73 | {
74 | //switch (n.Key)
75 | //{
76 | // case "Controller":
77 | // model.Controller = Convert.ToString(n.Value.Value);
78 | // break;
79 | // case "Area":
80 | // model.Area = Convert.ToString(n.Value.Value);
81 | // break;
82 | //}
83 | }
84 |
85 | var methods = item.Syntax.DescendantNodes().OfType().ToList();
86 | if (methods.Count > 0)
87 | {
88 | foreach (var m in methods)
89 | {
90 | var methodSymbol = semanticModel.GetDeclaredSymbol(m) as IMethodSymbol;
91 | if (IsIgnore(methodSymbol)) continue;
92 | var action = new ActionModel
93 | {
94 | Name = methodSymbol.Name,
95 | ReturnsVoid = methodSymbol.ReturnsVoid,
96 | HasReturnValue = !methodSymbol.ReturnsVoid
97 | };
98 | model.Actions.Add(action);
99 | // 获取方法的返回类型
100 | var returnType = methodSymbol.ReturnType;
101 | // 判断返回类型是否是 Task 或 Task<>
102 | bool returnsTask = returnType.Name == "Task" && (returnType.ContainingNamespace.ToString() == "System.Threading.Tasks");
103 |
104 | // 这个方法是否可以被 await
105 | action.IsAwaitable = returnsTask;
106 |
107 | if (action.IsAwaitable)
108 | {
109 | // 检查返回类型是否是 Task
110 | bool returnsTaskWithoutResult = returnType.Name == "Task" &&
111 | returnType.ContainingNamespace.ToString() == "System.Threading.Tasks";
112 |
113 | // 检查返回类型是否是 Task
114 | bool returnsTaskWithResult = returnType is INamedTypeSymbol namedTypeSymbol &&
115 | namedTypeSymbol.Name == "Task" &&
116 | namedTypeSymbol.TypeArguments.Length == 1 &&
117 | returnType.ContainingNamespace.ToString() == "System.Threading.Tasks";
118 |
119 | // 检查自定义类型是否有 GetAwaiter 并且 GetAwaiter().GetResult() 有返回值
120 | bool customAwaitableReturnsValue = false;
121 | var getAwaiterMethod = returnType.GetMembers("GetAwaiter").OfType().FirstOrDefault();
122 |
123 | if (getAwaiterMethod != null && getAwaiterMethod.Parameters.Length == 0)
124 | {
125 | var awaiterReturnType = getAwaiterMethod.ReturnType;
126 | var getResultMethod = awaiterReturnType.GetMembers("GetResult").OfType().FirstOrDefault();
127 |
128 | if (getResultMethod != null)
129 | {
130 | // 检查 GetResult() 是否有返回值
131 | customAwaitableReturnsValue = !getResultMethod.ReturnsVoid;
132 | }
133 | }
134 |
135 | // 判断 await 后是否有返回值
136 | action.HasReturnValue = returnsTaskWithResult || customAwaitableReturnsValue;
137 | }
138 |
139 | var paras = m.ParameterList.Parameters;
140 | foreach (var p in paras)
141 | {
142 | if (p.Type is null) continue;
143 | var typeInfo = semanticModel.GetTypeInfo(p.Type);
144 | var ap = new ActionParameterModel
145 | {
146 | Name = p.Identifier.ValueText,
147 | Type = typeInfo.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
148 | };
149 | action.Parameters.Add(ap);
150 | }
151 | }
152 | }
153 | }
154 |
155 | private static bool IsIgnore(IMethodSymbol methodSymbol)
156 | {
157 | if (methodSymbol is null) return true;
158 | var accessibility = methodSymbol.DeclaredAccessibility;
159 | if (accessibility != Accessibility.Public) return true;
160 | if (methodSymbol.IsStatic) return true;
161 | if (methodSymbol.IsOverride) return true;
162 | foreach (var attr in methodSymbol.GetAttributes())
163 | {
164 | if (attr.AttributeClass.Name == "IgnoreAttribute")
165 | {
166 | return true;
167 | }
168 | }
169 | return false;
170 | }
171 | }
172 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/DisposeAction.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuYao.LightRpc;
4 |
5 | ///
6 | /// This class can be used to provide an action when
7 | /// Dipose method is called.
8 | ///
9 | public class DisposeAction : IDisposable
10 | {
11 | private readonly Action _action;
12 |
13 | ///
14 | /// Creates a new object.
15 | ///
16 | /// Action to be executed when this object is disposed.
17 | public DisposeAction(Action action)
18 | {
19 | if (action == null)
20 | throw new ArgumentNullException(nameof(action));
21 |
22 | _action = action;
23 | }
24 |
25 | public void Dispose()
26 | {
27 | _action();
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/Helpers.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.CodeAnalysis;
2 | using Microsoft.CodeAnalysis.CSharp.Syntax;
3 |
4 | namespace LuYao.LightRpc;
5 |
6 | internal static class Helpers
7 | {
8 | public static string GetNamespace(BaseTypeDeclarationSyntax syntax)
9 | {
10 | // If we don't have a namespace at all we'll return an empty string
11 | // This accounts for the "default namespace" case
12 | string nameSpace = string.Empty;
13 |
14 | // Get the containing syntax node for the type declaration
15 | // (could be a nested type, for example)
16 | SyntaxNode potentialNamespaceParent = syntax.Parent;
17 |
18 | // Keep moving "out" of nested classes etc until we get to a namespace
19 | // or until we run out of parents
20 | while (potentialNamespaceParent != null &&
21 | potentialNamespaceParent is not NamespaceDeclarationSyntax
22 | && potentialNamespaceParent is not FileScopedNamespaceDeclarationSyntax)
23 | {
24 | potentialNamespaceParent = potentialNamespaceParent.Parent;
25 | }
26 |
27 | // Build up the final namespace by looping until we no longer have a namespace declaration
28 | if (potentialNamespaceParent is BaseNamespaceDeclarationSyntax namespaceParent)
29 | {
30 | // We have a namespace. Use that as the type
31 | nameSpace = namespaceParent.Name.ToString();
32 |
33 | // Keep moving "out" of the namespace declarations until we
34 | // run out of nested namespace declarations
35 | while (true)
36 | {
37 | if (namespaceParent.Parent is not NamespaceDeclarationSyntax parent)
38 | {
39 | break;
40 | }
41 |
42 | // Add the outer namespace as a prefix to the final namespace
43 | nameSpace = $"{namespaceParent.Name}.{nameSpace}";
44 | namespaceParent = parent;
45 | }
46 | }
47 |
48 | // return the final namespace
49 | return nameSpace;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/LuYao.LightRpc.SourceGenerators.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 | LuYao.LightRpc
6 | 10.0
7 | true
8 | false
9 | $(NoWarn);NU5128
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/Models/BuildControllerDescriptor/ActionModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuYao.LightRpc.Models.BuildControllerDescriptor;
6 |
7 | public class ActionModel
8 | {
9 | public string Name { get; set; }
10 | public string Path { get; set; }
11 | public bool ReturnsVoid { get; set; }
12 | public bool IsAwaitable { get; set; }
13 | public bool HasReturnValue { get; set; }
14 | public List Parameters { get; } = new List();
15 | }
16 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/Models/BuildControllerDescriptor/ActionParameterModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuYao.LightRpc.Models.BuildControllerDescriptor;
6 |
7 | public class ActionParameterModel
8 | {
9 | public string Name { get; set; }
10 | public string Type { get; set; }
11 | }
12 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/Models/BuildControllerDescriptor/ControllerModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuYao.LightRpc.Models.BuildControllerDescriptor;
6 |
7 | public class ControllerModel
8 | {
9 | public string Namespace { get; set; }
10 | public string Name { get; set; }
11 | public string FullName { get; set; }
12 |
13 | public List Actions { get; } = new List();
14 |
15 | public string GetActionPath(ActionModel action)
16 | {
17 | var parts = new List();
18 | var n = this.Name;
19 |
20 | if (n.EndsWith("Controller", StringComparison.OrdinalIgnoreCase))
21 | {
22 | n = n.Substring(0, n.Length - "Controller".Length);
23 | }
24 | if (n.EndsWith("Service", StringComparison.OrdinalIgnoreCase))
25 | {
26 | n = n.Substring(0, n.Length - "Service".Length);
27 | }
28 | parts.Add(n);
29 |
30 | n = action.Name;
31 | if (n.EndsWith("Async", StringComparison.OrdinalIgnoreCase))
32 | {
33 | n = n.Substring(0, n.Length - "Async".Length);
34 | }
35 | parts.Add(n);
36 |
37 | return string.Join("/", parts).ToLowerInvariant();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/Models/BuildRpcClientAgent/ActionModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | namespace LuYao.LightRpc.Models.BuildRpcClientAgent;
7 |
8 | public class ActionModel
9 | {
10 | public string Name { get; set; }
11 | public string Command { get; set; }
12 | public bool ReturnsVoid { get; set; }
13 | public bool IsAwaitable { get; set; }
14 | public bool HasReturnValue { get; set; }
15 | public string ReturnType { get; set; }
16 | public string ReturnDataType { get; set; }
17 | public List Parameters { get; } = new List();
18 | public List TypeParameters { get; } = new List();
19 | public bool IsGenericMethod => this.TypeParameters.Any();
20 | public string Accessibility { get; set; }
21 | }
22 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/Models/BuildRpcClientAgent/ActionParameterModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuYao.LightRpc.Models.BuildRpcClientAgent;
6 |
7 | public class ActionParameterModel
8 | {
9 | public string Name { get; set; }
10 | public string Type { get; set; }
11 | }
12 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/Models/BuildRpcClientAgent/ActionTypeParameterModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuYao.LightRpc.Models.BuildRpcClientAgent;
6 |
7 | public class ActionTypeParameterModel : ActionParameterModel
8 | {
9 | public List ConstraintTypes { get; } = new List();
10 | public bool HasReferenceTypeConstraint { get; set; }
11 | public bool HasValueTypeConstraint { get; set; }
12 | public bool HasConstructorConstraint { get; set; }
13 | public bool HasUnmanagedTypeConstraint { get; set; }
14 | public bool HasConstraint => ConstraintTypes.Count > 0 || HasReferenceTypeConstraint || HasValueTypeConstraint || HasConstructorConstraint || HasUnmanagedTypeConstraint;
15 | }
16 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/Models/BuildRpcClientAgent/ClientModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace LuYao.LightRpc.Models.BuildRpcClientAgent;
6 |
7 | public class ClientModel
8 | {
9 | public string Namespace { get; set; }
10 | public string Name { get; set; }
11 | public string FullName { get; set; }
12 | public List Type { get; } = new List();
13 | public List Actions { get; } = new List();
14 | }
15 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/Renders/BuildControllerDescriptor/ControllerDescriptorRender.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Models.BuildControllerDescriptor;
2 | using System;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Xml.Serialization;
7 |
8 | namespace LuYao.LightRpc.Renders.BuildControllerDescriptor;
9 |
10 | public class ControllerDescriptorRender
11 | {
12 | public ControllerModel Controller { get; }
13 |
14 | public ControllerDescriptorRender(ControllerModel controller)
15 | {
16 | Controller = controller;
17 | }
18 | public string Render()
19 | {
20 | var sb = new CSharpStringBuilder();
21 | sb.AppendLine("using System;");
22 | sb.AppendLine("using System.Collections.Generic;");
23 | sb.AppendLine("using System.Threading.Tasks;");
24 | sb.AppendLine("using LuYao.LightRpc;");
25 | sb.AppendLine("using LuYao.LightRpc.Attributes;");
26 | sb.AppendLine("using LuYao.LightRpc.Descriptors;");
27 | sb.AppendLine();
28 | sb.AppendLine($"namespace {this.Controller.Namespace}");
29 | sb.AppendLine("{");
30 | using (sb.Tab()) BuildClass(sb);
31 | sb.AppendLine("}");
32 | return sb.ToString();
33 | }
34 |
35 | private void BuildClass(CSharpStringBuilder sb)
36 | {
37 | sb.AppendLine($"[{this.Controller.Name}.{this.Controller.Name}DescriptorAttribute]");
38 | sb.AppendLine($"partial class {this.Controller.Name}");
39 | sb.AppendLine("{");
40 | using (sb.Tab())
41 | {
42 | this.WriteDescriptorAttribute(sb);
43 | //WriteOutput
44 | this.WriteDebugOutput(sb);
45 | }
46 | sb.AppendLine("}");
47 | }
48 |
49 | private void WriteDescriptorAttribute(CSharpStringBuilder sb)
50 | {
51 | sb.AppendLine($"internal class {this.Controller.Name}DescriptorAttribute : ControllerDescriptorAttribute");
52 | sb.AppendLine("{");
53 | using (sb.Tab())
54 | {
55 | sb.AppendLine($"public override IEnumerable GetActionDescriptors()");
56 | sb.AppendLine("{");
57 | using (sb.Tab())
58 | {
59 | if (this.Controller.Actions.Count > 0)
60 | {
61 | foreach (var action in this.Controller.Actions)
62 | {
63 | sb.AppendLine($"yield return new ActionDescriptor<{this.Controller.Name}>(\"{this.Controller.GetActionPath(action)}\",{action.Name});");
64 | }
65 | }
66 | else
67 | {
68 | sb.AppendLine("yield break;");
69 | }
70 | }
71 | sb.AppendLine("}");
72 |
73 | if (this.Controller.Actions.Count > 0)
74 | {
75 | foreach (var action in this.Controller.Actions)
76 | {
77 | sb.AppendLine($"private static {(action.IsAwaitable ? "async " : "")}Task {action.Name}({this.Controller.Name} controller, InvokeContext context)");
78 | sb.AppendLine("{");
79 | using (sb.Tab())
80 | {
81 | if (action.Parameters.Count > 0)
82 | {
83 | //拷贝变量
84 | sb.AppendLine($"var dict = context.Params;");
85 | //解析参数
86 | foreach (var parameter in action.Parameters)
87 | {
88 | sb.AppendLine($"{parameter.Type} _{parameter.Name} = default;");
89 | sb.AppendLine($"if (dict.TryGetValue<{parameter.Type}>(\"{parameter.Name}\", out var v_{parameter.Name}))");
90 | sb.AppendLine("{");
91 | using (sb.Tab()) sb.AppendLine($"_{parameter.Name} = v_{parameter.Name};");
92 | sb.AppendLine("}");
93 | }
94 | }
95 | var args = string.Join(", ", action.Parameters.Select(p => $"_{p.Name}"));
96 |
97 | //函数调用
98 | if (action.IsAwaitable)
99 | {
100 | if (action.HasReturnValue)
101 | {
102 | sb.AppendLine($"var result = await controller.{action.Name}({args});");
103 | sb.AppendLine($"context.SetResult(result);");
104 | }
105 | else
106 | {
107 | sb.AppendLine($"await controller.{action.Name}({args});");
108 | }
109 | }
110 | else
111 | {
112 | if (action.HasReturnValue)
113 | {
114 | sb.AppendLine($"var result = controller.{action.Name}({args});");
115 | sb.AppendLine($"context.SetResult(result);");
116 | }
117 | else
118 | {
119 | sb.AppendLine($"controller.{action.Name}({args});");
120 | }
121 | }
122 | if (!action.IsAwaitable)
123 | {
124 | sb.AppendLine($"return Task.CompletedTask;");
125 | }
126 | }
127 | sb.AppendLine("}");
128 | }
129 | }
130 | }
131 | sb.AppendLine("}");
132 | }
133 |
134 | private void WriteDebugOutput(CSharpStringBuilder sb)
135 | {
136 | #if DEBUG
137 | var xmlSerializer = new XmlSerializer(typeof(ControllerModel));
138 | string output = string.Empty;
139 | using (var stringWriter = new StringWriter())
140 | {
141 | xmlSerializer.Serialize(stringWriter, this.Controller);
142 | string xmlString = stringWriter.ToString();
143 | var bytes = Encoding.UTF8.GetBytes(xmlString);
144 | output = Convert.ToBase64String(bytes);
145 | }
146 | sb.AppendLine("public static String Output()");
147 | sb.AppendLine("{");
148 | using (sb.Tab()) sb.AppendLine($"return \"{output}\";");
149 | sb.AppendLine("}");
150 | #endif
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/Renders/BuildRpcClientAgent/RpcClientAgentRender.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Models.BuildControllerDescriptor;
2 | using LuYao.LightRpc.Models.BuildRpcClientAgent;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Xml.Serialization;
9 |
10 | namespace LuYao.LightRpc.Renders.BuildRpcClientAgent;
11 |
12 | public class RpcClientAgentRender
13 | {
14 | public ClientModel Client { get; }
15 |
16 | public RpcClientAgentRender(ClientModel client)
17 | {
18 | Client = client;
19 | }
20 | public string Render()
21 | {
22 | var sb = new CSharpStringBuilder();
23 | sb.AppendLine("using System;");
24 | sb.AppendLine("using System.Collections.Generic;");
25 | sb.AppendLine("using System.Threading.Tasks;");
26 | sb.AppendLine("using LuYao.LightRpc;");
27 | sb.AppendLine("using LuYao.LightRpc.Attributes;");
28 | sb.AppendLine("using LuYao.LightRpc.Descriptors;");
29 | sb.AppendLine();
30 | sb.AppendLine($"namespace {this.Client.Namespace}");
31 | sb.AppendLine("{");
32 | using (sb.Tab()) BuildClass(sb);
33 | sb.AppendLine("}");
34 | return sb.ToString();
35 | }
36 |
37 | private void BuildClass(CSharpStringBuilder sb)
38 | {
39 | if (this.Client.Type.Count == 0)
40 | {
41 | sb.AppendLine($"partial class {this.Client.Name}");
42 | }
43 | else
44 | {
45 | sb.AppendLine($"partial class {this.Client.Name}<{string.Join(",", this.Client.Type)}>");
46 | }
47 | sb.AppendLine("{");
48 | using (sb.Tab())
49 | {
50 | this.WriteAgent(sb);
51 | this.WriteDebugOutput(sb);
52 | }
53 | sb.AppendLine("}");
54 | }
55 |
56 | private void WriteAgent(CSharpStringBuilder sb)
57 | {
58 | foreach (var action in this.Client.Actions)
59 | {
60 | sb.AppendLine($"{action.Accessibility} partial {(action.IsAwaitable ? "async " : "")}{action.ReturnType} {action.Name}{BuildTypeArgs(action)}({BuildArgs(action)}){BuildTypeArgsConstraint(action)}");
61 | sb.AppendLine("{");
62 | using (sb.Tab())
63 | {
64 | sb.AppendLine("var _pkg_ = this.CreateDataPackage();");
65 | foreach (var arg in action.Parameters)
66 | {
67 | sb.AppendLine($"_pkg_.Set(\"{arg.Name}\", {arg.Name});");
68 | }
69 | if (action.HasReturnValue)
70 | {
71 | if (action.IsAwaitable)
72 | {
73 | sb.AppendLine($"var result = await this.InvokeAsync<{action.ReturnDataType}>(\"{action.Command}\", _pkg_);");
74 | sb.AppendLine("return result;");
75 | }
76 | else
77 | {
78 | sb.AppendLine($"var result = this.Invoke<{action.ReturnDataType}>(\"{action.Command}\", _pkg_);");
79 | sb.AppendLine("return result;");
80 | }
81 | }
82 | else
83 | {
84 | if (action.IsAwaitable)
85 | {
86 | sb.AppendLine($"await this.InvokeAsync(\"{action.Command}\", _pkg_);");
87 | }
88 | else
89 | {
90 | sb.AppendLine($"this.Invoke(\"{action.Command}\", _pkg_);");
91 | }
92 | }
93 | }
94 | sb.AppendLine("}");
95 | }
96 | }
97 |
98 | private object BuildTypeArgsConstraint(Models.BuildRpcClientAgent.ActionModel action)
99 | {
100 | if (action.IsGenericMethod == false) return string.Empty;
101 | var sb = new StringBuilder();
102 | var args = new List();
103 | foreach (var item in action.TypeParameters)
104 | {
105 | args.Clear();
106 | if (!item.HasConstraint) continue;
107 | if (item.ConstraintTypes.Any()) args.AddRange(item.ConstraintTypes);
108 | if (item.HasReferenceTypeConstraint) args.Add("class");
109 | if (item.HasConstructorConstraint) args.Add("new()");
110 | if (item.HasUnmanagedTypeConstraint)
111 | {
112 | args.Add("unmanaged");
113 | }
114 | else if (item.HasValueTypeConstraint)
115 | {
116 | args.Add("struct");
117 | }
118 | if (args.Count > 0)
119 | {
120 | sb.AppendLine($" where {item.Name} : {string.Join(", ", args)}");
121 | }
122 | }
123 | return sb.ToString();
124 | }
125 |
126 | private string BuildTypeArgs(Models.BuildRpcClientAgent.ActionModel action)
127 | {
128 | if (action.IsGenericMethod == false) return string.Empty;
129 | return $"<{string.Join(",", action.TypeParameters.Select(p => p.Type))}>";
130 | }
131 |
132 | private object BuildArgs(Models.BuildRpcClientAgent.ActionModel action)
133 | {
134 | if (action.Parameters.Count == 0) return string.Empty;
135 | return string.Join(", ", action.Parameters.Select(p => $"{p.Type} {p.Name}"));
136 | }
137 |
138 | private void WriteDebugOutput(CSharpStringBuilder sb)
139 | {
140 | #if DEBUG
141 | var xmlSerializer = new XmlSerializer(this.Client.GetType());
142 | string output = string.Empty;
143 | using (var stringWriter = new StringWriter())
144 | {
145 | xmlSerializer.Serialize(stringWriter, this.Client);
146 | string xmlString = stringWriter.ToString();
147 | var bytes = Encoding.UTF8.GetBytes(xmlString);
148 | output = Convert.ToBase64String(bytes);
149 | }
150 | sb.AppendLine("public static String Output()");
151 | sb.AppendLine("{");
152 | using (sb.Tab()) sb.AppendLine($"return \"{output}\";");
153 | sb.AppendLine("}");
154 | #endif
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc.SourceGenerators/RpcClientAgentGenerator.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Models.BuildRpcClientAgent;
2 | using LuYao.LightRpc.Renders.BuildRpcClientAgent;
3 | using Microsoft.CodeAnalysis;
4 | using Microsoft.CodeAnalysis.CSharp.Syntax;
5 | using Microsoft.CodeAnalysis.Text;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Collections.Immutable;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading;
12 |
13 | namespace LuYao.LightRpc;
14 |
15 | [Generator]
16 | public class RpcClientAgentGenerator : IIncrementalGenerator
17 | {
18 | public void Initialize(IncrementalGeneratorInitializationContext context)
19 | {
20 |
21 | var classDeclarations = context.SyntaxProvider.ForAttributeWithMetadataName(
22 | "LuYao.LightRpc.Attributes.RpcClientAgentAttribute",
23 | predicate: static (node, cancel) => node is ClassDeclarationSyntax,
24 | transform: static (ctx, cancel) => GetSemanticTargetForGeneration(ctx, cancel)
25 | ).Where(m => m.Item1 is not null && m.Item2 is not null);
26 |
27 |
28 | var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());
29 | context.RegisterSourceOutput(compilationAndClasses, Execute);
30 | }
31 | private static (ClassDeclarationSyntax, AttributeData) GetSemanticTargetForGeneration(GeneratorAttributeSyntaxContext context, CancellationToken ct)
32 | {
33 | if (context.TargetNode is not ClassDeclarationSyntax classDeclaration)
34 | {
35 | return (null, null);
36 | }
37 | AttributeData attribute = context.Attributes.FirstOrDefault(a => a.AttributeClass?.Name == "RpcClientAgentAttribute");
38 |
39 | return (classDeclaration, attribute);
40 | }
41 |
42 | private void Execute(SourceProductionContext context, (Compilation Left, ImmutableArray<(ClassDeclarationSyntax, AttributeData)> Right) args)
43 | {
44 | if (!args.Right.Any()) return;
45 | var compilation = args.Left;
46 | foreach ((ClassDeclarationSyntax Syntax, AttributeData Attr) item in args.Right)
47 | {
48 | if (item.Syntax is null || item.Attr is null) continue;
49 |
50 | string className = item.Syntax.Identifier.ValueText;
51 | string ns = Helpers.GetNamespace(item.Syntax);
52 |
53 | var semanticModel = compilation.GetSemanticModel(item.Syntax.SyntaxTree);
54 |
55 | var model = new ClientModel
56 | {
57 | Name = className,
58 | FullName = $"{ns}.{className}",
59 | Namespace = ns,
60 | };
61 |
62 | if (item.Syntax.TypeParameterList != null)
63 | {
64 | var typeParameters = item.Syntax.TypeParameterList.ChildNodes().ToList();
65 | foreach (var t in typeParameters)
66 | {
67 | model.Type.Add(t.ToFullString());
68 | }
69 | }
70 |
71 | BuildModel(context, item, semanticModel, model);
72 |
73 | var render = new RpcClientAgentRender(model);
74 | var code = render.Render();
75 |
76 | var sourceText = SourceText.From(code, Encoding.UTF8);
77 | context.AddSource($"{ns}.{className}.g.cs", sourceText);
78 | }
79 | }
80 | private static void BuildModel(SourceProductionContext context, (ClassDeclarationSyntax Syntax, AttributeData Attr) item, SemanticModel semanticModel, ClientModel model)
81 | {
82 | foreach (var n in item.Attr.NamedArguments)
83 | {
84 | //switch (n.Key)
85 | //{
86 | // case "Controller":
87 | // model.Controller = Convert.ToString(n.Value.Value);
88 | // break;
89 | // case "Area":
90 | // model.Area = Convert.ToString(n.Value.Value);
91 | // break;
92 | //}
93 | }
94 |
95 | var methods = item.Syntax.DescendantNodes().OfType().ToList();
96 | if (methods.Count > 0)
97 | {
98 | foreach (var m in methods)
99 | {
100 | var methodSymbol = semanticModel.GetDeclaredSymbol(m) as IMethodSymbol;
101 | if (IsIgnore(methodSymbol, out var command)) continue;
102 | var action = new ActionModel
103 | {
104 | Name = methodSymbol.Name,
105 | Command = command,
106 | ReturnsVoid = methodSymbol.ReturnsVoid,
107 | HasReturnValue = !methodSymbol.ReturnsVoid,
108 | Accessibility = methodSymbol.DeclaredAccessibility.ToString().ToLower()
109 | };
110 | if (methodSymbol.IsGenericMethod)
111 | {
112 | foreach (var t in methodSymbol.TypeParameters)
113 | {
114 | var mp = new ActionTypeParameterModel
115 | {
116 | Name = t.Name,
117 | Type = t.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
118 | HasReferenceTypeConstraint = t.HasReferenceTypeConstraint,
119 | HasValueTypeConstraint = t.HasValueTypeConstraint,
120 | HasConstructorConstraint = t.HasConstructorConstraint,
121 | HasUnmanagedTypeConstraint = t.HasUnmanagedTypeConstraint
122 | };
123 | action.TypeParameters.Add(mp);
124 | foreach (var type in t.ConstraintTypes)
125 | {
126 | mp.ConstraintTypes.Add(type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat));
127 | }
128 | }
129 | }
130 | model.Actions.Add(action);
131 | // 获取方法的返回类型
132 | var returnType = methodSymbol.ReturnType;
133 | action.ReturnType = returnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
134 | // 判断返回类型是否是 Task 或 Task<>
135 | bool returnsTask = returnType.Name == "Task" && (returnType.ContainingNamespace.ToString() == "System.Threading.Tasks");
136 |
137 | action.ReturnDataType = action.ReturnType;
138 | // 这个方法是否可以被 await
139 | action.IsAwaitable = returnsTask;
140 | if (returnsTask)
141 | {
142 | if (returnType is INamedTypeSymbol named && named.TypeArguments.Any())
143 | {
144 | action.ReturnDataType = named.TypeArguments[0].ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
145 | }
146 | }
147 |
148 | if (action.IsAwaitable)
149 | {
150 | // 检查返回类型是否是 Task
151 | bool returnsTaskWithoutResult = returnType.Name == "Task" &&
152 | returnType.ContainingNamespace.ToString() == "System.Threading.Tasks";
153 |
154 | // 检查返回类型是否是 Task
155 | bool returnsTaskWithResult = returnType is INamedTypeSymbol namedTypeSymbol &&
156 | namedTypeSymbol.Name == "Task" &&
157 | namedTypeSymbol.TypeArguments.Length == 1 &&
158 | returnType.ContainingNamespace.ToString() == "System.Threading.Tasks";
159 |
160 | // 检查自定义类型是否有 GetAwaiter 并且 GetAwaiter().GetResult() 有返回值
161 | bool customAwaitableReturnsValue = false;
162 | var getAwaiterMethod = returnType.GetMembers("GetAwaiter").OfType().FirstOrDefault();
163 |
164 | if (getAwaiterMethod != null && getAwaiterMethod.Parameters.Length == 0)
165 | {
166 | var awaiterReturnType = getAwaiterMethod.ReturnType;
167 | var getResultMethod = awaiterReturnType.GetMembers("GetResult").OfType().FirstOrDefault();
168 |
169 | if (getResultMethod != null)
170 | {
171 | // 检查 GetResult() 是否有返回值
172 | customAwaitableReturnsValue = !getResultMethod.ReturnsVoid;
173 | }
174 | }
175 |
176 | // 判断 await 后是否有返回值
177 | action.HasReturnValue = returnsTaskWithResult || customAwaitableReturnsValue;
178 | }
179 |
180 | var paras = m.ParameterList.Parameters;
181 | foreach (var p in paras)
182 | {
183 | if (p.Type is null) continue;
184 | var typeInfo = semanticModel.GetTypeInfo(p.Type);
185 | var ap = new ActionParameterModel
186 | {
187 | Name = p.Identifier.ValueText,
188 | Type = typeInfo.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)
189 | };
190 | action.Parameters.Add(ap);
191 | }
192 | }
193 | }
194 | }
195 |
196 | private static bool IsIgnore(IMethodSymbol methodSymbol, out string command)
197 | {
198 | command = string.Empty;
199 | if (methodSymbol is null) return true;
200 | if (methodSymbol.IsStatic) return true;
201 | if (methodSymbol.IsOverride) return true;
202 | foreach (var attr in methodSymbol.GetAttributes())
203 | {
204 | if (attr.AttributeClass.Name == "RemoteActionAttribute" && attr.ConstructorArguments.Count() > 0)
205 | {
206 | command = Convert.ToString(attr.ConstructorArguments[0].Value);
207 | return false;
208 | }
209 | }
210 | return true;
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/Attributes/ControllerAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuYao.LightRpc.Attributes;
4 |
5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
6 | public class ControllerAttribute : Attribute
7 | {
8 | }
9 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/Attributes/ControllerDescriptorAttribute.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Descriptors;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace LuYao.LightRpc.Attributes;
6 |
7 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
8 | public abstract class ControllerDescriptorAttribute : Attribute, IControllerDescriptor
9 | {
10 | public abstract IEnumerable GetActionDescriptors();
11 | }
12 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/Attributes/IgnoreAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuYao.LightRpc.Attributes;
4 |
5 | [AttributeUsage(AttributeTargets.Method)]
6 | public class IgnoreAttribute : Attribute
7 | {
8 | }
9 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/Attributes/RemoteActionAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuYao.LightRpc.Attributes;
4 |
5 | [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
6 | public class RemoteActionAttribute : Attribute
7 | {
8 | public RemoteActionAttribute(string command)
9 | {
10 | this.Command = command;
11 | }
12 | public string Command { get; }
13 | }
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/Attributes/RpcClientAgentAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuYao.LightRpc.Attributes;
4 |
5 | [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
6 | public class RpcClientAgentAttribute : Attribute
7 | {
8 | }
9 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/Descriptors/ActionDescriptor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace LuYao.LightRpc.Descriptors;
5 |
6 | public abstract class ActionDescriptor : IActionDescriptor
7 | {
8 | protected ActionDescriptor(string path)
9 | {
10 | if (string.IsNullOrWhiteSpace(path)) throw new System.ArgumentNullException(nameof(path));
11 | Path = path;
12 | }
13 |
14 | public string Path { get; }
15 | public abstract Task Invoke(object controller, InvokeContext context);
16 | }
17 |
18 | public class ActionDescriptor : ActionDescriptor
19 | {
20 | private readonly Func _invoke;
21 |
22 | public ActionDescriptor(string path, Func invoke) : base(path)
23 | {
24 | _invoke = invoke ?? throw new ArgumentNullException(nameof(invoke));
25 | }
26 |
27 | public override Task Invoke(object controller, InvokeContext context)
28 | {
29 | return _invoke((T)controller, context);
30 | }
31 | }
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/Descriptors/IActionDescriptor.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace LuYao.LightRpc.Descriptors;
4 |
5 | public interface IActionDescriptor
6 | {
7 | string Path { get; }
8 | Task Invoke(object controller, InvokeContext context);
9 | }
10 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/Descriptors/IControllerDescriptor.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace LuYao.LightRpc.Descriptors;
4 |
5 | public interface IControllerDescriptor
6 | {
7 | IEnumerable GetActionDescriptors();
8 | }
9 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/EmptyDataPackage.cs:
--------------------------------------------------------------------------------
1 | namespace LuYao.LightRpc;
2 |
3 | public class EmptyDataPackage : IDataPackage
4 | {
5 | public static EmptyDataPackage Instance { get; } = new EmptyDataPackage();
6 | private EmptyDataPackage() { }
7 | public bool TryGetValue(string key, out T? value)
8 | {
9 | value = default(T);
10 | return false;
11 | }
12 |
13 | public void Set(string key, T? value)
14 | {
15 | throw new System.NotSupportedException();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/Http/HttpJsonRpcTunnel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Net.Http;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace LuYao.LightRpc.Http;
8 |
9 | public abstract class HttpJsonRpcTunnel : IRpcTunnel
10 | {
11 | protected HttpJsonRpcTunnel(string endpoint, IDataConverter jsonConverter)
12 | {
13 | if (string.IsNullOrWhiteSpace(endpoint)) throw new ArgumentNullException(nameof(endpoint));
14 | if (jsonConverter == null) throw new ArgumentNullException(nameof(jsonConverter));
15 | this.Endpoint = endpoint;
16 | JsonConverter = jsonConverter;
17 | }
18 | public string Endpoint { get; }
19 | public IDataConverter JsonConverter { get; }
20 |
21 | public IDataConverter DataConverter => this.JsonConverter;
22 | protected virtual string MatchEndpoint(String action) => this.Endpoint;
23 | protected abstract HttpClient CreateHttpClient();
24 |
25 | public virtual RpcResult Send(string action, IDataPackage data)
26 | {
27 | #if NET5_0_OR_GREATER
28 | using var http = this.CreateHttpClient();
29 | using HttpRequestMessage request = CreateHttpRequestMessage(action, data);
30 | using var response = http.Send(request); string body = string.Empty;
31 | using (var ms = response.Content.ReadAsStream())
32 | using (var sr = new StreamReader(ms))
33 | {
34 | body = sr.ReadToEnd();
35 | }
36 | return CreateResult(response, body);
37 | #else
38 | return this.SendAsync(action, data).GetAwaiter().GetResult();
39 | #endif
40 | }
41 |
42 | public virtual async Task SendAsync(string action, IDataPackage data)
43 | {
44 | using var http = this.CreateHttpClient();
45 | using HttpRequestMessage request = CreateHttpRequestMessage(action, data);
46 | using var response = await http.SendAsync(request);
47 | string body = await response.Content.ReadAsStringAsync();
48 | return CreateResult(response, body);
49 | }
50 |
51 | protected virtual RpcResult CreateResult(HttpResponseMessage response, string body)
52 | {
53 | if (response.IsSuccessStatusCode)
54 | {
55 | return new RpcResult
56 | {
57 | Code = RpcResultCode.Ok,
58 | Data = this.JsonConverter.Deserialize(body)
59 | };
60 | }
61 | else
62 | {
63 | return new RpcResult
64 | {
65 | Code = (RpcResultCode)response.StatusCode,
66 | Message = body
67 | };
68 | }
69 | }
70 |
71 | protected virtual HttpRequestMessage CreateHttpRequestMessage(string action, IDataPackage data)
72 | {
73 | var builder = new UriBuilder(this.MatchEndpoint(action));
74 | var nv = System.Web.HttpUtility.ParseQueryString(builder.Query);
75 | nv["cmd"] = action;
76 | builder.Query = nv.ToString();
77 | var url = builder.ToString();
78 | var json = this.JsonConverter.Serialize(data);
79 | var request = new HttpRequestMessage(HttpMethod.Post, url);
80 | request.Content = new StringContent(json, Encoding.UTF8, "application/json");
81 | request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
82 | return request;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/IDataConverter.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace LuYao.LightRpc;
4 |
5 | public interface IDataConverter
6 | {
7 | IDataPackage CreatePackage();
8 | }
9 |
10 | public interface IDataConverter : IDataConverter
11 | {
12 | T Serialize(IDataPackage data);
13 | IDataPackage? Deserialize(T? data);
14 | }
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/IDataPackage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuYao.LightRpc;
4 |
5 | public interface IDataPackage
6 | {
7 | void Set(String key, T? value);
8 | bool TryGetValue(string key, out T? value);
9 | }
10 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/IRpcTunnel.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace LuYao.LightRpc;
4 |
5 | public interface IRpcTunnel
6 | {
7 | IDataConverter DataConverter { get; }
8 | Task SendAsync(string action, IDataPackage data);
9 | RpcResult Send(string action, IDataPackage data);
10 | }
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/InvokeContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuYao.LightRpc;
4 |
5 | public class InvokeContext
6 | {
7 | public IDataPackage Params { get; }
8 | public IDataPackage Response { get; }
9 |
10 | public InvokeContext(IDataPackage @params, IDataPackage response)
11 | {
12 | this.Params = @params;
13 | this.Response = response;
14 | }
15 |
16 |
17 | public void SetResult(T result)
18 | {
19 | this.Response.Set("data", result);
20 | }
21 | }
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/LuYao.LightRpc.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net45;net461;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0
4 | enable
5 | latest
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/RpcClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace LuYao.LightRpc;
5 |
6 | public abstract class RpcClient
7 | {
8 | public abstract IDataPackage CreateDataPackage();
9 | public abstract Task InvokeAsync(String action, IDataPackage package);
10 | public abstract Task InvokeAsync(String action, IDataPackage package);
11 | public abstract TResult Invoke(String action, IDataPackage package);
12 | public abstract void Invoke(String action, IDataPackage package);
13 | }
14 |
15 | public class RpcClient : RpcClient
16 | {
17 | public RpcClient(IRpcTunnel tunnel)
18 | {
19 | Tunnel = tunnel ?? throw new ArgumentNullException(nameof(tunnel));
20 | }
21 |
22 | public IRpcTunnel Tunnel { get; }
23 |
24 | public override IDataPackage CreateDataPackage() => this.Tunnel.DataConverter.CreatePackage();
25 |
26 | public override TResult Invoke(string action, IDataPackage package)
27 | {
28 | var result = this.Tunnel.Send(action, package);
29 | if (result.Code != RpcResultCode.Ok) throw new RpcException(result.Code, result.Message!);
30 | var output = result.Data ?? EmptyDataPackage.Instance;
31 | TResult data = default!;
32 | if (output.TryGetValue("data", out var v_ret)) data = v_ret!;
33 | return data;
34 | }
35 |
36 | public override void Invoke(string action, IDataPackage package)
37 | {
38 | var result = this.Tunnel.Send(action, package);
39 | if (result.Code != RpcResultCode.Ok) throw new RpcException(result.Code, result.Message!);
40 | }
41 |
42 | public override async Task InvokeAsync(String action, IDataPackage package)
43 | {
44 | var result = await this.Tunnel.SendAsync(action, package);
45 | if (result.Code != RpcResultCode.Ok) throw new RpcException(result.Code, result.Message!);
46 | }
47 |
48 | public override async Task InvokeAsync(string action, IDataPackage package)
49 | {
50 | var result = await this.Tunnel.SendAsync(action, package);
51 | if (result.Code != RpcResultCode.Ok) throw new RpcException(result.Code, result.Message!);
52 | var output = result.Data ?? EmptyDataPackage.Instance;
53 | TResult data = default!;
54 | if (output.TryGetValue("data", out var v_ret)) data = v_ret!;
55 | return data;
56 | }
57 | }
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/RpcException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace LuYao.LightRpc;
4 |
5 | public class RpcException : Exception
6 | {
7 | /// 代码
8 | public Int32 Code { get; set; }
9 |
10 | /// 实例化远程调用异常
11 | ///
12 | ///
13 | public RpcException(RpcResultCode code, String message) : base(message) => Code = (int)code;
14 | /// 实例化远程调用异常
15 | ///
16 | ///
17 | public RpcException(Int32 code, String message) : base(message) => Code = code;
18 |
19 | /// 实例化远程调用异常
20 | ///
21 | ///
22 | public RpcException(Int32 code, Exception ex) : base(ex.Message, ex) => Code = code;
23 | }
24 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/RpcResult.cs:
--------------------------------------------------------------------------------
1 | namespace LuYao.LightRpc;
2 |
3 | public class RpcResult
4 | {
5 | public RpcResultCode Code { get; set; }
6 | public string? Message { get; set; }
7 | public IDataPackage? Data { get; set; }
8 | }
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/RpcResultCode.cs:
--------------------------------------------------------------------------------
1 | namespace LuYao.LightRpc;
2 |
3 | public enum RpcResultCode
4 | {
5 | Ok = 200,
6 | Unauthorized = 401,
7 | Forbidden = 403,
8 | NotFound = 404,
9 | InternalServerError = 500
10 | }
11 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/RpcServer.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Attributes;
2 | using LuYao.LightRpc.Descriptors;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Reflection;
7 | using System.Threading.Tasks;
8 |
9 | namespace LuYao.LightRpc;
10 |
11 | public class RpcServer
12 | {
13 | public IDataConverter DataConverter { get; }
14 |
15 | public RpcServer(IDataConverter dataConverter)
16 | {
17 | DataConverter = dataConverter;
18 | }
19 |
20 | private IDictionary _services = new Dictionary(StringComparer.OrdinalIgnoreCase);
21 | public IDictionary Services => _services;
22 |
23 | public void Register() where TController : class, new()
24 | {
25 | var type = typeof(TController);
26 | var attribute = type.GetCustomAttributes(false).FirstOrDefault();
27 | if (attribute == null) throw new InvalidOperationException($"The controller {type.FullName} is not decorated with RpcControllerDescriptorAttribute.");
28 |
29 | lock (this)
30 | {
31 | var controller = new TController();
32 | var temp = new Dictionary(this._services, StringComparer.OrdinalIgnoreCase);
33 | foreach (var action in attribute.GetActionDescriptors())
34 | {
35 | temp[action.Path] = new RpcService(controller, action);
36 | }
37 | this._services = temp;
38 | }
39 | }
40 |
41 | public async Task InvokeAsync(string action, IDataPackage input)
42 | {
43 | if (action == null) throw new ArgumentNullException(nameof(action));
44 | var result = new RpcResult
45 | {
46 | Code = RpcResultCode.Ok,
47 | Data = this.DataConverter.CreatePackage()
48 | };
49 | if (!this.TryFindService(action, out var service))
50 | {
51 | result.Code = RpcResultCode.NotFound;
52 | return result;
53 | }
54 | var context = new InvokeContext(input, result.Data);
55 | try
56 | {
57 | await service!.Descriptor.Invoke(service.Controller, context);
58 | }
59 | catch (Exception e)
60 | {
61 | result.Code = RpcResultCode.InternalServerError;
62 | result.Message = e.Message;
63 | }
64 | return result;
65 | }
66 |
67 | private bool TryFindService(string action, out RpcService? service)
68 | {
69 | if (this.Services.TryGetValue(action, out service))
70 | {
71 | return true;
72 | }
73 | // 局部模糊匹配
74 | var p = action.IndexOf('/');
75 | if (p >= 0)
76 | {
77 | var ctrl = action.Substring(0, p);
78 | if (this.Services.TryGetValue(ctrl + "/*", out service)) return true;
79 | }
80 | // 全局模糊匹配
81 | if (this.Services.TryGetValue("*", out service)) return true;
82 | return false;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/LuYao.LightRpc/RpcService.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Descriptors;
2 | using System;
3 |
4 | namespace LuYao.LightRpc;
5 |
6 | public class RpcService
7 | {
8 | public RpcService(object controller, IActionDescriptor descriptor)
9 | {
10 | Controller = controller;
11 | Descriptor = descriptor;
12 | }
13 | public Object Controller { get; }
14 | public IActionDescriptor Descriptor { get; }
15 | }
16 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.Client/BaseClass.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 LuYao.LightRpc.Test.Client;
8 |
9 | public class BaseClass
10 | {
11 | }
12 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.Client/LuYao.LightRpc.Test.Client.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.Client/MainClient.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Attributes;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LuYao.LightRpc.Test.Client;
9 |
10 | [RpcClientAgent]
11 | public partial class MainClient : RpcClient
12 | {
13 | public MainClient(string endpoint) : base(new MainTunnel(endpoint))
14 | {
15 |
16 | }
17 | [RemoteAction("Test/Sum")]
18 | public partial Task Sum(int a, int b);
19 |
20 | [RemoteAction("Test/Sum")]
21 | public partial Task Sum1(T1 a, T2 b, T3 c)
22 | where T : struct
23 | where T1 : class
24 | where T2 : unmanaged
25 | where T3 : BaseClass, new()
26 | ;
27 | }
28 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.Client/MainTunnel.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Http;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace LuYao.LightRpc.Test.Client;
9 |
10 | public class MainTunnel : HttpJsonRpcTunnel
11 | {
12 | private static readonly SocketsHttpHandler _handler = new SocketsHttpHandler();
13 |
14 | public MainTunnel(string endpoint) : base(endpoint, new NewtonsoftDataConverter())
15 | {
16 |
17 | }
18 |
19 | protected override HttpClient CreateHttpClient()
20 | {
21 | return new HttpClient(_handler, false);
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.Client/Program.cs:
--------------------------------------------------------------------------------
1 | // See https://aka.ms/new-console-template for more information
2 | using LuYao.LightRpc.Test.Client;
3 |
4 | var endpoint = "http://localhost:5287/";
5 | var client = new MainClient(endpoint);
6 | var sum = await client.Sum(1, 2);
7 | Console.WriteLine(sum);
8 | Console.ReadLine();
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.MinimalApi/LuYao.LightRpc.Test.MinimalApi.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.MinimalApi/MainServer.cs:
--------------------------------------------------------------------------------
1 | namespace LuYao.LightRpc.Test.MinimalApi;
2 |
3 | public class MainServer : MainServer
4 | {
5 | public MainServer() : base(new NewtonsoftDataConverter())
6 | {
7 |
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.MinimalApi/Program.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc;
2 | using LuYao.LightRpc.Test.MinimalApi;
3 | using Microsoft.AspNetCore.Mvc;
4 |
5 | var builder = WebApplication.CreateBuilder(args);
6 | // Add services to the container.
7 | builder.Services.AddSingleton();
8 |
9 | var app = builder.Build();
10 |
11 | app.Map("/", async (
12 | HttpContext context,
13 | [FromQuery(Name = "cmd")] string? action,
14 | [FromServices] MainServer server
15 | ) =>
16 | {
17 | if (action is null) action = string.Empty;
18 | string json = string.Empty;
19 | var request = context.Request;
20 | using (var reader = new StreamReader(request.Body))
21 | {
22 | json = await reader.ReadToEndAsync();
23 | }
24 | var input = server.DataConverter.Deserialize(json) ?? EmptyDataPackage.Instance;
25 | var result = await server.InvokeAsync(action, input);
26 | var ret = new RpcHttpResult(result);
27 | return ret;
28 | });
29 |
30 | app.Run();
31 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.MinimalApi/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json.schemastore.org/launchsettings.json",
3 | "iisSettings": {
4 | "windowsAuthentication": false,
5 | "anonymousAuthentication": true,
6 | "iisExpress": {
7 | "applicationUrl": "http://localhost:36880",
8 | "sslPort": 0
9 | }
10 | },
11 | "profiles": {
12 | "http": {
13 | "commandName": "Project",
14 | "dotnetRunMessages": true,
15 | "launchBrowser": true,
16 | "applicationUrl": "http://localhost:5287",
17 | "environmentVariables": {
18 | "ASPNETCORE_ENVIRONMENT": "Development"
19 | }
20 | },
21 | "IIS Express": {
22 | "commandName": "IISExpress",
23 | "launchBrowser": true,
24 | "environmentVariables": {
25 | "ASPNETCORE_ENVIRONMENT": "Development"
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.MinimalApi/RpcHttpResult.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace LuYao.LightRpc.Test.MinimalApi;
3 |
4 | public class RpcHttpResult : IResult
5 | {
6 | public RpcResult RpcResult { get; }
7 |
8 | public RpcHttpResult(RpcResult rpcResult)
9 | {
10 | RpcResult = rpcResult;
11 | }
12 | public async Task ExecuteAsync(HttpContext httpContext)
13 | {
14 | var response = httpContext.Response;
15 | response.StatusCode = (int)this.RpcResult.Code;
16 | if (this.RpcResult.Code == RpcResultCode.Ok)
17 | {
18 | if (this.RpcResult.Data is not null)
19 | {
20 | var server = httpContext.RequestServices.GetRequiredService();
21 | var output = server.DataConverter.Serialize(this.RpcResult.Data);
22 | await response.WriteAsync(output);
23 | }
24 | }
25 | else
26 | {
27 | if (!string.IsNullOrWhiteSpace(this.RpcResult.Message))
28 | {
29 | await response.WriteAsync(this.RpcResult.Message);
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.MinimalApi/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test.MinimalApi/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test/LuYao.LightRpc.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test/MainServer.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 LuYao.LightRpc.Test;
8 |
9 | public class MainServer : RpcServer
10 | {
11 | public MainServer(IDataConverter dataConverter) : base(dataConverter)
12 | {
13 | this.Register();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.Test/TestController.cs:
--------------------------------------------------------------------------------
1 | using LuYao.LightRpc.Attributes;
2 |
3 | namespace LuYao.LightRpc.Test;
4 |
5 | [Controller]
6 | public partial class TestController
7 | {
8 | public int Sum(int a, int b)
9 | {
10 | return a + b;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/tests/LuYao.LightRpc.UnitTests/LuYao.LightRpc.UnitTests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net472;net6.0;net7.0;net8.0
5 |
6 | false
7 | true
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------