Repository: dotnetcore/BootstrapBlazor (2025-08-05T02:29:22Z)

Issue:
feat(IBrowserFingerService): add GetClientHubIdAsync method
### Is there an existing issue for this?

- [x] I have searched the existing issues

### Is your feature request related to a problem? Please describe the problem.

add GetClientHubIdAsync method

### Describe the solution you'd like

_No response_

### Additional context

_No response_


Discussion:
@ArgoZhang Thank you for contacting us. We will give feedback later.



Patch:
diff --git a/src/BootstrapBlazor.Server/Components/Samples/BrowserFingers.razor b/src/BootstrapBlazor.Server/Components/Samples/BrowserFingers.razor
index 007acbb2e10..083a585e76a 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/BrowserFingers.razor
+++ b/src/BootstrapBlazor.Server/Components/Samples/BrowserFingers.razor
@@ -12,7 +12,12 @@ private async Task GetFingerCodeAsync()
 }</Pre>
     <BootstrapInputGroup>
         <BootstrapInputGroupLabel DisplayText="Browser-Finger"></BootstrapInputGroupLabel>
-        <BootstrapInput @bind-Value="@_code" />
+        <BootstrapInput Value="@_code" Readonly="true" />
+    </BootstrapInputGroup>
+
+    <BootstrapInputGroup class="mt-3">
+        <BootstrapInputGroupLabel DisplayText="ClientHubId"></BootstrapInputGroupLabel>
+        <BootstrapInput Value="@_clientHubId" Readonly="true" />
     </BootstrapInputGroup>
 </DemoBlock>
 
diff --git a/src/BootstrapBlazor.Server/Components/Samples/BrowserFingers.razor.cs b/src/BootstrapBlazor.Server/Components/Samples/BrowserFingers.razor.cs
index 6641b3f46d9..e0a75a8f3a0 100644
--- a/src/BootstrapBlazor.Server/Components/Samples/BrowserFingers.razor.cs
+++ b/src/BootstrapBlazor.Server/Components/Samples/BrowserFingers.razor.cs
@@ -15,6 +15,7 @@ public partial class BrowserFingers
     private IBrowserFingerService? BrowserFingerService { get; set; }
 
     private string? _code;
+    private string? _clientHubId;
 
     /// <summary>
     /// <inheritdoc/>
@@ -25,10 +26,13 @@ protected override async Task OnInitializedAsync()
         await base.OnInitializedAsync();
 
         _code = await GetFingerCodeAsync();
+        _clientHubId = await GetClientHubIdAsync();
     }
 
     private Task<string?> GetFingerCodeAsync() => BrowserFingerService.GetFingerCodeAsync();
 
+    private Task<string?> GetClientHubIdAsync() => BrowserFingerService.GetClientHubIdAsync();
+
     private MethodItem[] GetMethods() =>
     [
         new()
@@ -37,6 +41,13 @@ private MethodItem[] GetMethods() =>
             Description = Localizer["GetFingerCodeAsync"],
             Parameters = " — ",
             ReturnValue = "Task<string?>"
+        },
+        new()
+        {
+            Name = "GetClientHubIdAsync",
+            Description = Localizer["GetClientHubIdAsync"],
+            Parameters = " — ",
+            ReturnValue = "Task<string?>"
         }
     ];
 }
