v3.5.2025.1001
# 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` µÄµäÐÍʹÓ÷½Ê½Óë×î¼Ñʵ¼ù¡£
|