v3.5.2025.1001
大石头 authored at 2025-10-02 01:20:22
6.13 KiB
NewLife.Remoting
# ClientBase ʹÓÃ˵Ã÷ ## ÊÊÓ÷¶Î§ - ÔËÐÐʱ£º.NET Framework 4.5+ / .NET Standard 2.0+ / .NET 5~9 - ÃüÃû¿Õ¼ä£º`NewLife.Remoting.Clients` - ÀàÐÍ£º`ClientBase`£¨³éÏó»ùÀࣩ ## ¸ÅÊö - `ClientBase` ÊÇÓ¦Óòã¿Í»§¶Ë»ùÀ࣬·â×°µÇ¼¡¢ÐÄÌø¡¢ÏÂÐÐ֪ͨ¡¢ÃüÁîÖ´ÐС¢Ê¼þÉϱ¨ÓëÔÚÏßÉý¼¶¡£ - ͬʱ֧³Ö»ùÓÚ `ApiClient`£¨TCP/UDP£©Óë `ApiHttpClient`£¨HTTP/HTTPS + WebSocket£©µÄͨÐÅÄ£ÐÍ¡£ - ÄÚÖÃ×Ô¶¯Öصǡ¢Ê±¼äУ׼Óëʧ°ÜÖØÊÔ¶ÓÁУ»²»¸Ä±ä¶ÔÍâ API µÄͬʱ¼ò»¯µäÐÍÒµÎñ½ÓÈë¡£ ## ͨÐÅÄ£ÐÍ - RPC£º`ApiClient` ³¤Á¬½ÓÖ±Á¬·þÎñ¶Ë£¬µÇ¼ºó·þÎñ¶Ë¿ÉÖ±½ÓÏ·¢ÃüÁî¡£ - HTTP£º`ApiHttpClient` µ÷Óà REST ½Ó¿Ú£¬Ö§³Öͨ¹ý WebSocket ½ÓÊÕÏÂÐÐ֪ͨ¡£ - OAuth£ºÔÚ HTTP Ä£ÐÍÉϵþ¼Ó OAuth µÇ¼£¬»ñµÃÁîÅÆ²¢ËæÃ¿´ÎÇëÇóЯ´ø¡£ ## ¿ìËÙ¿ªÊ¼ 1. ¶¨Òå¿Í»§¶ËÅÉÉúÀࣨ×îСʵÏÖ£© ```csharp using NewLife.Remoting; using NewLife.Remoting.Clients; // ÒÀ¾Ý·þÎñ¶Ë½Ó¿Úǰ׺£¬×Ô¶¨Ò嶯×÷·¾¶Ó³Éä public sealed class MyClient : ClientBase { public MyClient() : base() { InitFeatures(); } public MyClient(IClientSetting setting) : base(setting) { InitFeatures(); } private void InitFeatures() { // ĬÈÏÒÑÆôÓà Login/Logout/Ping£¬¿É°´Ðè×·¼Ó Features |= Features.Notify | Features.Upgrade | Features.CommandReply | Features.PostEvent; // ¿É¸²¸Ç¶¯×÷ǰ׺£»Óë·þÎñ¶Ë¿ØÖÆÆ÷/·Óɱ£³ÖÒ»Ö SetActions("Device/"); } } ``` 2. ÅäÖÃÓëʹÓà ```csharp using NewLife.Security; using NewLife.Log; using NewLife.Remoting.Models; var setting = new MySetting // Òà¿ÉʵÏÖ IClientSetting ²¢³Ö¾Ã»¯±£´æ { Server = "https://api.example.com", Code = "dev-001", Secret = "secret" }; var client = new MyClient(setting) { Log = XTrace.Log, // ¿ÉÑ¡£º×¢ÈëÈÕÖ¾ PasswordProvider = new SaltPasswordProvider{ Algorithm = "md5", SaltTime = 60 } // ¿ÉÑ¡£º±£»¤ÃÜÔ¿´«Êä }; client.OnLogined += (s,e) => XTrace.WriteLine("Logined: {0}", e.Response?.Token); client.Received += (s,e) => XTrace.WriteLine("Command: {0}", e.Model?.Command); // ·½°¸A£º×Ô¶¯ÖØÊԵǼ client.Open(); // ·½°¸B£ºÏÔʽµÇ¼ await client.Login("manual"); // ͳһԶ³Ìµ÷Óã¨×Ô¶¯ÅÐ¶Ï HTTP GET/POST¡¢×Ô¶¯ÖصÇÒ»´Î£© var ping = await client.InvokeAsync<IPingResponse>("Device/Ping", new PingRequest()); // ×¢Ïú£¨»ò using/Dispose£©¡£Dispose ÄÚ²¿»á³¢ÊÔ Logout await client.Logout("bye"); ``` ## ³£ÓÃÊôÐÔ/ÅäÖÃÏî - Á¬½ÓÓë¼øÈ¨ - `Server`£º·þÎñ¶ËµØÖ·£¬Ö§³Ö¶àµØÖ·¶ººÅ·Ö¸ô£¨¿Í»§¶Ë¸ºÔؾùºâ£©¡£ - `Code`/`Secret`£º¿Í»§¶Ë±àÂëÓëÃÜÔ¿£»Ö§³Ö×Ô¶¯×¢²áʱ·þÎñ¶ËÏ·¢ÐÂÖµ²¢±£´æµ½ `IClientSetting`¡£ - `PasswordProvider`£º¿ÉÑ¡£¬ÓÃÓÚ¶Ô `Secret` ×ö¹þÏ£±£»¤´«Ê䣨½¨Òé `SaltPasswordProvider`£©¡£ - µ÷ÓÃÓëÐòÁл¯ - `Timeout`£ºµ÷Óó¬Ê±Ê±¼ä£¨ºÁÃ룩£¬Ä¬ÈÏ 15000¡£ - `JsonHost`£ºÐòÁл¯ÌṩÕߣ¬Ä¬ÈÏ `JsonHelper.Default`¡£ - `ServiceProvider`£ºÒÀÀµ×¢ÈëÈÝÆ÷£¬×Ô¶¯×¢²á/½âÎöµÇ¼¡¢ÐÄÌøµÈÄ£ÐÍ¡£ - ¹¦ÄÜ¿ª¹Ø - `Features`£º`Login`/`Logout`/`Ping`/`Upgrade`/`Notify`/`CommandReply`/`PostEvent` ¿É°´ÐèÆôÓᣠ- `Actions`£º¸÷¹¦ÄܶÔÓ¦µÄ¶¯×÷·¾¶×ֵ䣬ĬÈÏǰ׺ `Device/`£¬¿ÉÔÚ `SetActions` Öе÷Õû¡£ - Õï¶Ï - `Log`£ºÈÕÖ¾£»`Tracer`£ºÁ´Â·×·×Ù¡£ - `Delay`£º×î½üÒ»´ÎÍù·µÑÓ³Ù£¨ºÁÃ룩£»`GetNow()`£º°´·þÎñ¶ËУ׼ºóµÄµ±Ç°Ê±¼ä£¨±¾µØÊ±Çø£©¡£ ## ÉúÃüÖÜÆÚ - `Open()`£º¶¨Ê±³¢ÊԵǼ£¬ÍøÂç¾ÍÐ÷ºó×Ô¶¯µÇ¼²¢Æô¶¯ÐÄÌø/Éý¼¶¶¨Ê±Æ÷¡£ - `Login(source?)`£ºµÇ¼³É¹¦ºó×Ô¶¯ÉèÖà Token¡¢ÐÞÕýʱ¼äÆ«ÒÆ²¢´¥·¢ `OnLogined`¡£ - `Logout(reason?)`£ºµ÷Ó÷þÎñ¶Ë×¢Ïú£¬Í£Ö¹¶¨Ê±Æ÷²¢ÖØÖÃ״̬¡£ - `Dispose()`£ºÄÚ²¿³¢ÊÔ×¢Ïú²¢ÊÍ·Å×ÊÔ´¡£ ## Ô¶³Ìµ÷Óà - `InvokeAsync<TResult>(action, args)`£ºÍ³Ò»µ÷ÓÃÈë¿Ú¡£ - HTTP ×Ô¶¯Åж¨ GET/POST£º²ÎÊýΪ¿Õ/»ù´¡ÀàÐÍ¡¢»ò `action` ÒÔ `Get` ¿ªÍ·/°üº¬ `/get` ʱʹÓà GET¡£ - Èô·µ»Ø 401£¨Unauthorized£©£¬°´Ðè×Ô¶¯ÖصÇÒ»´ÎºóÖØÊÔµ±Ç°ÇëÇó¡£ - `GetAsync<TResult>(action, args)`£ºHTTP רÓà GET£¨¿ÉÖ±½Óµ÷Óã©¡£ - `Invoke<TResult>(...)`£ºÍ¬²½·â×°¡£ ## ÐÄÌøÓëʱ¼äУ׼ - `Ping()`£ºÉϱ¨ÔËÐÐ״̬ÓëÐÔÄÜ¡£Ê§°ÜÈë¶ÓÁУ¨×î¶à `MaxFails`£©µÈ´ýºóÐøÖØÊÔ£»·þÎñ¶Ë¿Éͨ¹ýÏìÓ¦µ÷ÕûÐÄÌøÖÜÆÚ¡£ - `FixTime()`£ºÄÚ²¿¼ÆËãÍù·µÑÓ³Ù `Delay` ºÍʱ¼äÆ«ÒÆ `_span`£¬`GetNow()` ·µ»Ø¶ÔÆëºóµÄ±¾µØÊ±ÇøÊ±¼ä¡£ ## ÏÂÐÐ֪ͨÓëÃüÁî - ÆôÓà `Features.Notify` ºó£¬HTTP ģʽ×Ô¶¯Î¬»¤ WebSocket ³¤Á¬½ÓÒÔ½ÓÊÕÏÂÐÐ֪ͨ¡£ - ÃüÁî´¦Àí - ʼþ£º`Received`£¨ÊÕµ½ÃüÁîʱ´¥·¢£©¡£ - È¥ÖØ£ºÏàͬ `Id` µÄÃüÁîÖ»Ö´ÐÐÒ»´Î¡£ - ¹ýÆÚ/¶¨Ê±£º°´ `Expire`/`StartTime` ×Ô¶¯¶ªÆú»òÑÓ³ÙÖ´ÐУ»ÑÓ³ÙÖ´ÐÐÔÚºǫ́ÅŶӡ£ - Ö´ÐÐÍê³É¿Éͨ¹ý `CommandReply` Éϱ¨£¨ÐèÆôÓà `Features.CommandReply`£©¡£ ## ʼþÉϱ¨ - `WriteEvent(type, name, remark)`£ºÐ´Èëʼþ¶ÓÁв¢Óɶ¨Ê±Æ÷ÅúÁ¿Éϱ¨ `PostEvents`¡£ - ʧ°Üʼþ½øÈë±¾µØÊ§°Ü¶ÓÁУ¬´ýÍøÂç»Ö¸´ºóÖØÊÔ¡£ ## ÔÚÏßÉý¼¶ - ÆôÓà `Features.Upgrade` ºó£¬µ÷Óà `Upgrade(channel?)`£º²éѯ¸üС¢ÏÂÔØ¡¢¹þϣУÑé¡¢½âѹÓ븲¸Ç£¬¿ÉѡִÐÐÔ¤°²×°½Å±¾/Ö´ÐÐÆ÷£»Ç¿ÖƸüкó¿É `Restart()`¡£ - `BuildUrl(relativeUrl)`£ºÔÚ HTTP ģʽÏ£¬½«Ïà¶ÔµØÖ·×ªÎª»ùÓÚµ±Ç°·þÎñµØÖ·µÄ¾ø¶ÔµØÖ·¡£ ## À©Õ¹µã£¨³£ÓÃÖØÐ´£© - `SetActions(prefix)`£ºÍ³Ò»¶¨Ò嶯×÷·¾¶Ç°×ºÓëÓ³Éä¡£ - `CreateHttp(urls)`/`CreateRpc(urls)`£º×Ô¶¨Òåµ×²ã¿Í»§¶ËÅäÖã¨Èç Header¡¢ÖØÊÔ²ßÂÔ¡¢SocketLog µÈ£©¡£ - `BuildLoginRequest()`/`FillLoginRequest(req)`£º²¹³ä°æ±¾¡¢±àÒëʱ¼ä¡¢ÍøÂçÐÅÏ¢¡¢É豸Ψһ±êʶ¡¢Ê±¼ä´ÁµÈ¡£ - `BuildPingRequest()`/`FillPingRequest(req)`£º·á¸»ÐÄÌøÉϱ¨ÄÚÈÝ¡£ - `UpgradeAsync(channel)`£º×Ô¶¨ÒåÉý¼¶ÐÅÏ¢»ñÈ¡¡£ - `OnPing(state)`£ºÐÄÌøÖÜÆÚÄÚ×Ô¶¨ÒåÐÐΪ£¨ÀýÈç¶îÍâѲ¼ì£©¡£ ## ³£¼ûÎÊÌâ - ÈçºÎÇø·Ö HTTP GET/POST£¿ - ĬÈϹæÔò£º²ÎÊýΪ¿Õ/»ù´¡ÀàÐÍ£¬»ò¶¯×÷ÃûÒÔ `Get` ¿ªÍ·/°üº¬ `/get`£¨ºöÂÔ´óСд£©¡ú GET£»·ñÔò POST¡£ - Ϊʲô»á×Ô¶¯Öصǣ¿ - µ±µ÷Ó÷µ»Ø 401£¨Unauthorized£©Ê±£¬Èç¹ûÆôÓÃÁË `Login` ÄÜÁ¦£¬½«Çл»µ½´ýµÇ¼²¢Ö´ÐÐÒ»´ÎµÇ¼£¬È»ºóÖØÊÔÔ­ÇëÇó¡£ - ¶àµØÖ·ÈçºÎ¸ºÔؾùºâ£¿ - `Server` Ö§³Ö¶ººÅ·Ö¸ô¶à¸öµØÖ·£»ÔËÐÐʱ±ä¸üµØÖ·»á×Ô¶¯Çл»¡£ - ÈçºÎ»ñÈ¡Óë·þÎñ¶ËÒ»Öµĵ±Ç°Ê±¼ä£¿ - ʹÓà `GetNow()`£¬Æä»ùÓÚ×î½üÒ»´ÎÐÄÌø/µÇ¼µÄʱ¼ä²î½øÐб¾µØÊ±¼äУ׼¡£ ## ÍêÕûʾÀý£¨´øÃüÁî»ØÖ´£© ```csharp var client = new MyClient(new MySetting { Server = "https://api.example.com", Code = "dev-001", Secret = "secret" }) { Log = XTrace.Log }; client.Received += async (s, e) => { if (e.Model?.Command == "Reboot") { // TODO: Ö´ÐÐÖØÆô await client.CommandReply(new CommandReplyModel { Id = e.Model.Id, Status = CommandStatus.³É¹¦, Data = "ÒÑÖ´ÐÐÖØÆô" }); } }; client.Open(); ``` ## ×¢ÒâÊÂÏî - `ClientBase` Ϊ³éÏóÀàÐÍ£¬Ç붨ÒåÅÉÉúÀàºóʹÓᣠ- ¸ß²¢·¢ÏµÄ״̬À©Õ¹Çë×ÔÐб£Ö¤Ḭ̈߳²È«¡£ - ÈÕÖ¾Óë×·×Ù£º½¨ÒéÔÚÉú²ú¿ªÆô±ØÒªµÄ Info ¼¶±ðÈÕÖ¾£¬Debug ¼¶±ð½öÓÃÓÚ¶¨Î»ÎÊÌâ¡£ ## ±ä¸ü¼Ç¼ - ÎĵµÊ×´ÎÌí¼Ó£º½éÉÜ»ùÓÚ `ClientBase` µÄµäÐÍʹÓ÷½Ê½Óë×î¼Ñʵ¼ù¡£