diff --git a/src/BootstrapBlazor.Server/Locales/en-US.json b/src/BootstrapBlazor.Server/Locales/en-US.json
index 6ed2b91ae0e..6ff433dc2aa 100644
--- a/src/BootstrapBlazor.Server/Locales/en-US.json
+++ b/src/BootstrapBlazor.Server/Locales/en-US.json
@@ -6685,7 +6685,8 @@
   "BootstrapBlazor.Server.Components.Samples.BrowserFingers": {
     "BrowserFingerTitle": "Browser fingerprint",
     "BrowserFingerIntro": "Obtain the client browser fingerprint by calling the <code>IBrowserFingerService</code> service instance method <code>GetFingerCodeAsync</code>. The fingerprint is consistent in privacy mode",
-    "GetFingerCodeAsync": "Method for obtaining fingerprints"
+    "GetFingerCodeAsync": "Method for obtaining fingerprints",
+    "GetClientHubIdAsync": "Method for obtaining client hub Id"
   },
   "BootstrapBlazor.Server.Components.Samples.SvgEditors": {
     "SvgEditorTitle": "SvgEditor",
diff --git a/src/BootstrapBlazor.Server/Locales/zh-CN.json b/src/BootstrapBlazor.Server/Locales/zh-CN.json
index aa6be40dab3..24b995075c2 100644
--- a/src/BootstrapBlazor.Server/Locales/zh-CN.json
+++ b/src/BootstrapBlazor.Server/Locales/zh-CN.json
@@ -6685,7 +6685,8 @@
   "BootstrapBlazor.Server.Components.Samples.BrowserFingers": {
     "BrowserFingerTitle": "浏览器指纹",
     "BrowserFingerIntro": "通过调用 <code>IBrowserFingerService</code> 服务实例方法 <code>GetFingerCodeAsync</code> 获得客户端浏览器指纹，隐私模式下指纹是一致的",
-    "GetFingerCodeAsync": "获得指纹方法"
+    "GetFingerCodeAsync": "获得指纹方法",
+    "GetClientHubIdAsync": "获得客户端连接 Id 方法"
   },
   "BootstrapBlazor.Server.Components.Samples.SvgEditors": {
     "SvgEditorTitle": "Svg 编辑器",
diff --git a/src/BootstrapBlazor/Services/DefaultBrowserFingerService.cs b/src/BootstrapBlazor/Services/DefaultBrowserFingerService.cs
index b99da81f736..e04288faed8 100644
--- a/src/BootstrapBlazor/Services/DefaultBrowserFingerService.cs
+++ b/src/BootstrapBlazor/Services/DefaultBrowserFingerService.cs
@@ -13,12 +13,15 @@ class DefaultBrowserFingerService(IJSRuntime jSRuntime) : IBrowserFingerService
     [NotNull]
     private JSModule? _module = null;
 
-    /// <summary>
-    /// 获取剪切板数据方法
-    /// </summary>
     public async Task<string?> GetFingerCodeAsync(CancellationToken token = default)
     {
         _module ??= await jSRuntime.LoadUtility();
         return await _module.InvokeAsync<string?>("getFingerCode", token);
     }
+
+    public async Task<string?> GetClientHubIdAsync(CancellationToken token = default)
+    {
+        _module ??= await jSRuntime.LoadUtility();
+        return await _module.InvokeAsync<string?>("getClientHubId", token);
+    }
 }
diff --git a/src/BootstrapBlazor/Services/IBrowserFingerService.cs b/src/BootstrapBlazor/Services/IBrowserFingerService.cs
index 6c461220b08..05c218cbf3e 100644
--- a/src/BootstrapBlazor/Services/IBrowserFingerService.cs
+++ b/src/BootstrapBlazor/Services/IBrowserFingerService.cs
@@ -15,4 +15,11 @@ public interface IBrowserFingerService
     /// </summary>
     /// <returns></returns>
     Task<string?> GetFingerCodeAsync(CancellationToken token = default);
+
+    /// <summary>
+    /// 获得当前连接的客户端 ID 由 BootstrapBlazor 组件框架提供
+    /// </summary>
+    /// <param name="token"></param>
+    /// <returns></returns>
+    Task<string?> GetClientHubIdAsync(CancellationToken token = default);
 }
diff --git a/src/BootstrapBlazor/wwwroot/modules/client.js b/src/BootstrapBlazor/wwwroot/modules/client.js
index a608d7b9090..8a6a06eb866 100644
--- a/src/BootstrapBlazor/wwwroot/modules/client.js
+++ b/src/BootstrapBlazor/wwwroot/modules/client.js
@@ -24,6 +24,6 @@ export async function getClientInfo(url) {
     if (result) {
         data.ip = result.Ip;
     }
-    data.id = localStorage.getItem('bb_hub_connection_id') ?? result.Id;
+    data.id = localStorage.getItem('bb_hub_connection_id') || result.Id;
     return data;
 }
diff --git a/src/BootstrapBlazor/wwwroot/modules/utility.js b/src/BootstrapBlazor/wwwroot/modules/utility.js
index 0d97300e834..8cc314048fe 100644
--- a/src/BootstrapBlazor/wwwroot/modules/utility.js
+++ b/src/BootstrapBlazor/wwwroot/modules/utility.js
@@ -919,6 +919,10 @@ export function getNetworkInfo() {
     return null;
 }
 
+export function getClientHubId() {
+    return localStorage.getItem('bb_hub_connection_id');
+}
+
 export {
     autoAdd,
     autoRemove,


Test patch:
diff --git a/test/UnitTest/Services/BrowserFingerServiceTest.cs b/test/UnitTest/Services/BrowserFingerServiceTest.cs
index 7d28958c8ac..773d1aca131 100644
--- a/test/UnitTest/Services/BrowserFingerServiceTest.cs
+++ b/test/UnitTest/Services/BrowserFingerServiceTest.cs
@@ -15,4 +15,13 @@ public async Task GetFingerCodeAsync_Ok()
         var code = await service.GetFingerCodeAsync();
         Assert.Equal("9527", code);
     }
+
+    [Fact]
+    public async Task GetClientHubIdAsync_Ok()
+    {
+        Context.JSInterop.Setup<string?>("getClientHubId").SetResult("9528");
+        var service = Context.Services.GetRequiredService<IBrowserFingerService>();
+        var code = await service.GetClientHubIdAsync();
+        Assert.Equal("9528", code);
+    }
 }