ΠΡΠ΅ ΠΌΡ Π·Π½Π°Π΅ΠΌ ΠΊΠ°ΠΊ ΡΠ»ΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°ΡΡ ΠΊΡΡΠΏΠ½ΡΠ΅ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ, ΠΈ ΡΡΠΏΠ΅Π²Π°ΡΡ Π·Π° ΠΏΡΠΎΠ³ΡΠ΅ΡΡΠΎΠΌ. Π Π°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² Π΄Π»Ρ Revit ΡΡΠΎ ΠΏΠΎΠ½ΠΈΠΌΠ°ΡΡ ΠΊΠ°ΠΊ Π½ΠΈΠΊΡΠΎ Π»ΡΡΡΠ΅. ΠΠ°ΠΌ ΠΏΡΠΈΡ ΠΎΠ΄ΠΈΡΡΡ ΠΏΠΈΡΠ°ΡΡ ΡΠ²ΠΎΠΈ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ Π½Π° .NET Framework 4.8. ΠΠ°ΠΌ ΠΏΡΠΈΡ ΠΎΠ΄ΠΈΡΡΡ ΠΎΡΠΊΠ°Π·ΡΠ²Π°ΡΡΡΡ ΠΎΡ ΡΠΎΠ²ΡΠ΅ΠΌΠ΅Π½Π½ΡΡ ΠΈ Π±ΡΡΡΡΡΡ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊ. ΠΡΠΎ Π² ΠΊΠΎΠ½Π΅ΡΠ½ΠΎΠΌ ΡΠΊΠ°Π·ΡΠ²Π°Π΅ΡΡΡ ΠΈ Π½Π° ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡ , ΠΊΠΎΡΠΎΡΡΠ΅ Π²ΡΠ½ΡΠΆΠ΄Π΅Π½Ρ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡΡΡ ΡΡΡΠ°ΡΠ΅Π²ΡΠΈΠΌ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠ½ΡΠΌ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠ΅Π½ΠΈΠ΅ΠΌ.
Π ΡΠ°ΠΊΠΈΡ ΡΡΠ΅Π½Π°ΡΠΈΡΡ ΡΠ°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ Π½Π° Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ΠΌ Named Pipes ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΠ΅ΡΡΡ ΠΏΡΠ΅Π²ΠΎΡΡ ΠΎΠ΄Π½ΡΠΌ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ΠΌ Π±Π»Π°Π³ΠΎΠ΄Π°ΡΡ ΡΠ²ΠΎΠ΅ΠΉ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΠΈ Π½Π°Π΄Π΅ΠΆΠ½ΠΎΡΡΠΈ. Π ΡΡΠΎΠΉ ΡΡΠ°ΡΡΠ΅ ΠΌΡ ΡΠ°ΡΡΠΌΠΎΡΡΠΈΠΌ, ΠΊΠ°ΠΊ ΡΠΎΠ·Π΄Π°ΡΡ ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Named Pipes Π΄Π»Ρ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ Revit, ΡΠ°Π±ΠΎΡΠ°ΡΡΠΈΠΌ Π½Π° .NET 4.8 ΠΈ Π΅Π³ΠΎ ΠΏΠ»Π°Π³ΠΈΠ½Π°, ΡΠ°Π±ΠΎΡΠ°ΡΡΠΈΠΌ Π½Π° .NET 7.
- ΠΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π² ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ Named Pipes Π΄Π»Ρ ΠΎΠ±ΡΠ΅Π½ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡΠΌΠΈ Π½Π° ΡΠ°Π·Π½ΡΡ Π²Π΅ΡΡΠΈΡΡ .NET
- Π§ΡΠΎ ΡΠ°ΠΊΠΎΠ΅ Named Pipes?
- ΠΠ·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡΠΌΠΈ Π½Π° .NET 4.8 ΠΈ .NET 7
- Π£ΡΡΠ°Π½ΠΎΠ²ΠΊΠ° .NET Runtime Π²ΠΎ Π²ΡΠ΅ΠΌΡ ΡΡΡΠ°Π½ΠΎΠ²ΠΊΠΈ ΠΏΠ»Π°Π³ΠΈΠ½Π°
- ΠΠ°ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅
ΠΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ Π² ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ Named Pipes Π΄Π»Ρ ΠΎΠ±ΡΠ΅Π½ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡΠΌΠΈ Π½Π° ΡΠ°Π·Π½ΡΡ Π²Π΅ΡΡΠΈΡΡ .NET
Π ΠΌΠΈΡΠ΅ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ ΡΠ°ΡΡΠΎ ΡΡΠ΅Π±ΡΠ΅ΡΡΡ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΡΡ ΠΎΠ±ΠΌΠ΅Π½ Π΄Π°Π½Π½ΡΠΌΠΈ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠ°Π·Π½ΡΠΌΠΈ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡΠΌΠΈ, ΠΎΡΠΎΠ±Π΅Π½Π½ΠΎ Π² ΡΠ»ΡΡΠ°ΡΡ , ΠΊΠΎΠ³Π΄Π° ΠΎΠ½ΠΈ ΡΠ°Π±ΠΎΡΠ°ΡΡ Π½Π° ΡΠ°Π·Π½ΡΡ Π²Π΅ΡΡΠΈΡΡ .NET ΠΈΠ»ΠΈ ΡΠ°Π·Π½ΡΡ ΡΠ·ΡΠΊΠ°Ρ . Π Π°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ Π½Π° Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±ΡΡΡ ΠΎΠ±ΠΎΡΠ½ΠΎΠ²Π°Π½Π½ΡΠΌ. Π§ΡΠΎ ΠΏΡΠΎΡΠ΅, Π²ΡΠ·Π²Π°ΡΡ ΡΡΠ½ΠΊΡΠΈΡ Π½Π°ΠΏΡΡΠΌΡΡ, ΠΈΠ»ΠΈ ΠΎΠ±ΠΌΠ΅Π½ΡΡΡΡΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡΠΌΠΈ? ΠΡΠ΅Π²ΠΈΠ΄Π½ΠΎ ΠΏΠ΅ΡΠ²ΠΎΠ΅.
Π’ΠΎΠ³Π΄Π° ΠΊΠ°ΠΊΠΈΠ΅ ΠΏΡΠ΅ΠΈΠΌΡΡΠ΅ΡΡΠ²Π° Π² ΡΠΎΠΌ ΡΡΠΎΠ±Ρ ΡΡΠΎ Π΄Π΅Π»Π°ΡΡ?
-
Π Π΅ΡΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ½ΡΠ»ΠΈΠΊΡΠ° Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ
Π‘ ΠΊΠ°ΠΆΠ΄ΡΠΌ Π³ΠΎΠ΄ΠΎΠΌ ΡΠ°Π·ΠΌΠ΅Ρ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² Π΄Π»Ρ Revit Π²ΡΠ΅ Π±ΠΎΠ»ΡΡΠ΅ ΠΈ Π±ΠΎΠ»ΡΡΠ΅ ΡΠ°ΡΡΠ΅Ρ, Π° Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΡΠ°ΡΡΡΡ Π² Π³Π΅ΠΎΠΌΠ΅ΡΡΠΈΡΠ΅ΡΠΊΠΎΠΉ ΠΏΡΠΎΠ³ΡΠ΅ΡΡΠΈΠΈ. ΠΠ»Π°Π³ΠΈΠ½Ρ ΠΌΠΎΠ³ΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π½Π΅ΡΠΎΠ²ΠΌΠ΅ΡΡΠΈΠΌΡΠ΅ Π²Π΅ΡΡΠΈΠΈ ΠΎΠ΄Π½ΠΎΠΉ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠΈ, ΡΡΠΎ Π²ΡΠ·ΠΎΠ²Π΅Ρ ΠΊΡΠ°Ρ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ. ΠΠ·ΠΎΠ»ΡΡΠΈΡ ΠΏΡΠΎΡΠ΅ΡΡΠΎΠ² ΡΠ΅ΡΠ°Π΅Ρ ΡΡΡ ΠΏΡΠΎΠ±Π»Π΅ΠΌΡ.
-
ΠΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΡ
ΠΠΈΠΆΠ΅ ΠΏΡΠΈΠ²Π΅Π΄Π΅Π½Ρ Π·Π°ΠΌΠ΅ΡΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ ΡΠΎΡΡΠΈΡΠΎΠ²ΠΊΠΈ ΠΈ ΠΌΠ°ΡΠ΅ΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈΡ Π²ΡΡΠΈΡΠ»Π΅Π½ΠΈΠΉ Π½Π° ΡΠ°Π·Π½ΡΡ Π²Π΅ΡΡΠΈΡΡ .NET
BenchmarkDotNet v0.13.9, Windows 11 (10.0.22621.1702/22H2/2022Update/SunValley2) AMD Ryzen 5 2600X, 1 CPU, 12 logical and 6 physical cores .NET 7.0 : .NET 7.0.9 (7.0.923.32018), X64 RyuJIT AVX2 .NET Framework 4.8 : .NET Framework 4.8.1 (4.8.9139.0), X64 RyuJIT VectorSize=256Method Runtime Mean Error StdDev Allocated ListSort .NET 7.0 1,113,161.8 ns 20,385.15 ns 21,811.88 ns 804753 B ListOrderBy .NET 7.0 1,064,851.1 ns 12,401.25 ns 11,600.13 ns 807054 B MinValue .NET 7.0 979.4 ns 7.40 ns 6.56 ns - MaxValue .NET 7.0 970.6 ns 4.32 ns 3.60 ns - ListSort .NET Framework 4.8 2,144,723.5 ns 40,359.72 ns 37,752.51 ns 1101646 B ListOrderBy .NET Framework 4.8 2,192,414.7 ns 25,938.78 ns 24,263.15 ns 1105311 B MinValue .NET Framework 4.8 58,019.0 ns 460.30 ns 430.57 ns 40 B MaxValue .NET Framework 4.8 66,053.4 ns 610.28 ns 541.00 ns 41 B Π Π°Π·Π½ΠΈΡΠ° Π² 68 ΡΠ°Π· Π² ΡΠΊΠΎΡΠΎΡΡΠΈ ΠΏΡΠΈ Π½Π°Ρ ΠΎΠΆΠ΄Π΅Π½ΠΈΠΈ ΠΌΠΈΠ½ΠΈΠΌΠ°Π»ΡΠ½ΠΎΠ³ΠΎ Π·Π½Π°ΡΠ΅Π½ΠΈΠ΅, ΠΈ ΠΏΠΎΠ»Π½ΠΎΠ΅ ΠΎΡΡΡΡΡΡΠ²ΠΈΠ΅ Π²ΡΠ΄Π΅Π»Π΅Π½ΠΈΡ ΠΏΠ°ΠΌΡΡΠΈ, Π²ΠΏΠ΅ΡΠ°ΡΠ»ΡΠ΅Ρ.
Π’ΠΎΠ³Π΄Π° ΠΊΠ°ΠΊ Π½Π°ΠΏΠΈΡΠ°ΡΡ ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΡ Π½Π° ΠΏΠΎΡΠ»Π΅Π΄Π½Π΅ΠΉ Π²Π΅ΡΡΠΈΠΈ .NET, ΠΊΠΎΡΠΎΡΠ°Ρ Π±ΡΠ΄Π΅Ρ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΎΠ²Π°ΡΡ Ρ Π½Π΅ΡΠΎΠ²ΠΌΠ΅ΡΡΠΈΠΌΡΠΌ .NET framework? Π‘ΠΎΠ·Π΄Π°ΡΡ Π΄Π²Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, Server ΠΈ Client, Π½Π΅ Π΄ΠΎΠ±Π°Π²Π»ΡΡ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ ΠΌΠ΅ΠΆΠ΄Ρ Π΄ΡΡΠ³ Π΄ΡΡΠ³ΠΎΠΌ ΠΈ Π½Π°ΡΡΡΠΎΠΈΡΡ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ Π½ΠΈΠΌΠΈ ΠΏΠΎ Π½Π°ΡΡΡΠΎΠ΅Π½Π½ΠΎΠΌΡ ΠΏΡΠΎΡΠΎΠΊΠΎΠ»Ρ.
ΠΠΈΠΆΠ΅ ΠΏΡΠΈΠ²Π΅Π΄Π΅Π½Ρ Π½Π΅ΠΊΠΎΡΠΎΡΡΠ΅ ΠΈΠ· Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΡΡ Π²Π°ΡΠΈΠ°Π½ΡΠΎΠ² Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ Π΄Π²ΡΡ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ:
-
ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ WCF (Windows Communication Foundation)
-
ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠΎΠΊΠ΅ΡΠΎΠ² (TCP ΠΈΠ»ΠΈ UDP)
-
ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ Named Pipes
-
ΠΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅ ΡΠΈΠ³Π½Π°Π»ΠΎΠ² ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΎΠ½Π½ΠΎΠΉ ΡΠΈΡΡΠ΅ΠΌΡ (Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, ΡΠΈΠ³Π½Π°Π»ΠΎΠ² Windows):
ΠΡΠΈΠΌΠ΅Ρ ΠΊΠΎΠ΄Π° ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠΈ Autodesk, Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½Π° Project Browser Ρ Π±Π΅ΠΊΠ΅Π½Π΄ΠΎΠΌ Revit ΠΏΠΎΡΡΠ΅Π΄ΡΡΠ²ΠΎΠΌ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ
public class DataTransmitter : IEventObserver { private void PostMessageToMainWindow(int iCmd) => this.HandleOnMainThread((Action) (() => Win32Api.PostMessage(Application.UIApp.getUIApplication().MainWindowHandle, 273U, new IntPtr(iCmd), IntPtr.Zero))); public void HandleShortCut(string key, bool ctrlPressed) { string lower = key.ToLower(); switch (PrivateImplementationDetails.ComputeStringHash(lower)) { case 388133425: if (!(lower == "f2")) break; this.PostMessageToMainWindow(DataTransmitter.ID_RENAME); break; case 1740784714: if (!(lower == "delete")) break; this.PostMessageToMainWindow(DataTransmitter.ID_DELETE); break; case 3447633555: if (!(lower == "contextmenu")) break; this.PostMessageToMainWindow(DataTransmitter.ID_PROJECTBROWSER_CONTEXT_MENU_POP); break; case 3859557458: if (!(lower == "c") || !ctrlPressed) break; this.PostMessageToMainWindow(DataTransmitter.ID_COPY); break; case 4077666505: if (!(lower == "v") || !ctrlPressed) break; this.PostMessageToMainWindow(DataTransmitter.ID_PASTE); break; case 4228665076: if (!(lower == "y") || !ctrlPressed) break; this.PostMessageToMainWindow(DataTransmitter.ID_REDO); break; case 4278997933: if (!(lower == "z") || !ctrlPressed) break; this.PostMessageToMainWindow(DataTransmitter.ID_UNDO); break; } } }
Π£ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ Π²Π°ΡΠΈΠ°Π½ΡΠ° Π΅ΡΡΡ ΡΠ²ΠΎΠΈ Π΄ΠΎΡΡΠΎΠΈΠ½ΡΡΠ²Π° ΠΈ Π½Π΅Π΄ΠΎΡΡΠ°ΡΠΊΠΈ, ΡΠ°ΠΌΡΠΌ ΡΠ΄ΠΎΠ±Π½ΡΠΌ Π½Π° ΠΌΠΎΠΉ Π²Π·Π³Π»ΡΠ΄, Π΄Π»Ρ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ Π½Π° ΠΎΠ΄Π½ΠΎΠΉ Π»ΠΎΠΊΠ°Π»ΡΠ½ΠΎΠΉ ΠΌΠ°ΡΠΈΠ½Π΅ ΡΠ²Π»ΡΠ΅ΡΡΡ Named Pipes. ΠΠ³ΠΎ ΠΌΡ ΠΈ ΡΠ°ΡΡΠΌΠΎΡΡΠΈΠΌ.
Named Pipes ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΡΡ ΡΠΎΠ±ΠΎΠΉ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌ ΠΌΠ΅ΠΆΠΏΡΠΎΡΠ΅ΡΡΠ½ΠΎΠ³ΠΎ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ (Inter-Process Communication, IPC), ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΏΡΠΎΡΠ΅ΡΡΠ°ΠΌ ΠΎΠ±ΠΌΠ΅Π½ΠΈΠ²Π°ΡΡΡΡ Π΄Π°Π½Π½ΡΠΌΠΈ ΡΠ΅ΡΠ΅Π· ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½ΡΠ΅ ΠΊΠ°Π½Π°Π»Ρ. ΠΠ½ΠΈ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°ΡΡ ΠΎΠ΄Π½ΠΎΠ½Π°ΠΏΡΠ°Π²Π»Π΅Π½Π½ΠΎΠ΅ ΠΈΠ»ΠΈ Π΄Π²ΡΠ½Π°ΠΏΡΠ°Π²Π»Π΅Π½Π½ΠΎΠ΅ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΎΡΠ΅ΡΡΠ°ΠΌΠΈ. ΠΠΎΠΌΠΈΠΌΠΎ Π²ΡΡΠΎΠΊΠΎΠΉ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ, Named Pipes ΡΠ°ΠΊΠΆΠ΅ ΠΏΡΠ΅Π΄Π»Π°Π³Π°ΡΡ ΡΠ°Π·Π»ΠΈΡΠ½ΡΠ΅ ΡΡΠΎΠ²Π½ΠΈ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡΠΈ, ΡΡΠΎ Π΄Π΅Π»Π°Π΅Ρ ΠΈΡ ΠΏΡΠΈΠ²Π»Π΅ΠΊΠ°ΡΠ΅Π»ΡΠ½ΡΠΌ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ΠΌ Π΄Π»Ρ ΠΌΠ½ΠΎΠ³ΠΈΡ ΡΡΠ΅Π½Π°ΡΠΈΠ΅Π² Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΎΡΠ΅ΡΡΠ°ΠΌΠΈ.
Π Π°ΡΡΠΌΠΎΡΡΠΈΠΌ Π΄Π²Π° ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ, ΠΎΠ΄Π½ΠΎ ΠΈΠ· ΠΊΠΎΡΠΎΡΡΡ ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ Π±ΠΈΠ·Π½Π΅Ρ-Π»ΠΎΠ³ΠΈΠΊΡ (ΡΠ΅ΡΠ²Π΅Ρ), Π° Π΄ΡΡΠ³ΠΎΠ΅ - ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠΉ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ (ΠΊΠ»ΠΈΠ΅Π½Ρ). ΠΠ»Ρ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠ΅Π½ΠΈΡ ΡΠ²ΡΠ·ΠΈ ΠΌΠ΅ΠΆΠ΄Ρ ΡΡΠΈΠΌΠΈ Π΄Π²ΡΠΌΡ ΠΏΡΠΎΡΠ΅ΡΡΠ°ΠΌΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ NamedPipe.
ΠΡΠΈΠ½ΡΠΈΠΏ ΡΠ°Π±ΠΎΡΡ NamedPipe Π²ΠΊΠ»ΡΡΠ°Π΅Ρ Π² ΡΠ΅Π±Ρ ΡΠ»Π΅Π΄ΡΡΡΠΈΠ΅ ΡΠ°Π³ΠΈ:
- Π‘ΠΎΠ·Π΄Π°Π½ΠΈΠ΅ ΠΈ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ NamedPipe: Π‘Π΅ΡΠ²Π΅Ρ ΡΠΎΠ·Π΄Π°Π΅Ρ ΠΈ ΠΊΠΎΠ½ΡΠΈΠ³ΡΡΠΈΡΡΠ΅Ρ NamedPipe Ρ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΡΠΌ ΠΈΠΌΠ΅Π½Π΅ΠΌ, ΠΊΠΎΡΠΎΡΠΎΠ΅ Π±ΡΠ΄Π΅Ρ Π΄ΠΎΡΡΡΠΏΠ½ΠΎ ΠΊΠ»ΠΈΠ΅Π½ΡΡ. ΠΠ»ΠΈΠ΅Π½ΡΡ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π·Π½Π°ΡΡ ΡΡΠΎ ΠΈΠΌΡ, ΡΡΠΎΠ±Ρ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠΈΡΡΡΡ ΠΊ ΡΡΡΠ±Π΅.
- ΠΠΆΠΈΠ΄Π°Π½ΠΈΠ΅ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ: Π‘Π΅ΡΠ²Π΅Ρ Π½Π°ΡΠΈΠ½Π°Π΅Ρ ΠΎΠΆΠΈΠ΄Π°ΡΡ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠ° ΠΊ ΡΡΡΠ±Π΅. ΠΡΠΎ Π±Π»ΠΎΠΊΠΈΡΡΡΡΠ°Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΡ, ΠΈ ΡΠ΅ΡΠ²Π΅Ρ ΠΎΡΡΠ°Π΅ΡΡΡ Π² ΠΏΠΎΠ΄Π²Π΅ΡΠ΅Π½Π½ΠΎΠΌ ΡΠΎΡΡΠΎΡΠ½ΠΈΠΈ Π΄ΠΎ ΡΠ΅Ρ ΠΏΠΎΡ, ΠΏΠΎΠΊΠ° ΠΊΠ»ΠΈΠ΅Π½Ρ Π½Π΅ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠΈΡΡΡ.
- ΠΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΊ NamedPipe: ΠΠ»ΠΈΠ΅Π½Ρ ΠΈΠ½ΠΈΡΠΈΠΈΡΡΠ΅Ρ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΊ NamedPipe, ΡΠΊΠ°Π·ΡΠ²Π°Ρ ΠΈΠΌΡ ΡΡΡΠ±Ρ, ΠΊ ΠΊΠΎΡΠΎΡΠΎΠΉ ΠΎΠ½ Ρ ΠΎΡΠ΅Ρ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠΈΡΡΡΡ.
- ΠΠ±ΠΌΠ΅Π½ Π΄Π°Π½Π½ΡΠΌΠΈ: ΠΠΎΡΠ»Π΅ ΡΡΠΏΠ΅ΡΠ½ΠΎΠ³ΠΎ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½Ρ ΠΈ ΡΠ΅ΡΠ²Π΅Ρ ΠΌΠΎΠ³ΡΡ ΠΎΠ±ΠΌΠ΅Π½ΠΈΠ²Π°ΡΡΡΡ Π΄Π°Π½Π½ΡΠΌΠΈ Π² Π²ΠΈΠ΄Π΅ Π±Π°ΠΉΡΠΎΠ²ΡΡ ΠΏΠΎΡΠΎΠΊΠΎΠ². ΠΠ»ΠΈΠ΅Π½Ρ ΠΎΡΠΏΡΠ°Π²Π»ΡΠ΅Ρ Π·Π°ΠΏΡΠΎΡΡ Π½Π° Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π±ΠΈΠ·Π½Π΅Ρ-Π»ΠΎΠ³ΠΈΠΊΠΈ, Π° ΡΠ΅ΡΠ²Π΅Ρ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°Π΅Ρ ΡΡΠΈ Π·Π°ΠΏΡΠΎΡΡ ΠΈ ΠΎΡΡΡΠ»Π°Π΅Ρ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ.
- ΠΠ°Π²Π΅ΡΡΠ΅Π½ΠΈΠ΅ ΡΠ΅Π°Π½ΡΠ°: ΠΠΎΡΠ»Π΅ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ ΠΎΠ±ΠΌΠ΅Π½Π° Π΄Π°Π½Π½ΡΠΌΠΈ ΠΊΠ»ΠΈΠ΅Π½Ρ ΠΈ ΡΠ΅ΡΠ²Π΅Ρ ΠΌΠΎΠ³ΡΡ Π·Π°ΠΊΡΡΡΡ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ Ρ NamedPipe.
ΠΠ° ΠΏΠ»Π°ΡΡΠΎΡΠΌΠ΅ .NET ΡΠ΅ΡΠ²Π΅ΡΠ½Π°Ρ ΡΠ°ΡΡΡ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»Π΅Π½Π° ΠΊΠ»Π°ΡΡΠΎΠΌ NamedPipeServerStream. Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΊΠ»Π°ΡΡΠ° ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΠ΅Ρ Π°ΡΠΈΠ½Ρ
ΡΠΎΠ½Π½ΡΠ΅ ΠΈ ΡΠΈΠ½Ρ
ΡΠΎΠ½Π½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ Π΄Π»Ρ ΡΠ°Π±ΠΎΡΡ Ρ NamedPipe.
ΠΠΎ ΠΈΠ·Π±Π΅ΠΆΠ°Π½ΠΈΠ΅ Π±Π»ΠΎΠΊΠΈΡΠΎΠ²ΠΊΠΈ ΠΎΡΠ½ΠΎΠ²Π½ΠΎΠ³ΠΎ ΠΏΠΎΡΠΎΠΊΠ°, ΠΌΡ Π±ΡΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π°ΡΠΈΠ½Ρ
ΡΠΎΠ½Π½ΡΠ΅ ΠΌΠ΅ΡΠΎΠ΄Ρ.
ΠΡΠΈΠΌΠ΅Ρ ΠΊΠΎΠ΄Π° Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ NamedPipeServer:
public static class NamedPipeUtil
{
/// <summary>
/// Create a server for the current user only
/// </summary>
public static NamedPipeServerStream CreateServer(PipeDirection? pipeDirection = null)
{
const PipeOptions pipeOptions = PipeOptions.Asynchronous | PipeOptions.WriteThrough;
return new NamedPipeServerStream(
GetPipeName(),
pipeDirection ?? PipeDirection.InOut,
NamedPipeServerStream.MaxAllowedServerInstances,
PipeTransmissionMode.Byte,
pipeOptions);
}
private static string GetPipeName()
{
var serverDirectory = AppDomain.CurrentDomain.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar);
var pipeNameInput = $"{Environment.UserName}.{serverDirectory}";
var hash = new SHA256Managed().ComputeHash(Encoding.UTF8.GetBytes(pipeNameInput));
return Convert.ToBase64String(hash)
.Replace("/", "_")
.Replace("=", string.Empty);
}
}ΠΠΌΡ ΡΠ΅ΡΠ²Π΅ΡΠ° Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½ΠΎ ΡΠΎΠ΄Π΅ΡΠΆΠ°ΡΡ ΡΠΏΠ΅ΡΠΈΠ°Π»ΡΠ½ΡΠ΅ ΡΠΈΠΌΠ²ΠΎΠ»Ρ Π²ΠΎ ΠΈΠ·Π±Π΅ΠΆΠ°Π½ΠΈΠ΅ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡ. ΠΠ»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΈΠΌΠ΅Π½ΠΈ ΡΡΡΠ±Ρ ΠΌΡ Π±ΡΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Ρ Π΅Ρ, ΡΠΎΠ·Π΄Π°Π½Π½ΡΠΉ ΠΈΠ· ΠΈΠΌΠ΅Π½ΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ ΠΈ ΡΠ΅ΠΊΡΡΠ΅ΠΉ ΠΏΠ°ΠΏΠΊΠΈ, Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½ΠΎ ΡΠ½ΠΈΠΊΠ°Π»ΡΠ½ΠΎ ΡΡΠΎΠ±Ρ ΠΊΠ»ΠΈΠ΅Π½Ρ ΠΏΡΠΈ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π» ΠΈΠΌΠ΅Π½Π½ΠΎ ΡΡΠΎΡ ΡΠ΅ΡΠ²Π΅Ρ. ΠΡ ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡΡ ΡΡΠΎ ΠΏΠΎΠ²Π΅Π΄Π΅Π½ΠΈΠ΅ ΠΈΠ»ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π»ΡΠ±ΠΎΠ΅ ΠΈΠΌΡ Π² ΡΠ°ΠΌΠΊΠ°Ρ ΡΠ²ΠΎΠ΅Π³ΠΎ ΠΏΡΠΎΠ΅ΠΊΡΠ°, ΠΎΡΠΎΠ±Π΅Π½Π½ΠΎ Π΅ΡΠ»ΠΈ ΠΊΠ»ΠΈΠ΅Π½Ρ ΠΈ ΡΠ΅ΡΠ²Π΅Ρ Π½Π°Ρ ΠΎΠ΄ΡΡΡΡ Π² ΡΠ°Π·Π½ΡΡ Π΄ΠΈΡΠ΅ΠΊΡΠΎΡΠΈΡΡ .
ΠΠ°Π½Π½ΡΠΉ ΠΏΠΎΠ΄Ρ ΠΎΠ΄ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ Π² Roslyn .NET compiler. ΠΠ»Ρ ΡΠ΅Ρ ΠΊΡΠΎ ΡΠΈΠ»ΡΠ½Π΅Π΅ Ρ ΠΎΡΠ΅Ρ ΡΠ³Π»ΡΠ±ΠΈΡΡΡΡ Π² ΡΡΡ ΡΠ΅ΠΌΡ, ΡΠ΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡΡ ΠΈΠ·ΡΡΠΈΡΡ ΠΈΡΡ ΠΎΠ΄Π½ΡΠΉ ΠΊΠΎΠ΄ ΠΏΡΠΎΠ΅ΠΊΡΠ°
PipeDirection ΡΠΊΠ°Π·ΡΠ²Π°Π΅Ρ Π½Π°ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΊΠ°Π½Π°Π»Π°, PipeDirection.In Π³ΠΎΠ²ΠΎΡΠΈΡ ΠΎ ΡΠΎΠΌ ΡΡΠΎ ΡΠ΅ΡΠ²Π΅Ρ Π±ΡΠ΄Π΅Ρ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΡΠΈΠ½ΠΈΠΌΠ°ΡΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ, Π° PipeDirection.InOut ΡΠΌΠΎΠΆΠ΅Ρ ΠΊΠ°ΠΊ ΠΏΡΠΈΠ½ΠΈΠΌΠ°ΡΡ, ΡΠ°ΠΊ ΠΈ ΠΎΡΠΏΡΠ°Π²Π»ΡΡΡ ΠΈΡ
.
ΠΠ»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠ° Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΡ ΠΊΠ»Π°ΡΡΠΎΠΌ NamedPipeClientStream. ΠΠΎΠ΄ ΠΏΡΠ°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈ Π°Π½Π°Π»ΠΎΠ³ΠΈΡΠ΅Π½ Ρ ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ, ΠΈ ΠΌΠΎΠΆΠ΅Ρ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ ΠΎΡΠ»ΠΈΡΠ°ΡΡΡΡ Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ Π²Π΅ΡΡΠΈΠΉ .NET.
ΠΠ°ΠΏΡΠΈΠΌΠ΅Ρ, Π² .NET framework 4.8 Π·Π½Π°ΡΠ΅Π½ΠΈΡ PipeOptions.CurrentUserOnly Π½Π΅Ρ, Π½ΠΎ ΠΏΠΎΡΠ²ΠΈΠ»ΠΎΡΡ Π² .NET 7.
/// <summary>
/// Create a client for the current user only
/// </summary>
public static NamedPipeClientStream CreateClient(PipeDirection? pipeDirection = null)
{
const PipeOptions pipeOptions = PipeOptions.Asynchronous | PipeOptions.WriteThrough | PipeOptions.CurrentUserOnly;
return new NamedPipeClientStream(".",
GetPipeName(),
pipeDirection ?? PipeDirection.Out,
pipeOptions);
}
private static string GetPipeName()
{
var clientDirectory = AppDomain.CurrentDomain.BaseDirectory.TrimEnd(Path.DirectorySeparatorChar);
var pipeNameInput = $"{System.Environment.UserName}.{clientDirectory}";
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(pipeNameInput));
return Convert.ToBase64String(bytes)
.Replace("/", "_")
.Replace("=", string.Empty);
}NamedPipe ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΠ΅Ρ ΡΠΎΠ±ΠΎΠΉ Stream, ΡΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ Π½Π°ΠΌ Π·Π°ΠΏΠΈΡΡΠ²Π°ΡΡ Π»ΡΠ±ΡΡ ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°ΡΠ΅Π»ΡΠ½ΠΎΡΡΡ Π±Π°ΠΉΡΠΎΠ² Π² ΠΏΠΎΡΠΎΠΊ. ΠΠ΄Π½Π°ΠΊΠΎ, ΡΠ°Π±ΠΎΡΠ°ΡΡ Ρ Π±Π°ΠΉΡΠ°ΠΌΠΈ Π½Π°ΠΏΡΡΠΌΡΡ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ Π½Π΅ ΠΎΡΠ΅Π½Ρ ΡΠ΄ΠΎΠ±Π½ΠΎ, ΠΎΡΠΎΠ±Π΅Π½Π½ΠΎ ΠΊΠΎΠ³Π΄Π° ΠΌΡ ΠΈΠΌΠ΅Π΅ΠΌ Π΄Π΅Π»ΠΎ ΡΠΎ ΡΠ»ΠΎΠΆΠ½ΡΠΌΠΈ Π΄Π°Π½Π½ΡΠΌΠΈ ΠΈΠ»ΠΈ ΡΡΡΡΠΊΡΡΡΠ°ΠΌΠΈ. ΠΠ»Ρ ΡΠΏΡΠΎΡΠ΅Π½ΠΈΡ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ Ρ ΠΏΠΎΡΠΎΠΊΠ°ΠΌΠΈ Π΄Π°Π½Π½ΡΡ ΠΈ ΡΡΡΡΠΊΡΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ Π² ΡΠ΄ΠΎΠ±Π½ΠΎΠΌ ΡΠΎΡΠΌΠ°ΡΠ΅ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡΡΡ ΠΏΡΠΎΡΠΎΠΊΠΎΠ»Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠΈ.
ΠΡΠΎΡΠΎΠΊΠΎΠ»Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠΈ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΡΡ ΡΠΎΡΠΌΠ°Ρ ΠΈ ΠΏΠΎΡΡΠ΄ΠΎΠΊ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠΈ Π΄Π°Π½Π½ΡΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡΠΌΠΈ. ΠΠ½ΠΈ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°ΡΡ ΡΡΡΡΠΊΡΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠΈ, ΡΡΠΎΠ±Ρ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΡΡ ΠΏΠΎΠ½ΠΈΠΌΠ°Π½ΠΈΠ΅ ΠΈ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΡΡ ΠΈΠ½ΡΠ΅ΡΠΏΡΠ΅ΡΠ°ΡΠΈΡ Π΄Π°Π½Π½ΡΡ ΠΌΠ΅ΠΆΠ΄Ρ ΠΎΡΠΏΡΠ°Π²ΠΈΡΠ΅Π»Π΅ΠΌ ΠΈ ΠΏΠΎΠ»ΡΡΠ°ΡΠ΅Π»Π΅ΠΌ.
Π ΡΠ»ΡΡΠ°Ρ ΠΊΠΎΠ³Π΄Π° Π½Π°ΠΌ Π½ΡΠΆΠ½ΠΎ ΠΎΡΠΏΡΠ°Π²ΠΈΡΡ "ΠΠ°ΠΏΡΠΎΡ Π½Π° Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΠΎΠΉ ΠΊΠΎΠΌΠ°Π½Π΄Ρ Π½Π° ΡΠ΅ΡΠ²Π΅ΡΠ΅" ΠΈΠ»ΠΈ "ΠΠ°ΠΏΡΠΎΡ Π½Π° ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ Π½Π°ΡΡΡΠΎΠ΅ΠΊ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ",
ΡΠ΅ΡΠ²Π΅Ρ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΏΠΎΠ½ΠΈΠΌΠ°ΡΡ ΠΊΠ°ΠΊ Π΅Π³ΠΎ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡ ΠΎΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°.
ΠΠΎΡΡΠΎΠΌΡ Π΄Π»Ρ ΠΎΠ±Π»Π΅Π³ΡΠ΅Π½ΠΈΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π·Π°ΠΏΡΠΎΡΠΎΠ² ΠΈ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ΠΌ ΠΎΠ±ΠΌΠ΅Π½Π° Π΄Π°Π½Π½ΡΠΌΠΈ, ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Enum RequestType.
public enum RequestType
{
PrintMessage,
UpdateModel
}Π‘Π°ΠΌ Π·Π°Π±ΡΠΎΡ Π±ΡΠ΄Π΅Ρ ΠΏΡΠ΅Π΄ΡΡΠ°Π²Π»ΡΡΡ ΠΊΠ»Π°ΡΡ, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΡΠΎΠ΄Π΅ΡΠΆΠ°ΡΡ Π²ΡΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΡ ΠΎ ΠΏΠ΅ΡΠ΅Π΄Π°Π²Π°Π΅ΠΌΡΡ Π΄Π°Π½Π½ΡΡ .
public abstract class Request
{
public abstract RequestType Type { get; }
protected abstract void AddRequestBody(BinaryWriter writer);
/// <summary>
/// Write a Request to the given stream.
/// </summary>
public async Task WriteAsync(Stream outStream)
{
using var memoryStream = new MemoryStream();
using var writer = new BinaryWriter(memoryStream, Encoding.Unicode);
writer.Write((int) Type);
AddRequestBody(writer);
writer.Flush();
// Write the length of the request
var length = checked((int) memoryStream.Length);
// There is no way to know the number of bytes written to
// the pipe stream. We just have to assume all of them are written
await outStream.WriteAsync(BitConverter.GetBytes(length), 0, 4);
memoryStream.Position = 0;
await memoryStream.CopyToAsync(outStream, length);
}
/// <summary>
/// Write a string to the Writer where the string is encoded
/// as a length prefix (signed 32-bit integer) follows by
/// a sequence of characters.
/// </summary>
protected static void WriteLengthPrefixedString(BinaryWriter writer, string value)
{
writer.Write(value.Length);
writer.Write(value.ToCharArray());
}
}ΠΠ»Π°ΡΡ ΡΠΎΠ΄Π΅ΡΠΆΠΈΡ Π±Π°Π·ΠΎΠ²ΡΠΉ ΠΊΠΎΠ΄ Π΄Π»Ρ Π·Π°ΠΏΠΈΡΠΈ Π΄Π°Π½Π½ΡΡ
Π² ΠΏΠΎΡΠΎΠΊ. AddRequestBody() ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄Π½ΡΠΌΠΈ ΠΊΠ»Π°ΡΡΠ°ΠΌΠΈ, Π΄Π»Ρ Π·Π°ΠΏΠΈΡΠΈ Π΄Π»Ρ Π·Π°ΠΏΠΈΡΠΈ ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΡΡ
ΡΡΡΡΠΊΡΡΡΠΈΡΠΎΠ²Π°Π½Π½ΡΡ
Π΄Π°Π½Π½ΡΡ
.
ΠΡΠΈΠΌΠ΅ΡΡ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄Π½ΡΡ ΠΊΠ»Π°ΡΡΠΎΠ²:
/// <summary>
/// Represents a Request from the client. A Request is as follows.
///
/// Field Name Type Size (bytes)
/// --------------------------------------------------
/// RequestType Integer 4
/// Message String Variable
///
/// Strings are encoded via a character count prefix as a
/// 32-bit integer, followed by an array of characters.
///
/// </summary>
public class PrintMessageRequest : Request
{
public string Message { get; }
public override RequestType Type => RequestType.PrintMessage;
public PrintMessageRequest(string message)
{
Message = message;
}
protected override void AddRequestBody(BinaryWriter writer)
{
WriteLengthPrefixedString(writer, Message);
}
}
/// <summary>
/// Represents a Request from the client. A Request is as follows.
///
/// Field Name Type Size (bytes)
/// --------------------------------------------------
/// ResponseType Integer 4
/// Iterations Integer 4
/// ForceUpdate Boolean 1
/// ModelName String Variable
///
/// Strings are encoded via a character count prefix as a
/// 32-bit integer, followed by an array of characters.
///
/// </summary>
public class UpdateModelRequest : Request
{
public int Iterations { get; }
public bool ForceUpdate { get; }
public string ModelName { get; }
public override RequestType Type => RequestType.UpdateModel;
public UpdateModelRequest(string modelName, int iterations, bool forceUpdate)
{
Iterations = iterations;
ForceUpdate = forceUpdate;
ModelName = modelName;
}
protected override void AddRequestBody(BinaryWriter writer)
{
writer.Write(Iterations);
writer.Write(ForceUpdate);
WriteLengthPrefixedString(writer, ModelName);
}
}ΠΡΠΏΠΎΠ»ΡΠ·ΡΡ Π΄Π°Π½Π½ΡΡ ΡΡΡΡΠΊΡΡΡΡ, ΠΊΠ»ΠΈΠ΅Π½ΡΡ ΠΌΠΎΠ³ΡΡ ΡΠΎΠ·Π΄Π°Π²Π°ΡΡ Π·Π°ΠΏΡΠΎΡΡ ΡΠ°Π·Π»ΠΈΡΠ½ΡΡ
ΡΠΈΠΏΠΎΠ², ΠΊΠ°ΠΆΠ΄ΡΠΉ ΠΈΠ· ΠΊΠΎΡΠΎΡΡΡ
ΠΎΠΏΡΠ΅Π΄Π΅Π»ΡΠ΅Ρ ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΡΡ Π»ΠΎΠ³ΠΈΠΊΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π΄Π°Π½Π½ΡΡ
ΠΈ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΠΎΠ².
ΠΠ»Π°ΡΡΡ PrintMessageRequest ΠΈ UpdateModelRequest ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΡΡ ΠΏΡΠΈΠΌΠ΅ΡΡ Π·Π°ΠΏΡΠΎΡΠΎΠ², ΠΊΠΎΡΠΎΡΡΠ΅ ΠΌΠΎΠΆΠ½ΠΎ ΠΎΡΠΏΡΠ°Π²ΠΈΡΡ ΡΠ΅ΡΠ²Π΅ΡΡ Π΄Π»Ρ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΠΊΠΎΠ½ΠΊΡΠ΅ΡΠ½ΡΡ
Π·Π°Π΄Π°Ρ.
ΠΠ° ΡΡΠΎΡΠΎΠ½Π΅ ΡΠ΅ΡΠ²Π΅ΡΠ°, Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠ°ΡΡ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΡΡ Π»ΠΎΠ³ΠΈΠΊΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π²Ρ ΠΎΠ΄ΡΡΠΈΡ Π·Π°ΠΏΡΠΎΡΠΎΠ². ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ ΡΠ΅ΡΠ²Π΅Ρ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΡΠΈΡΠ°ΡΡ Π΄Π°Π½Π½ΡΠ΅ ΠΈΠ· ΠΏΠΎΡΠΎΠΊΠ° ΠΈ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΠΏΠΎΠ»ΡΡΠ΅Π½Π½ΡΠ΅ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ Π΄Π»Ρ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ Π½ΡΠΆΠ½ΡΡ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΉ.
ΠΡΠΈΠΌΠ΅Ρ ΠΏΠΎΠ»ΡΡΠ΅Π½Π½ΠΎΠ³ΠΎ Π·Π°ΠΏΡΠΎΡΠ° Π½Π° ΡΡΠΎΡΠΎΠ½Π΅ ΡΠ΅ΡΠ²Π΅ΡΠ°:
/// <summary>
/// Represents a request from the client. A request is as follows.
///
/// Field Name Type Size (bytes)
/// ----------------------------------------------------
/// RequestType enum RequestType 4
/// RequestBody Request subclass variable
///
/// </summary>
public abstract class Request
{
public enum RequestType
{
PrintMessage,
UpdateModel
}
public abstract RequestType Type { get; }
/// <summary>
/// Read a Request from the given stream.
/// </summary>
public static async Task<Request> ReadAsync(Stream stream)
{
var lengthBuffer = new byte[4];
await ReadAllAsync(stream, lengthBuffer, 4).ConfigureAwait(false);
var length = BitConverter.ToUInt32(lengthBuffer, 0);
var requestBuffer = new byte[length];
await ReadAllAsync(stream, requestBuffer, requestBuffer.Length);
using var reader = new BinaryReader(new MemoryStream(requestBuffer), Encoding.Unicode);
var requestType = (RequestType) reader.ReadInt32();
return requestType switch
{
RequestType.PrintMessage => PrintMessageRequest.Create(reader),
RequestType.UpdateModel => UpdateModelRequest.Create(reader),
_ => throw new ArgumentOutOfRangeException()
};
}
/// <summary>
/// This task does not complete until we are completely done reading.
/// </summary>
private static async Task ReadAllAsync(Stream stream, byte[] buffer, int count)
{
var totalBytesRead = 0;
do
{
var bytesRead = await stream.ReadAsync(buffer, totalBytesRead, count - totalBytesRead);
if (bytesRead == 0) throw new EndOfStreamException("Reached end of stream before end of read.");
totalBytesRead += bytesRead;
} while (totalBytesRead < count);
}
/// <summary>
/// Read a string from the Reader where the string is encoded
/// as a length prefix (signed 32-bit integer) followed by
/// a sequence of characters.
/// </summary>
protected static string ReadLengthPrefixedString(BinaryReader reader)
{
var length = reader.ReadInt32();
return length < 0 ? null : new string(reader.ReadChars(length));
}
}
/// <summary>
/// Represents a Request from the client. A Request is as follows.
///
/// Field Name Type Size (bytes)
/// --------------------------------------------------
/// RequestType Integer 4
/// Message String Variable
///
/// Strings are encoded via a character count prefix as a
/// 32-bit integer, followed by an array of characters.
///
/// </summary>
public class PrintMessageRequest : Request
{
public string Message { get; }
public override RequestType Type => RequestType.PrintMessage;
public PrintMessageRequest(string message)
{
Message = message;
}
protected override void AddRequestBody(BinaryWriter writer)
{
WriteLengthPrefixedString(writer, Message);
}
}
/// <summary>
/// Represents a Request from the client. A Request is as follows.
///
/// Field Name Type Size (bytes)
/// --------------------------------------------------
/// RequestType Integer 4
/// Iterations Integer 4
/// ForceUpdate Boolean 1
/// ModelName String Variable
///
/// Strings are encoded via a character count prefix as a
/// 32-bit integer, followed by an array of characters.
///
/// </summary>
public class UpdateModelRequest : Request
{
public int Iterations { get; }
public bool ForceUpdate { get; }
public string ModelName { get; }
public override RequestType Type => RequestType.UpdateModel;
public UpdateModelRequest(string modelName, int iterations, bool forceUpdate)
{
Iterations = iterations;
ForceUpdate = forceUpdate;
ModelName = modelName;
}
protected override void AddRequestBody(BinaryWriter writer)
{
writer.Write(Iterations);
writer.Write(ForceUpdate);
WriteLengthPrefixedString(writer, ModelName);
}
}ΠΠ΅ΡΠΎΠ΄ ReadAsync() ΡΡΠΈΡΡΠ²Π°Π΅Ρ ΡΠΈΠΏ Π·Π°ΠΏΡΠΎΡΠ° ΠΈΠ· ΠΏΠΎΡΠΎΠΊΠ°, Π° Π·Π°ΡΠ΅ΠΌ, Π² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ ΡΠΈΠΏΠ°, ΡΡΠΈΡΡΠ²Π°Π΅Ρ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠΈΠ΅ Π΄Π°Π½Π½ΡΠ΅ ΠΈ ΡΠΎΠ·Π΄Π°Π΅Ρ ΠΎΠ±ΡΠ΅ΠΊΡ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠ΅Π³ΠΎ Π·Π°ΠΏΡΠΎΡΠ°.
Π Π΅Π°Π»ΠΈΠ·Π°ΡΠΈΡ ΠΏΡΠΎΡΠΎΠΊΠΎΠ»Π° ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠΈ Π΄Π°Π½Π½ΡΡ ΠΈ ΡΡΡΡΠΊΡΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π·Π°ΠΏΡΠΎΡΠΎΠ² Π² Π²ΠΈΠ΄Π΅ ΠΊΠ»Π°ΡΡΠΎΠ² ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡΡ ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎ ΡΠΏΡΠ°Π²Π»ΡΡΡ ΠΎΠ±ΠΌΠ΅Π½ΠΎΠΌ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠ΅ΠΉ ΠΌΠ΅ΠΆΠ΄Ρ ΠΊΠ»ΠΈΠ΅Π½ΡΠΎΠΌ ΠΈ ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ, ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°Ρ ΠΏΡΠΈ ΡΡΠΎΠΌ ΡΡΡΡΠΊΡΡΡΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠ΅ ΠΈ ΠΏΠΎΠ½ΡΡΠ½ΠΎΠ΅ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ Π΄Π²ΡΠΌΡ ΡΡΠΎΡΠΎΠ½Π°ΠΌΠΈ. ΠΠ΄Π½Π°ΠΊΠΎ, ΠΏΡΠΈ ΠΏΡΠΎΠ΅ΠΊΡΠΈΡΠΎΠ²Π°Π½ΠΈΠΈ ΠΏΠΎΠ΄ΠΎΠ±Π½ΡΡ ΠΏΡΠΎΡΠΎΠΊΠΎΠ»ΠΎΠ² Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΡΡΠΈΡΡΠ²Π°ΡΡ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΡΠ΅ ΡΠΈΡΠΊΠΈ Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΠΎΡΡΠΈ, Π° ΡΠ°ΠΊΠΆΠ΅ ΡΠ±Π΅Π΄ΠΈΡΡΡΡ, ΡΡΠΎ ΠΎΠ±Π° ΠΊΠΎΠ½ΡΠ° Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΠΎ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡ Π²ΡΠ΅ Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΡΠ΅ ΡΠ»ΡΡΠ°ΠΈ.
ΠΠ»Ρ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ Ρ UI ΠΊΠ»ΠΈΠ΅Π½ΡΠ° Π½Π° ΡΠ΅ΡΠ²Π΅Ρ, ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΊΠ»Π°ΡΡ ClientDispatcher ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°ΡΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΡ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠΉ, ΡΠ°ΠΉΠΌ-Π°ΡΡΠΎΠ² ΠΈ ΠΏΠ»Π°Π½ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ Π·Π°ΠΏΡΠΎΡΠΎΠ², ΠΏΡΠ΅Π΄ΠΎΡΡΠ°Π²Π»ΡΡ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡ Π΄Π»Ρ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠ° Ρ ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ ΡΠ΅ΡΠ΅Π· ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½ΡΠ΅ ΡΡΡΠ±Ρ.
/// <summary>
/// This class manages the connections, timeout and general scheduling of requests to the server.
/// </summary>
public class ClientDispatcher
{
private const int TimeOutNewProcess = 10000;
private Task _connectionTask;
private readonly NamedPipeClientStream _client = NamedPipeUtil.CreateClient(PipeDirection.Out);
/// <summary>
/// Connects to server without awaiting
/// </summary>
public void ConnectToServer()
{
_connectionTask = _client.ConnectAsync(TimeOutNewProcess);
}
/// <summary>
/// Write a Request to the server.
/// </summary>
public async Task WriteRequestAsync(Request request)
{
await _connectionTask;
await request.WriteAsync(_client);
}
}ΠΡΠΈΠ½ΡΠΈΠΏ ΡΠ°Π±ΠΎΡΡ:
- ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ: Π ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡΠ΅ ΠΊΠ»Π°ΡΡΠ° ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΡΠ΅ΡΡΡ
NamedPipeClientStream, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΠΉ Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΡΠΊΠΎΠ³ΠΎ ΠΏΠΎΡΠΎΠΊΠ° Ρ ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½ΡΠΌ ΠΊΠ°Π½Π°Π»ΠΎΠΌ. - Π£ΡΡΠ°Π½ΠΎΠ²ΠΊΠ° ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ: ΠΠ΅ΡΠΎΠ΄
ConnectToServerΠΈΠ½ΠΈΡΠΈΠΈΡΡΠ΅Ρ Π°ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΠΎΠ΅ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΊ ΡΠ΅ΡΠ²Π΅ΡΡ. Π Π΅Π·ΡΠ»ΡΡΠ°Ρ ΠΎΠΏΠ΅ΡΠ°ΡΠΈΠΈ ΡΠΎΡ ΡΠ°Π½ΡΠ΅ΡΡΡ Π²Task.TimeOutNewProcessΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ Π΄Π»Ρ ΠΎΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠ° Π² ΡΠ»ΡΡΠ°Π΅ Π²ΠΎΠ·Π½ΠΈΠΊΠ½ΠΎΠ²Π΅Π½ΠΈΡ Π½Π΅ΠΏΡΠ΅Π΄Π²ΠΈΠ΄Π΅Π½Π½ΡΡ ΠΈΡΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ. - ΠΡΠΏΡΠ°Π²ΠΊΠ° Π·Π°ΠΏΡΠΎΡΠΎΠ²: ΠΠ΅ΡΠΎΠ΄
WriteRequestAsyncΠΏΡΠ΅Π΄Π½Π°Π·Π½Π°ΡΠ΅Π½ Π΄Π»Ρ Π°ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΠΎΠΉ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ ΠΎΠ±ΡΠ΅ΠΊΡΠ° Request ΡΠ΅ΡΠ΅Π· ΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½Π½ΠΎΠ΅ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅. ΠΠ°ΠΏΡΠΎΡ ΠΎΡΠΏΡΠ°Π²ΠΈΡΡΡ ΡΠΎΠ»ΡΠΊΠΎ ΠΏΠΎΡΠ»Π΅ ΡΡΡΠ°Π½ΠΎΠ²ΠΊΠΈ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡ.
ΠΠ»Ρ ΠΏΡΠΈΠ΅ΠΌΠ° ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ, ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΊΠ»Π°ΡΡ ServerDispatcher ΠΊΠΎΡΠΎΡΡΠΉ ΡΠΏΡΠ°Π²Π»ΡΡΡ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠ΅ΠΌ ΠΈ ΡΠΈΡΠ°ΡΡ Π·Π°ΠΏΡΠΎΡΡ.
/// <summary>
/// This class manages the connections, timeout and general scheduling of the client requests.
/// </summary>
public class ServerDispatcher
{
private readonly NamedPipeServerStream _server = NamedPipeUtil.CreateServer(PipeDirection.In);
/// <summary>
/// This function will accept and process new requests until the client disconnects from the server
/// </summary>
public async Task ListenAndDispatchConnections()
{
try
{
await _server.WaitForConnectionAsync();
await ListenAndDispatchConnectionsCoreAsync();
}
finally
{
_server.Close();
}
}
private async Task ListenAndDispatchConnectionsCoreAsync()
{
while (_server.IsConnected)
{
try
{
var request = await Request.ReadAsync(_server);
if (request.Type == Request.RequestType.PrintMessage)
{
var printRequest = (PrintMessageRequest) request;
Console.WriteLine($"Message from client: {printRequest.Message}");
}
else if (request.Type == Request.RequestType.UpdateModel)
{
var printRequest = (UpdateModelRequest) request;
Console.WriteLine($"The {printRequest.ModelName} model has been {(printRequest.ForceUpdate ? "forcibly" : string.Empty)} updated {printRequest.Iterations} times");
}
}
catch (EndOfStreamException)
{
return; //Pipe disconnected
}
}
}
}ΠΡΠΈΠ½ΡΠΈΠΏ ΡΠ°Π±ΠΎΡΡ:
- ΠΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·Π°ΡΠΈΡ: Π ΠΊΠΎΠ½ΡΡΡΡΠΊΡΠΎΡΠ΅ ΠΊΠ»Π°ΡΡΠ° ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΡΠ΅ΡΡΡ
NamedPipeServerStream, ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΠΉ Π΄Π»Ρ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΡΠ΅ΡΠ²Π΅ΡΠ½ΠΎΠ³ΠΎ ΠΏΠΎΡΠΎΠΊΠ° Ρ ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½ΡΠΌ ΠΊΠ°Π½Π°Π»ΠΎΠΌ. - ΠΡΠΎΡΠ»ΡΡΠΈΠ²Π°Π½ΠΈΠ΅ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΠΉ: ΠΠ΅ΡΠΎΠ΄
ListenAndDispatchConnectionsΠ°ΡΠΈΠ½Ρ ΡΠΎΠ½Π½ΠΎΠ³ΠΎ ΠΎΠΆΠΈΠ΄Π°Π΅Ρ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°, ΠΏΠΎΡΠ»Π΅ Π·Π°Π²Π΅ΡΡΠ΅Π½ΠΈΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π·Π°ΠΏΡΠΎΡΠΎΠ² Π·Π°ΠΊΡΡΠ²Π°Π΅Ρ ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Π½Π½ΡΠΉ ΠΊΠ°Π½Π°Π» ΠΈ ΠΎΡΠ²ΠΎΠ±ΠΎΠΆΠ΄Π°Π΅Ρ ΡΠ΅ΡΡΡΡΡ. - ΠΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π·Π°ΠΏΡΠΎΡΠΎΠ²: ΠΠ΅ΡΠΎΠ΄
ListenAndDispatchConnectionsCoreAsyncΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°Π΅Ρ Π·Π°ΠΏΡΠΎΡΡ, Π΄ΠΎ ΠΌΠΎΠΌΠ΅Π½ΡΠ° ΠΎΡΠΊΠ»ΡΡΠ΅Π½ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°. Π Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ ΠΎΡ ΡΠΈΠΏΠ° Π·Π°ΠΏΡΠΎΡΠ° ΠΏΡΠΎΠΈΡΡ ΠΎΠ΄ΠΈΡ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠ°Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠ° Π΄Π°Π½Π½ΡΡ , Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ, Π²ΡΠ²ΠΎΠ΄ Π² ΠΊΠΎΠ½ΡΠΎΠ»Ρ ΡΠΎΠ΄Π΅ΡΠΆΠ°Π½ΠΈΡ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΡ ΠΈΠ»ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠ΅ ΠΌΠΎΠ΄Π΅Π»ΠΈ.
ΠΡΠΈΠΌΠ΅Ρ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ Π·Π°ΠΏΡΠΎΡΠ° ΠΈΠ· UI Π½Π° ΡΠ΅ΡΠ²Π΅Ρ:
/// <summary>
/// Programme entry point
/// </summary>
public sealed partial class App
{
public static ClientDispatcher ClientDispatcher { get; }
static App()
{
ClientDispatcher = new ClientDispatcher();
ClientDispatcher.ConnectToServer();
}
}
/// <summary>
/// WPF view business logic
/// </summary>
public partial class MainViewModel : ObservableObject
{
[ObservableProperty] private string _message = string.Empty;
[RelayCommand]
private async Task SendMessageAsync()
{
var request = new PrintMessageRequest(Message);
await App.ClientDispatcher.WriteRequestAsync(request);
}
[RelayCommand]
private async Task UpdateModelAsync()
{
var request = new UpdateModelRequest(AppDomain.CurrentDomain.FriendlyName, 666, true);
await App.ClientDispatcher.WriteRequestAsync(request);
}
}ΠΡΠΈΠΌΠ΅Ρ ΠΊΠΎΠ΄Π° ΠΏΠΎΠ»Π½ΠΎΡΡΡΡ Π΄ΠΎΡΡΡΠΏΠ΅Π½ Π² ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠΈ, Π²Ρ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π·Π°ΠΏΡΡΡΠΈΡΡ Π΅Π³ΠΎ Π½Π° ΡΠ²ΠΎΠ΅ΠΉ ΠΌΠ°ΡΠΈΠ½Π΅ Π²ΡΠΏΠΎΠ»Π½ΠΈΠ² Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΎ ΡΠ°Π³ΠΎΠ²:
- ΠΠ°ΠΏΡΡΡΠΈΡΠ΅ "Build Solution"
- ΠΠ°ΠΏΡΡΡΠΈΡΠ΅ "Run OneWay\Backend"
ΠΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ Π·Π°ΠΏΡΡΡΠΈΡ Server ΠΈ Client, Π° ΠΏΠΎΠ»Π½ΡΠΉ Π²ΡΠ²ΠΎΠ΄ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠΉ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡΠΈΡ ΡΡ ΠΏΠΎ NamedPipe Π²Ρ ΡΠ²ΠΈΠ΄ΠΈΡΠ΅ Π² ΠΊΠΎΠ½ΡΠΎΠ»ΠΈ IDE.
Π§Π°ΡΡΠΎ Π²ΠΎΠ·Π½ΠΈΠΊΠ°ΡΡ ΡΠΈΡΡΠ°ΡΠΈΠΈ, ΠΊΠΎΠ³Π΄Π° ΠΎΠ±ΡΡΠ½Π°Ρ ΠΎΠ΄Π½ΠΎΠ½Π°ΠΏΡΠ°Π²Π»Π΅Π½Π½Π°Ρ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠ° Π΄Π°Π½Π½ΡΡ ΠΎΡ ΠΊΠ»ΠΈΠ΅Π½ΡΠ° ΠΊ ΡΠ΅ΡΠ²Π΅ΡΡ Π½Π΅Π΄ΠΎΡΡΠ°ΡΠΎΡΠ½Π°. Π ΡΠ°ΠΊΠΈΡ ΡΠ»ΡΡΠ°ΡΡ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡ ΠΎΡΠΈΠ±ΠΊΠΈ ΠΈΠ»ΠΈ ΠΎΡΠΏΡΠ°Π²Π»ΡΡΡ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ Π² ΠΎΡΠ²Π΅Ρ. Π§ΡΠΎΠ±Ρ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΡΡ Π±ΠΎΠ»Π΅Π΅ ΡΠ»ΠΎΠΆΠ½ΠΎΠ΅ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ ΠΊΠ»ΠΈΠ΅Π½ΡΠΎΠΌ ΠΈ ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ, ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ°ΠΌ ΠΏΡΠΈΡ ΠΎΠ΄ΠΈΡΡΡ ΠΏΡΠΈΠ±Π΅Π³Π°ΡΡ ΠΊ ΠΏΡΠΈΠΌΠ΅Π½Π΅Π½ΠΈΡ Π΄Π²ΡΡ ΡΡΠΎΡΠΎΠ½Π½Π΅ΠΉ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΠΈ Π΄Π°Π½Π½ΡΡ , ΠΊΠΎΡΠΎΡΠ°Ρ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΎΠ±ΠΌΠ΅Π½ΠΈΠ²Π°ΡΡΡΡ ΠΈΠ½ΡΠΎΡΠΌΠ°ΡΠΈΠ΅ΠΉ Π² ΠΎΠ±ΠΎΠΈΡ Π½Π°ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡΡ .
ΠΠ°ΠΊ ΠΈ Π² ΡΠ»ΡΡΠ°Π΅ Ρ Π·Π°ΠΏΡΠΎΡΠ°ΠΌΠΈ, Π΄Π»Ρ ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΠΉ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΎΡΠ²Π΅ΡΠΎΠ² ΡΠ°ΠΊΠΆΠ΅ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠΏΡΠ΅Π΄Π΅Π»ΠΈΡΡ ΠΏΠ΅ΡΠ΅ΡΠΈΡΠ»Π΅Π½ΠΈΠ΅ Π΄Π»Ρ ΡΠΈΠΏΠΎΠ² ΠΎΡΠ²Π΅ΡΠΎΠ². ΠΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΡ ΠΏΡΠ°Π²ΠΈΠ»ΡΠ½ΠΎ ΠΈΠ½ΡΠ΅ΡΠΏΡΠ΅ΡΠΈΡΠΎΠ²Π°ΡΡ ΠΏΠΎΠ»ΡΡΠ΅Π½Π½ΡΠ΅ Π΄Π°Π½Π½ΡΠ΅.
public enum ResponseType
{
// The update request completed on the server and the results are contained in the message.
UpdateCompleted,
// The request was rejected by the server.
Rejected
}ΠΠ»Ρ ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎΠΉ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ ΠΎΡΠ²Π΅ΡΠΎΠ² ΠΏΠΎΡΡΠ΅Π±ΡΠ΅ΡΡΡ ΡΠΎΠ·Π΄Π°ΡΡ Π½ΠΎΠ²ΡΠΉ ΠΊΠ»Π°ΡΡ, Π½Π°Π·Π²Π°Π½Π½ΡΠΉ Response. ΠΠΎ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»Ρ ΠΎΠ½ Π½ΠΈΡΠ΅ΠΌ Π½Π΅ ΠΎΡΠ»ΠΈΡΠ°Π΅ΡΡΡ ΠΎΡ ΠΊΠ»Π°ΡΡΠ° Request, ΠΎΠ΄Π½Π°ΠΊΠΎ Π² ΠΎΡΠ»ΠΈΡΠΈΠ΅ ΠΎΡ Request, ΠΊΠΎΡΠΎΡΡΠΉ ΠΌΠΎΠΆΠ΅Ρ ΡΠΈΡΠ°ΡΡΡΡ Π½Π° ΡΠ΅ΡΠ²Π΅ΡΠ΅, Response Π±ΡΠ΄Π΅Ρ Π·Π°ΠΏΠΈΡΡΠ²Π°ΡΡΡΡ Π² ΠΏΠΎΡΠΎΠΊ.
/// <summary>
/// Base class for all possible responses to a request.
/// The ResponseType enum should list all possible response types
/// and ReadResponse creates the appropriate response subclass based
/// on the response type sent by the client.
/// The format of a response is:
///
/// Field Name Field Type Size (bytes)
/// -------------------------------------------------
/// ResponseType enum ResponseType 4
/// ResponseBody Response subclass variable
/// </summary>
public abstract class Response
{
public enum ResponseType
{
// The update request completed on the server and the results are contained in the message.
UpdateCompleted,
// The request was rejected by the server.
Rejected
}
public abstract ResponseType Type { get; }
protected abstract void AddResponseBody(BinaryWriter writer);
/// <summary>
/// Write a Response to the stream.
/// </summary>
public async Task WriteAsync(Stream outStream)
{
// Same as request class from client
}
/// <summary>
/// Write a string to the Writer where the string is encoded
/// as a length prefix (signed 32-bit integer) follows by
/// a sequence of characters.
/// </summary>
protected static void WriteLengthPrefixedString(BinaryWriter writer, string value)
{
// Same as request class from client
}
}ΠΡΠΎΠΈΠ·Π²ΠΎΠ΄Π½ΡΠ΅ ΠΊΠ»Π°ΡΡΡ Π²Ρ ΠΌΠΎΠΆΠ΅ΡΠ΅ Π½Π°ΠΉΡΠΈ Π² ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠΈ ΠΏΡΠΎΠ΅ΠΊΡΠ°: PipeProtocol
ΠΠ»Ρ ΡΠΎΠ³ΠΎ ΡΡΠΎΠ±Ρ ΡΠ΅ΡΠ²Π΅Ρ ΠΌΠΎΠ³ ΠΎΡΠΏΡΠ°Π²Π»ΡΡΡ ΠΎΡΠ²Π΅ΡΡ ΠΊΠ»ΠΈΠ΅Π½ΡΡ, ΠΌΡ Π΄ΠΎΠ»ΠΆΠ½Ρ ΠΌΠΎΠ΄ΠΈΡΠΈΡΠΈΡΠΎΠ²Π°ΡΡ ΠΊΠ»Π°ΡΡ ServerDispatcher.
ΠΡΠΎ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ Π·Π°ΠΏΠΈΡΡΠ²Π°ΡΡ ΠΎΡΠ²Π΅ΡΡ Π² Stream ΠΏΠΎΡΠ»Π΅ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ Π·Π°Π΄Π°ΡΠΈ.
Π’Π°ΠΊ ΠΆΠ΅ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠΌ Π½Π°ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ ΡΡΡΠ±Ρ Π½Π° Π΄Π²ΡΠ½Π°ΠΏΡΠ°Π²Π»Π΅Π½Π½ΠΎΠ΅:
_server = NamedPipeUtil.CreateServer(PipeDirection.InOut);
/// <summary>
/// Write a Response to the client.
/// </summary>
public async Task WriteResponseAsync(Response response) => await response.WriteAsync(_server);ΠΠ»Ρ Π΄Π΅ΠΌΠΎΠ½ΡΡΡΠ°ΡΠΈΠΈ ΡΠ°Π±ΠΎΡΡ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π·Π°Π΄Π΅ΡΠΆΠΊΡ Π½Π° 2 ΡΠ΅ΠΊΡΠ½Π΄Ρ, ΡΠΌΡΠ»ΠΈΡΡΡ ΡΡΠΆΠ΅Π»ΡΡ Π·Π°Π΄Π°ΡΡ, Π² ΠΌΠ΅ΡΠΎΠ΄Π΅ ListenAndDispatchConnectionsCoreAsync:
private async Task ListenAndDispatchConnectionsCoreAsync()
{
while (_server.IsConnected)
{
try
{
var request = await Request.ReadAsync(_server);
// ...
if (request.Type == Request.RequestType.UpdateModel)
{
var printRequest = (UpdateModelRequest) request;
await Task.Delay(TimeSpan.FromSeconds(2));
await WriteResponseAsync(new UpdateCompletedResponse(changes: 69, version: "2.1.7"));
}
}
catch (EndOfStreamException)
{
return; //Pipe disconnected
}
}
}Π Π½Π°ΡΡΠΎΡΡΠΈΠΉ ΠΌΠΎΠΌΠ΅Π½Ρ ΠΊΠ»ΠΈΠ΅Π½Ρ Π½Π΅ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°Π΅Ρ ΠΎΡΠ²Π΅ΡΡ ΠΎΡ ΡΠ΅ΡΠ²Π΅ΡΠ°. ΠΠ°Π²Π°ΠΉΡΠ΅ ΡΠ΄Π΅Π»Π°Π΅ΠΌ ΡΡΠΎ. Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π² ΠΊΠ»ΠΈΠ΅Π½ΡΠ΅ ΠΊΠ»Π°ΡΡ Response, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡ ΠΏΠΎΠ»ΡΡΠ΅Π½Π½ΡΠ΅ ΠΎΡΠ²Π΅ΡΡ.
/// <summary>
/// Base class for all possible responses to a request.
/// The ResponseType enum should list all possible response types
/// and ReadResponse creates the appropriate response subclass based
/// on the response type sent by the client.
/// The format of a response is:
///
/// Field Name Field Type Size (bytes)
/// -------------------------------------------------
/// ResponseType enum ResponseType 4
/// ResponseBody Response subclass variable
///
/// </summary>
public abstract class Response
{
public enum ResponseType
{
// The update request completed on the server and the results are contained in the message.
UpdateCompleted,
// The request was rejected by the server.
Rejected
}
public abstract ResponseType Type { get; }
/// <summary>
/// Read a Request from the given stream.
/// </summary>
public static async Task<Response> ReadAsync(Stream stream)
{
// Same as request class from server
}
/// <summary>
/// This task does not complete until we are completely done reading.
/// </summary>
private static async Task ReadAllAsync(Stream stream, byte[] buffer, int count)
{
// Same as request class from server
}
/// <summary>
/// Read a string from the Reader where the string is encoded
/// as a length prefix (signed 32-bit integer) followed by
/// a sequence of characters.
/// </summary>
protected static string ReadLengthPrefixedString(BinaryReader reader)
{
// Same as request class from server
}
}ΠΠ°Π»Π΅Π΅ ΠΎΠ±Π½ΠΎΠ²ΠΈΠΌ ΠΊΠ»Π°ΡΡ ClientDispatcher, ΡΡΠΎΠ±Ρ ΠΎΠ½ ΠΌΠΎΠ³ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡ ΠΎΡΠ²Π΅ΡΡ ΠΎΡ ΡΠ΅ΡΠ²Π΅ΡΠ°. ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ Π½ΠΎΠ²ΡΠΉ ΠΌΠ΅ΡΠΎΠ΄ ΠΈ ΠΈΠ·ΠΌΠ΅Π½ΠΈΠΌ Π½Π°ΠΏΡΠ°Π²Π»Π΅Π½ΠΈΠ΅ Π½Π° Π΄Π²ΡΠ½Π°ΠΏΡΠ°Π²Π»Π΅Π½Π½ΠΎΠ΅.
_client = NamedPipeUtil.CreateClient(PipeDirection.InOut);
/// <summary>
/// Read a Response from the server.
/// </summary>
public async Task<Response> ReadResponseAsync() => await Response.ReadAsync(_client);Π’Π°ΠΊΠΆΠ΅ Π΄ΠΎΠ±Π°Π²ΠΈΠΌ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΡ ΠΎΡΠ²Π΅ΡΠ° Π²ΠΎ ViewModel, Π³Π΄Π΅ Π±ΡΠ΄Π΅ΠΌ ΠΏΡΠΎΡΡΠΎ Π²ΡΠ²ΠΎΠ΄ΠΈΡΡ Π΅Π³ΠΎ ΠΊΠ°ΠΊ ΡΠΎΠΎΠ±ΡΠ΅Π½ΠΈΠ΅.
[RelayCommand]
private async Task UpdateModelAsync()
{
var request = new UpdateModelRequest(AppDomain.CurrentDomain.FriendlyName, 666, true);
await App.ClientDispatcher.WriteRequestAsync(request);
var response = await App.ClientDispatcher.ReadResponseAsync();
if (response.Type == Response.ResponseType.UpdateCompleted)
{
var completedResponse = (UpdateCompletedResponse) response;
MessageBox.Show($"{completedResponse.Changes} elements successfully updated to version {completedResponse.Version}");
}
else if (response.Type == Response.ResponseType.Rejected)
{
MessageBox.Show("Update failed");
}
}ΠΡΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡ Π±ΠΎΠ»Π΅Π΅ ΡΡΡΠ΅ΠΊΡΠΈΠ²Π½ΠΎ ΠΎΡΠ³Π°Π½ΠΈΠ·ΠΎΠ²Π°ΡΡ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΠ΅ ΠΌΠ΅ΠΆΠ΄Ρ ΠΊΠ»ΠΈΠ΅Π½ΡΠΎΠΌ ΠΈ ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ, ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°Ρ Π±ΠΎΠ»Π΅Π΅ ΠΏΠΎΠ»Π½ΡΡ ΠΈ Π½Π°Π΄Π΅ΠΆΠ½ΡΡ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΡ Π·Π°ΠΏΡΠΎΡΠΎΠ² ΠΈ ΠΎΡΠ²Π΅ΡΠΎΠ².
Π’Π΅Ρ Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ ΡΠ°Π·Π²ΠΈΠ²Π°ΡΡΡΡ, Π° Revit Π½Π΅ ΠΌΠ΅Π½ΡΠ΅ΡΡΡ Β© ΠΠΎΠ½ΡΡΡΠΈΠΉ
Π Π½Π°ΡΡΠΎΡΡΠ΅Π΅ Π²ΡΠ΅ΠΌΡ Revit ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅Ρ .NET Framework 4.8. ΠΠ΄Π½Π°ΠΊΠΎ Π΄Π»Ρ ΡΠ»ΡΡΡΠ΅Π½ΠΈΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΎΠ³ΠΎ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠ° ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ², ΡΠ°ΡΡΠΌΠΎΡΡΠΈΠΌ ΠΏΠ΅ΡΠ΅Ρ ΠΎΠ΄ Π½Π° .NET 7. ΠΠ°ΠΆΠ½ΠΎ ΠΎΡΠΌΠ΅ΡΠΈΡΡ, ΡΡΠΎ Π±ΡΠΊΡΠ½Π΄ ΠΏΠ»Π°Π³ΠΈΠ½Π° Π±ΡΠ΄Π΅Ρ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΎΠ²Π°ΡΡ ΡΠΎΠ»ΡΠΊΠΎ Ρ Revit Π½Π° ΡΡΡΠ°ΡΠ΅Π²ΡΠ΅ΠΌ Framework, ΠΈ Π±ΡΠ΄Π΅Ρ Π²ΡΡΡΡΠΏΠ°ΡΡ Π² ΠΊΠ°ΡΠ΅ΡΡΠ²Π΅ ΡΠ΅ΡΠ²Π΅ΡΠ°.
ΠΠ°Π²Π°ΠΉΡΠ΅ ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΌΠ΅Ρ Π°Π½ΠΈΠ·ΠΌ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ, ΠΊΠΎΡΠΎΡΡΠΉ ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ ΠΊΠ»ΠΈΠ΅Π½ΡΡ ΠΎΡΠΏΡΠ°Π²Π»ΡΡΡ Π·Π°ΠΏΡΠΎΡΡ Π½Π° ΡΠ΄Π°Π»Π΅Π½ΠΈΠ΅ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² ΠΌΠΎΠ΄Π΅Π»ΠΈ, Π° Π·Π°ΡΠ΅ΠΌ ΠΏΠΎΠ»ΡΡΠ°ΡΡ ΠΎΡΠ²Π΅ΡΡ ΠΎ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΠ΅ ΡΠ΄Π°Π»Π΅Π½ΠΈΡ. ΠΠ»Ρ ΡΠ΅Π°Π»ΠΈΠ·Π°ΡΠΈΠΈ ΡΡΠΎΠΉ ΡΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½ΠΎΡΡΠΈ ΠΌΡ Π±ΡΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ Π΄Π²ΡΡΡΠΎΡΠΎΠ½Π½ΡΡ ΠΏΠ΅ΡΠ΅Π΄Π°ΡΡ Π΄Π°Π½Π½ΡΡ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠ΅ΡΠ²Π΅ΡΠΎΠΌ ΠΈ ΠΊΠ»ΠΈΠ΅Π½ΡΠΎΠΌ.
ΠΠ΅ΡΠ²ΡΠΌ ΡΠ°Π³ΠΎΠΌ Π² Π½Π°ΡΠ΅ΠΌ ΠΏΡΠΎΡΠ΅ΡΡΠ΅ ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠΈ Π±ΡΠ΄Π΅Ρ Π½Π°ΡΡΠΈΡΡ ΠΏΠ»Π°Π³ΠΈΠ½ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΈ Π·Π°ΠΊΡΡΠ²Π°ΡΡΡΡ ΠΏΡΠΈ Π·Π°ΠΊΡΡΡΠΈΠΈ Revit. ΠΠ»Ρ ΡΡΠΎΠ³ΠΎ ΠΌΡ Π½Π°ΠΏΠΈΡΠ°Π»ΠΈ ΠΌΠ΅ΡΠΎΠ΄, ΠΊΠΎΡΠΎΡΡΠΉ ΠΎΡΠΏΡΠ°Π²Π»ΡΠ΅Ρ ID ΡΠ΅ΠΊΡΡΠ΅Π³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° ΠΊΠ»ΠΈΠ΅Π½ΡΡ. ΠΡΠΎ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ ΠΊΠ»ΠΈΠ΅Π½ΡΡ ΠΎΡΡΡΠ΅ΡΡΠ²ΠΈΡΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠ΅ Π·Π°ΠΊΡΡΡΠΈΠ΅ ΡΠ²ΠΎΠ΅Π³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° ΠΏΡΠΈ Π·Π°ΠΊΡΡΡΠΈΠΈ ΡΠΎΠ΄ΠΈΡΠ΅Π»ΡΡΠΊΠΎΠ³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° Revit.
ΠΠΎΠ΄ Π΄Π»Ρ ΠΎΡΠΏΡΠ°Π²ΠΊΠΈ ID ΡΠ΅ΠΊΡΡΠ΅Π³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° ΠΊΠ»ΠΈΠ΅Π½ΡΡ:
private static void RunClient(string clientName)
{
var startInfo = new ProcessStartInfo
{
FileName = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!.AppendPath(clientName),
Arguments = Process.GetCurrentProcess().Id.ToString()
};
Process.Start(startInfo);
}Π Π²ΠΎΡ ΠΊΠΎΠ΄ Π΄Π»Ρ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°, ΠΊΠΎΡΠΎΡΡΠΉ ΠΎΡΡΡΠ΅ΡΡΠ²Π»ΡΠ΅Ρ Π·Π°ΠΊΡΡΡΠΈΠ΅ ΡΠ²ΠΎΠ΅Π³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° ΠΏΡΠΈ Π·Π°ΠΊΡΡΡΠΈΠΈ ΡΠΎΠ΄ΠΈΡΠ΅Π»ΡΡΠΊΠΎΠ³ΠΎ ΠΏΡΠΎΡΠ΅ΡΡΠ° Revit:
protected override void OnStartup(StartupEventArgs args)
{
ParseCommandArguments(args.Args);
}
private void ParseCommandArguments(string[] args)
{
var ownerPid = args[0];
var ownerProcess = Process.GetProcessById(int.Parse(ownerPid));
ownerProcess.EnableRaisingEvents = true;
ownerProcess.Exited += (_, _) => Shutdown();
}ΠΡΠΎΠΌΠ΅ ΡΠΎΠ³ΠΎ, Π½Π°ΠΌ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌ ΠΌΠ΅ΡΠΎΠ΄, ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΠΎΡΠ²Π΅ΡΠ°ΡΡ Π·Π° ΡΠ΄Π°Π»Π΅Π½ΠΈΠ΅ Π²ΡΠ±ΡΠ°Π½Π½ΡΡ ΡΠ»Π΅ΠΌΠ΅Π½ΡΠΎΠ² ΠΌΠΎΠ΄Π΅Π»ΠΈ:
public static ICollection<ElementId> DeleteSelectedElements()
{
var transaction = new Transaction(Document);
transaction.Start("Delete elements");
var selectedIds = UiDocument.Selection.GetElementIds();
var deletedIds = Document.Delete(selectedIds);
transaction.Commit();
return deletedIds;
}Π’Π°ΠΊΠΆΠ΅ ΠΎΠ±Π½ΠΎΠ²ΠΈΠΌ ΠΌΠ΅ΡΠΎΠ΄ ListenAndDispatchConnectionsCoreAsync Π΄Π»Ρ ΠΎΠ±ΡΠ°Π±ΠΎΡΠΊΠΈ Π²Ρ ΠΎΠ΄ΡΡΠΈΡ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΠΉ:
private async Task ListenAndDispatchConnectionsCoreAsync()
{
while (_server.IsConnected)
{
try
{
var request = await Request.ReadAsync(_server);
if (request.Type == Request.RequestType.DeleteElements)
{
await ProcessDeleteElementsAsync();
}
}
catch (EndOfStreamException)
{
return; //Pipe disconnected
}
}
}
private async Task ProcessDeleteElementsAsync()
{
try
{
var deletedIds = await Application.AsyncEventHandler.RaiseAsync(_ => RevitApi.DeleteSelectedElements());
await WriteResponseAsync(new DeletionCompletedResponse(deletedIds.Count));
}
catch (Exception exception)
{
await WriteResponseAsync(new RejectedResponse(exception.Message));
}
}Π, Π½Π°ΠΊΠΎΠ½Π΅Ρ, ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π½ΡΠΉ ΠΊΠΎΠ΄ ViewModel:
[RelayCommand]
private async Task DeleteElementsAsync()
{
var request = new DeleteElementsRequest();
await App.ClientDispatcher.WriteRequestAsync(request);
var response = await App.ClientDispatcher.ReadResponseAsync();
if (response.Type == Response.ResponseType.Success)
{
var completedResponse = (DeletionCompletedResponse) response;
MessageBox.Show($"{completedResponse.Changes} elements successfully deleted");
}
else if (response.Type == Response.ResponseType.Rejected)
{
var rejectedResponse = (RejectedResponse) response;
MessageBox.Show($"Deletion failed\n{rejectedResponse.Reason}");
}
}ΠΠ΅ Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½Π° ΠΏΠΎΡΠ»Π΅Π΄Π½ΡΡ Π²Π΅ΡΡΠΈΡ .NET Runtime Π½Π° Π»ΠΎΠΊΠ°Π»ΡΠ½ΠΎΠΉ ΠΌΠ°ΡΠΈΠ½Π΅, Π½Π°ΠΌ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ Π²Π½Π΅ΡΡΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ Π² ΡΡΡΠ°Π½ΠΎΠ²ΡΠΈΠΊ ΠΏΠ»Π°Π³ΠΈΠ½Π°.
ΠΡΠ»ΠΈ Π²Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΠ΅ ΡΠ°Π±Π»ΠΎΠ½Ρ Nice3point.RevitTemplates, ΡΠΎ Π²Π½Π΅ΡΡΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΡ Π½Π΅ ΡΠΎΡΡΠ°Π²ΠΈΡ ΡΡΡΠ΄Π°. Π ΡΠ°Π±Π»ΠΎΠ½Π°Ρ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΡΡΡ Π±ΠΈΠ±Π»ΠΈΠΎΡΠ΅ΠΊΠ° WixSharp, ΠΊΠΎΡΠΎΡΠ°Ρ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΡΠΎΠ·Π΄Π°Π²Π°ΡΡ .msi ΡΠ°ΠΉΠ»Ρ ΠΏΡΡΠΌΠΎ Π½Π° C#.
ΠΠ»Ρ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΡ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΡ
Π΄Π΅ΠΉΡΡΠ²ΠΈΠΉ, ΠΈ ΡΡΡΠ°Π½ΠΎΠ²ΠΊΠΈ .NET Runtime ΡΠΎΠ·Π΄Π°Π΄ΠΈΠΌ CustomAction
public static class RuntimeActions
{
/// <summary>
/// Add-in client .NET version
/// </summary>
private const string DotnetRuntimeVersion = "7";
/// <summary>
/// Direct download link
/// </summary>
private const string DotnetRuntimeUrl = $"https://aka.ms/dotnet/{DotnetRuntimeVersion}.0/windowsdesktop-runtime-win-x64.exe";
/// <summary>
/// Installing the .NET runtime after installing software
/// </summary>
[CustomAction]
public static ActionResult InstallDotnet(Session session)
{
try
{
var isRuntimeInstalled = CheckDotnetInstallation();
if (isRuntimeInstalled) return ActionResult.Success;
var destinationPath = Path.Combine(Path.GetTempPath(), "windowsdesktop-runtime-win-x64.exe");
UpdateStatus(session, "Downloading .NET runtime");
DownloadRuntime(destinationPath);
UpdateStatus(session, "Installing .NET runtime");
var status = InstallRuntime(destinationPath);
var result = status switch
{
0 => ActionResult.Success,
1602 => ActionResult.UserExit,
1618 => ActionResult.Success,
_ => ActionResult.Failure
};
File.Delete(destinationPath);
return result;
}
catch (Exception exception)
{
session.Log("Error downloading and installing DotNet: " + exception.Message);
return ActionResult.Failure;
}
}
private static int InstallRuntime(string destinationPath)
{
var startInfo = new ProcessStartInfo(destinationPath)
{
Arguments = "/q",
UseShellExecute = false
};
var installProcess = Process.Start(startInfo)!;
installProcess.WaitForExit();
return installProcess.ExitCode;
}
private static void DownloadRuntime(string destinationPath)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
using var httpClient = new HttpClient();
var responseBytes = httpClient.GetByteArrayAsync(DotnetRuntimeUrl).Result;
File.WriteAllBytes(destinationPath, responseBytes);
}
private static bool CheckDotnetInstallation()
{
var startInfo = new ProcessStartInfo
{
FileName = "dotnet",
Arguments = "--list-runtimes",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
};
try
{
var process = Process.Start(startInfo)!;
var output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return output.Split('\n')
.Where(line => line.Contains("Microsoft.WindowsDesktop.App"))
.Any(line => line.Contains($"{DotnetRuntimeVersion}."));
}
catch
{
return false;
}
}
private static void UpdateStatus(Session session, string message)
{
var record = new Record(3);
record[2] = message;
session.Message(InstallMessage.ActionStart, record);
}
}ΠΡΠΎΡ ΠΊΠΎΠ΄ ΠΏΡΠΎΠ²Π΅ΡΡΠ΅Ρ, ΡΡΡΠ°Π½ΠΎΠ²Π»Π΅Π½Π° Π»ΠΈ ΡΡΠ΅Π±ΡΠ΅ΠΌΠ°Ρ Π²Π΅ΡΡΠΈΡ .NET Π½Π° Π»ΠΎΠΊΠ°Π»ΡΠ½ΠΎΠΉ ΠΌΠ°ΡΠΈΠ½Π΅, ΠΈ Π΅ΡΠ»ΠΈ Π½Π΅Ρ, ΡΠΎ ΡΠΊΠ°ΡΠΈΠ²Π°Π΅Ρ ΠΈ ΡΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅Ρ Π΅Π΅. ΠΠΎ Π²ΡΠ΅ΠΌΡ ΡΡΡΠ°Π½ΠΎΠ²ΠΊΠΈ ΠΎΠ±Π½ΠΎΠ²Π»ΡΠ΅ΡΡΡ Status ΡΠ΅ΠΊΡΡΠ΅Π³ΠΎ Ρ ΠΎΠ΄Π° Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΡ ΡΠΊΠ°ΡΠΈΠ²Π°Π½ΠΈΡ ΠΈ ΡΠ°ΡΠΏΠ°ΠΊΠΎΠ²ΠΊΠΈ Runtime.
ΠΡΡΠ°Π»ΠΎΡΡ ΠΏΠΎΠ΄ΠΊΠ»ΡΡΠΈΡΡ CustomAction Π² ΠΏΡΠΎΠ΅ΠΊΡ WixSharp, Π΄Π»Ρ ΡΡΠΎΠ³ΠΎ ΠΈΠ½ΠΈΡΠΈΠ°Π»ΠΈΠ·ΠΈΡΡΠ΅ΠΌ ΡΠ²ΠΎΠΉΡΡΠ²ΠΎ Actions:
var project = new Project
{
Name = "Wix Installer",
UI = WUI.WixUI_FeatureTree,
GUID = new Guid("8F2926C8-3C6C-4D12-9E3C-7DF611CD6DDF"),
Actions = new Action[]
{
new ManagedAction(RuntimeActions.InstallDotnet,
Return.check,
When.Before,
Step.InstallFinalize,
Condition.NOT_Installed)
}
};Π Π΄Π°Π½Π½ΠΎΠΉ ΡΡΠ°ΡΡΠ΅ ΠΌΡ ΡΠ°ΡΡΠΌΠΎΡΡΠ΅Π»ΠΈ ΠΊΠ°ΠΊ Named Pipes, ΠΏΡΠ΅ΠΈΠΌΡΡΠ΅ΡΡΠ²Π΅Π½Π½ΠΎ ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΠ΅ Π΄Π»Ρ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ ΡΠ°Π·Π½ΡΠΌΠΈ ΠΏΡΠΎΡΠ΅ΡΡΠ°ΠΌΠΈ, ΠΌΠΎΠ³ΡΡ Π±ΡΡΡ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½Ρ Π² ΡΡΠ΅Π½Π°ΡΠΈΡΡ , Π³Π΄Π΅ ΡΡΠ΅Π±ΡΠ΅ΡΡΡ ΠΎΠ±ΠΌΠ΅Π½ Π΄Π°Π½Π½ΡΠΌΠΈ ΠΌΠ΅ΠΆΠ΄Ρ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡΠΌΠΈ Π½Π° ΡΠ°Π·Π½ΡΡ Π²Π΅ΡΡΠΈΡΡ .NET. ΠΠΌΠ΅Ρ Π΄Π΅Π»ΠΎ Ρ ΠΊΠΎΠ΄ΠΎΠΌ, ΠΊΠΎΡΠΎΡΡΠΉ Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°ΡΡ Π² Π½Π΅ΡΠΊΠΎΠ»ΡΠΊΠΈΡ Π²Π΅ΡΡΠΈΡΡ , Π²ΡΠ²Π΅ΡΠ΅Π½Π½Π°Ρ ΡΡΡΠ°ΡΠ΅Π³ΠΈΡ ΠΌΠ΅ΠΆΠΏΡΠΎΡΠ΅ΡΡΠ½ΠΎΠ³ΠΎ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ (Inter-Process Communication, IPC) ΠΌΠΎΠΆΠ΅Ρ Π±ΡΡΡ ΠΏΠΎΠ»Π΅Π·Π½ΠΎΠΉ ΠΈ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠΈΠ²Π°ΡΡ ΠΊΠ»ΡΡΠ΅Π²ΡΠ΅ ΠΏΡΠ΅ΠΈΠΌΡΡΠ΅ΡΡΠ²Π°, ΡΠ°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ:
- Π Π΅ΡΠ΅Π½ΠΈΠ΅ ΠΊΠΎΠ½ΡΠ»ΠΈΠΊΡΠΎΠ² Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠ΅ΠΉ
- Π£Π»ΡΡΡΠ΅Π½ΠΈΠ΅ ΠΏΡΠΎΠΈΠ·Π²ΠΎΠ΄ΠΈΡΠ΅Π»ΡΠ½ΠΎΡΡΠΈ
- Π€ΡΠ½ΠΊΡΠΈΠΎΠ½Π°Π»ΡΠ½Π°Ρ Π³ΠΈΠ±ΠΊΠΎΡΡΡ
ΠΡ ΠΎΠ±ΡΡΠ΄ΠΈΠ»ΠΈ ΠΏΡΠΎΡΠ΅ΡΡ ΡΠΎΠ·Π΄Π°Π½ΠΈΡ ΡΠ΅ΡΠ²Π΅ΡΠ° ΠΈ ΠΊΠ»ΠΈΠ΅Π½ΡΠ°, ΠΊΠΎΡΠΎΡΡΠ΅ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΡΡΡ Π΄ΡΡΠ³ Ρ Π΄ΡΡΠ³ΠΎΠΌ ΡΠ΅ΡΠ΅Π· Π·Π°ΡΠ°Π½Π΅Π΅ ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΡΠΉ ΠΏΡΠΎΡΠΎΠΊΠΎΠ», Π° ΡΠ°ΠΊΠΆΠ΅ ΡΠ°Π·Π»ΠΈΡΠ½ΡΠ΅ ΡΠΏΠΎΡΠΎΠ±Ρ ΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΡΠΎΠ΅Π΄ΠΈΠ½Π΅Π½ΠΈΡΠΌΠΈ.
Π Π°ΡΡΠΌΠΎΡΡΠ΅Π»ΠΈ ΠΏΡΠΈΠΌΠ΅Ρ ΠΎΡΠ²Π΅ΡΠΎΠ² ΡΠ΅ΡΠ²Π΅ΡΠ° ΠΈ Π΄Π΅ΠΌΠΎΠ½ΡΡΡΠ°ΡΠΈΡ ΡΠ°Π±ΠΎΡΡ ΠΎΠ±Π΅ΠΈΡ ΡΡΠΎΡΠΎΠ½ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ.
ΠΠ°ΠΊΠΎΠ½Π΅Ρ, ΠΌΡ ΠΏΠΎΠ΄ΡΠ΅ΡΠΊΠ½ΡΠ»ΠΈ ΠΊΠ°ΠΊ Named Pipes ΠΈΡΠΏΠΎΠ»ΡΠ·ΡΡΡΡΡ Π² ΡΠ°Π·ΡΠ°Π±ΠΎΡΠΊΠ΅ ΠΏΠ»Π°Π³ΠΈΠ½Π° Π΄Π»Ρ Revit Π΄Π»Ρ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠ΅Π½ΠΈΡ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ ΠΌΠ΅ΠΆΠ΄Ρ Π±Π΅ΠΊΠ΅Π½Π΄ΠΎΠΌ, ΡΠ°Π±ΠΎΡΠ°ΡΡΠΈΠΌ Π½Π° ΡΡΡΠ°ΡΠ΅Π²ΡΠ΅ΠΉ ΠΏΠ»Π°ΡΡΠΎΡΠΌΠ΅ .NET 4.8, ΠΈ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»ΡΡΠΊΠΈΠΌ ΠΈΠ½ΡΠ΅ΡΡΠ΅ΠΉΡΠΎΠΌ, ΡΠ°Π±ΠΎΡΠ°ΡΡΠΈΠΌ Π½Π° Π±ΠΎΠ»Π΅Π΅ Π½ΠΎΠ²ΠΎΠΉ Π²Π΅ΡΡΠΈΠΈ .NET 7.
ΠΠ΅ΠΌΠΎΠ½ΡΡΡΠ°ΡΠΈΠΎΠ½Π½ΡΠΉ ΠΊΠΎΠ΄ Π΄Π»Ρ ΠΊΠ°ΠΆΠ΄ΠΎΠΉ ΡΠ°ΡΡΠΈ ΡΡΠΎΠΉ ΡΡΠ°ΡΡΠΈ Π΄ΠΎΡΡΡΠΏΠ΅Π½ Π½Π° GitHub.
Π ΠΎΠΏΡΠ΅Π΄Π΅Π»Π΅Π½Π½ΡΡ ΡΠ»ΡΡΠ°ΡΡ ΡΠ°Π·Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΏΡΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Π½Π° ΠΎΡΠ΄Π΅Π»ΡΠ½ΡΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΡ ΠΌΠΎΠΆΠ΅Ρ Π½Π΅ ΡΠΎΠ»ΡΠΊΠΎ ΡΠΌΠ΅Π½ΡΡΠΈΡΡ Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡΠΈ Π² ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠ΅, Π½ΠΎ ΠΈ ΡΡΠΊΠΎΡΠΈΡΡ Π΅Π³ΠΎ Π²ΡΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅. ΠΠΎ Π΄Π°Π²Π°ΠΉΡΠ΅ Π½Π΅ Π·Π°Π±ΡΠ²Π°ΡΡ, ΡΡΠΎ Π²ΡΠ±ΠΎΡ ΠΏΠΎΠ΄Ρ ΠΎΠ΄Π° ΡΡΠ΅Π±ΡΠ΅Ρ Π°Π½Π°Π»ΠΈΠ·Π° ΠΈ Π΄ΠΎΠ»ΠΆΠ΅Π½ ΠΎΡΠ½ΠΎΠ²ΡΠ²Π°ΡΡΡΡ Π½Π° ΡΠ΅Π°Π»ΡΠ½ΡΡ ΡΡΠ΅Π±ΠΎΠ²Π°Π½ΠΈΡΡ ΠΈ ΠΎΠ³ΡΠ°Π½ΠΈΡΠ΅Π½ΠΈΡΡ Π²Π°ΡΠ΅Π³ΠΎ ΠΏΡΠΎΠ΅ΠΊΡΠ°.
ΠΡ Π½Π°Π΄Π΅Π΅ΠΌΡΡ, ΡΡΠΎ ΡΡΠ° ΡΡΠ°ΡΡΡ ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ Π²Π°ΠΌ Π½Π°ΠΉΡΠΈ ΠΎΠΏΡΠΈΠΌΠ°Π»ΡΠ½ΠΎΠ΅ ΡΠ΅ΡΠ΅Π½ΠΈΠ΅ Π΄Π»Ρ Π²Π°ΡΠΈΡ ΡΡΠ΅Π½Π°ΡΠΈΠ΅Π² ΠΌΠ΅ΠΆΠΏΡΠΎΡΠ΅ΡΡΠ½ΠΎΠ³ΠΎ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡΠ²ΠΈΡ ΠΈ Π΄Π°ΡΡ ΠΏΠΎΠ½ΠΈΠΌΠ°Π½ΠΈΠ΅, ΠΊΠ°ΠΊ ΠΏΡΠΈΠΌΠ΅Π½ΡΡΡ ΠΏΠΎΠ΄Ρ ΠΎΠ΄Ρ IPC Π½Π° ΠΏΡΠ°ΠΊΡΠΈΠΊΠ΅.