From 2b7112653c342a77dbd45f7fd2d5bfdce180c324 Mon Sep 17 00:00:00 2001 From: Argo Date: Tue, 24 Aug 2021 10:12:14 +0000 Subject: [PATCH] =?UTF-8?q?!1754=20feat(#I4720Q):=20=20add=20location=20se?= =?UTF-8?q?rvices=20*=20chore:=20bump=20version=20to=205.7.4=20*=20doc:=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=AE=9A=E4=B9=89=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=96=87=E6=A1=A3=20*=20doc:=20=E5=A2=9E=E5=8A=A0=20Locator=20?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=20*=20refactor:=20=E8=B0=83=E6=95=B4=20IPLoc?= =?UTF-8?q?atorOption=20=E5=86=85=E9=83=A8=E5=8F=82=E6=95=B0=20*=20refacto?= =?UTF-8?q?r:=20=20=E7=A7=BB=E9=99=A4=20IPLocator=20=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E6=B3=A8=E5=85=A5=E6=9B=B4=E6=94=B9=E5=88=B0=20BootstrapBlazor?= =?UTF-8?q?=20*=20refactor:=20=E6=97=A5=E5=BF=97=E5=A2=9E=E5=8A=A0=20IP=20?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=20*=20chore:=20=E7=A7=BB=E5=8A=A8=E6=96=87?= =?UTF-8?q?=E4=BB=B6=20*=20doc:=20=E5=A2=9E=E5=8A=A0=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E6=B3=A8=E6=84=8F=E4=BA=8B=E9=A1=B9=20*=20feat:=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=9C=AC=E5=9C=B0=E8=BF=9E=E6=8E=A5=E8=A7=A3=E6=9E=90?= =?UTF-8?q?=20*=20feat:=20=E6=A0=B9=E6=8D=AE=E6=9C=80=E6=96=B0=E7=99=BE?= =?UTF-8?q?=E5=BA=A6=E6=8E=A5=E5=8F=A3=E6=9B=B4=E6=96=B0=E7=B1=BB=E7=BB=93?= =?UTF-8?q?=E6=9E=84=20*=20chore:=20=E5=A2=9E=E5=8A=A0=E7=BC=96=E7=A0=81?= =?UTF-8?q?=E6=94=AF=E6=8C=81=20*=20doc:=20=E5=A2=9E=E5=8A=A0=20Locator=20?= =?UTF-8?q?=E7=A4=BA=E4=BE=8B=20*=20feat:=20=E5=A2=9E=E5=8A=A0=20Locator?= =?UTF-8?q?=20=E9=85=8D=E7=BD=AE=E5=9B=9E=E8=B0=83=E5=A7=94=E6=89=98=20*?= =?UTF-8?q?=20refactor:=20=E9=87=8D=E6=9E=84=E4=BB=A3=E7=A0=81=E6=B6=88?= =?UTF-8?q?=E9=99=A4=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF=20*=20chore:=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20Http=20=E5=8C=85=E4=BE=9D=E8=B5=96=20*=20f?= =?UTF-8?q?eat:=20=E5=A2=9E=E5=8A=A0=E6=8E=A5=E5=8F=A3=E5=AE=9E=E7=8E=B0?= =?UTF-8?q?=E7=B1=BB=20*=20feat:=20=E5=A2=9E=E5=8A=A0=20IPLocator=20?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E6=B3=A8=E5=85=A5=20*=20feat:=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20AddIPLocator=20=E6=9C=8D=E5=8A=A1=E6=B3=A8=E5=85=A5?= =?UTF-8?q?=E4=BB=A3=E7=A0=81=20*=20feat:=20=E5=A2=9E=E5=8A=A0=20StringExt?= =?UTF-8?q?ensions=20=E6=89=A9=E5=B1=95=E6=96=B9=E6=B3=95=20*=20feat:=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20IPLocator=20=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E5=AE=9A=E4=B9=89=20*=20refactor:=20=E6=9B=B4?= =?UTF-8?q?=E6=94=B9=E6=97=A5=E5=BF=97=20Key=20=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor.Server/Startup.cs | 13 +-- src/BootstrapBlazor.Shared/Locales/en.json | 1 + src/BootstrapBlazor.Shared/Locales/zh.json | 1 + .../Pages/Samples/Client.razor.cs | 3 - .../Pages/Samples/Locator.razor | 58 ++++++++++ .../Pages/Samples/Locator.razor.cs | 54 ++++++++++ .../Shared/NavMenu.razor.cs | 6 ++ src/BootstrapBlazor/BootstrapBlazor.csproj | 4 +- .../Components/IPLocator/BaiDuIPLocator.cs | 53 ++++++++++ .../Components/IPLocator/DefaultIPLocator.cs | 50 +++++++++ .../IPLocator/DefaultIPLocatorProvider.cs | 58 ++++++++++ .../Components/IPLocator/IIPLocator.cs | 21 ++++ .../IPLocator/IIPLocatorProvider.cs | 21 ++++ .../Components/IPLocator/IPLocatorOption.cs | 54 ++++++++++ .../Components/Logger/BlazorLogger.cs | 2 +- ...tstrapBlazorServiceCollectionExtensions.cs | 14 ++- .../ConfigurationExtensions.cs | 0 .../Extensions/StringExtensions.cs | 100 ++++++++++++++++++ .../ServiceProviderHelper.cs | 0 19 files changed, 495 insertions(+), 18 deletions(-) create mode 100644 src/BootstrapBlazor.Shared/Pages/Samples/Locator.razor create mode 100644 src/BootstrapBlazor.Shared/Pages/Samples/Locator.razor.cs create mode 100644 src/BootstrapBlazor/Components/IPLocator/BaiDuIPLocator.cs create mode 100644 src/BootstrapBlazor/Components/IPLocator/DefaultIPLocator.cs create mode 100644 src/BootstrapBlazor/Components/IPLocator/DefaultIPLocatorProvider.cs create mode 100644 src/BootstrapBlazor/Components/IPLocator/IIPLocator.cs create mode 100644 src/BootstrapBlazor/Components/IPLocator/IIPLocatorProvider.cs create mode 100644 src/BootstrapBlazor/Components/IPLocator/IPLocatorOption.cs rename src/BootstrapBlazor/{Components/Logger => Extensions}/ConfigurationExtensions.cs (100%) create mode 100644 src/BootstrapBlazor/Extensions/StringExtensions.cs rename src/BootstrapBlazor/{Extensions => Utils}/ServiceProviderHelper.cs (100%) diff --git a/src/BootstrapBlazor.Server/Startup.cs b/src/BootstrapBlazor.Server/Startup.cs index 8f54b6e40..e4c0a8d2e 100644 --- a/src/BootstrapBlazor.Server/Startup.cs +++ b/src/BootstrapBlazor.Server/Startup.cs @@ -3,18 +3,10 @@ // Website: https://www.blazor.zone or https://argozhang.github.io/ using BootstrapBlazor.Components; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpOverrides; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.Linq; using System.Reflection; +using System.Text; namespace BootstrapBlazor.Server { @@ -52,7 +44,8 @@ namespace BootstrapBlazor.Server // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940 public void ConfigureServices(IServiceCollection services) { - services.AddLogging(builder => builder.AddConsole()); + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + services.AddCors(); services.AddResponseCompression(); diff --git a/src/BootstrapBlazor.Shared/Locales/en.json b/src/BootstrapBlazor.Shared/Locales/en.json index 9cecd5abb..14f2c71bc 100644 --- a/src/BootstrapBlazor.Shared/Locales/en.json +++ b/src/BootstrapBlazor.Shared/Locales/en.json @@ -379,6 +379,7 @@ "GroupBox": "GroupBox", "HandwrittenPage": "HandwrittenPage", "ListView": "ListView", + "Locator": "Locator", "Popover": "Popover", "QRCode": "QRCode", "Search": "Search", diff --git a/src/BootstrapBlazor.Shared/Locales/zh.json b/src/BootstrapBlazor.Shared/Locales/zh.json index 93ea4bbd0..c575488a9 100644 --- a/src/BootstrapBlazor.Shared/Locales/zh.json +++ b/src/BootstrapBlazor.Shared/Locales/zh.json @@ -379,6 +379,7 @@ "GroupBox": "集合 GroupBox", "HandwrittenPage": "手写组件 HandwrittenPage", "ListView": "列表组件 ListView", + "Locator": "位置定位 Locator", "Popover": "弹出窗 Popover", "QRCode": "二维码 QRCode", "Search": "搜索框 Search", diff --git a/src/BootstrapBlazor.Shared/Pages/Samples/Client.razor.cs b/src/BootstrapBlazor.Shared/Pages/Samples/Client.razor.cs index f460c7a02..d92816b43 100644 --- a/src/BootstrapBlazor.Shared/Pages/Samples/Client.razor.cs +++ b/src/BootstrapBlazor.Shared/Pages/Samples/Client.razor.cs @@ -14,9 +14,6 @@ namespace BootstrapBlazor.Shared.Pages /// public partial class Client { - /// - /// - /// [Inject] [NotNull] private WebClientService? ClientService { get; set; } diff --git a/src/BootstrapBlazor.Shared/Pages/Samples/Locator.razor b/src/BootstrapBlazor.Shared/Pages/Samples/Locator.razor new file mode 100644 index 000000000..fa1b747d5 --- /dev/null +++ b/src/BootstrapBlazor.Shared/Pages/Samples/Locator.razor @@ -0,0 +1,58 @@ +@page "/locator" + +

获取 IP 地理位置

+ +

多用系统日志跟踪

+ + +

用法介绍

+
+

组件中使用注入服务 IIPLocatorProvider 调用 Locate 方法

+
[Inject]
+[NotNull]
+private IIPLocatorProvider? IPLocator { get; set; }
+
+
+ +
由于地理位置查询接口返回字符集可能是其他字符集如 gbk,程序会报错;
+
解决办法:
+
Startup 文件中 ConfigureServices 方法内增加下面这句话即可解决
+
+
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance)
+
IP 测试数据
+
112.224.74.239 山东省济南市 联通
+
183.160.236.53 安徽省合肥市 电信
+
+
+ +
+
+ +
+
+
+
+

扩展自定义地理位置查询接口

+
+

1. 实现自定义定位器

+
private class CustomerLocator : IIPLocator
+{
+    public Task<string> Locate(IPLocatorOption option)
+    {
+        throw new NotImplementedException();
+    }
+}
+

2. 配置自定义定位器

+
public void ConfigureServices(IServiceCollection services)
+{
+    services.AddBootstrapBlazor(locatorAction: option =>
+    {
+        option.LocatorName = "CustomerLocator";
+        option.LocatorFactory = name => new CustomerLocator();
+        option.Url = "http://apis.juhe.cn/ip/ipNew?key=f57102d1b9fadd3f4a1c29072d0c0206&ip=";
+    });
+}
+
通过 AddBootstrapBlazor 方法的回调委托参数进行自定义定位器 CustomerLocator 配置
+
+
diff --git a/src/BootstrapBlazor.Shared/Pages/Samples/Locator.razor.cs b/src/BootstrapBlazor.Shared/Pages/Samples/Locator.razor.cs new file mode 100644 index 000000000..dc047e286 --- /dev/null +++ b/src/BootstrapBlazor.Shared/Pages/Samples/Locator.razor.cs @@ -0,0 +1,54 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +using BootstrapBlazor.Components; +using Microsoft.AspNetCore.Components; +using System.Diagnostics.CodeAnalysis; +using System.Threading.Tasks; + +namespace BootstrapBlazor.Shared.Pages +{ + /// + /// + /// + public partial class Locator + { + [Inject] + [NotNull] + private WebClientService? ClientService { get; set; } + + [Inject] + [NotNull] + private IIPLocatorProvider? IPLocator { get; set; } + + private string? Ip { get; set; } + + private string? Location { get; set; } + + /// + /// + /// + /// + /// + protected override async Task OnAfterRenderAsync(bool firstRender) + { + await base.OnAfterRenderAsync(firstRender); + + if (firstRender) + { + await ClientService.RetrieveRemoteInfo(); + Ip = ClientService.Ip; + StateHasChanged(); + } + } + + private async Task OnClick() + { + if (!string.IsNullOrEmpty(Ip)) + { + Location = await IPLocator.Locate(Ip); + } + } + } +} diff --git a/src/BootstrapBlazor.Shared/Shared/NavMenu.razor.cs b/src/BootstrapBlazor.Shared/Shared/NavMenu.razor.cs index 15017e297..82255701c 100644 --- a/src/BootstrapBlazor.Shared/Shared/NavMenu.razor.cs +++ b/src/BootstrapBlazor.Shared/Shared/NavMenu.razor.cs @@ -435,6 +435,12 @@ namespace BootstrapBlazor.Shared.Shared Url = "listviews" }, new() + { + IsNew = true, + Text = Localizer["Locator"], + Url = "locator" + }, + new() { Text = Localizer["QRCode"], Url = "qrcodes" diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 413942b84..4efbaf931 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,13 +1,14 @@ - 5.7.3 + 5.7.4 + @@ -16,6 +17,7 @@ + diff --git a/src/BootstrapBlazor/Components/IPLocator/BaiDuIPLocator.cs b/src/BootstrapBlazor/Components/IPLocator/BaiDuIPLocator.cs new file mode 100644 index 000000000..1d6748041 --- /dev/null +++ b/src/BootstrapBlazor/Components/IPLocator/BaiDuIPLocator.cs @@ -0,0 +1,53 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace BootstrapBlazor.Components +{ + /// + /// + /// + internal class BaiDuIPLocator : DefaultIPLocator + { + /// + /// 详细地址信息 + /// + public IEnumerable? Data { get; set; } + + /// + /// 结果状态返回码 + /// + public string? Status { get; set; } + + /// + /// + /// + /// + /// + public override Task Locate(IPLocatorOption option) => Locate(option); + + /// + /// + /// + /// + public override string ToString() + { + return Status == "0" ? (Data?.FirstOrDefault()?.Location ?? "XX XX") : "Error"; + } + } + + /// + /// + /// + public class LocationInfo + { + /// + /// + /// + public string? Location { get; set; } + } +} diff --git a/src/BootstrapBlazor/Components/IPLocator/DefaultIPLocator.cs b/src/BootstrapBlazor/Components/IPLocator/DefaultIPLocator.cs new file mode 100644 index 000000000..b3397c307 --- /dev/null +++ b/src/BootstrapBlazor/Components/IPLocator/DefaultIPLocator.cs @@ -0,0 +1,50 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +using Microsoft.Extensions.Logging; +using System; +using System.Net.Http.Json; +using System.Threading; +using System.Threading.Tasks; + +namespace BootstrapBlazor.Components +{ + /// + /// + /// + internal class DefaultIPLocator : IIPLocator + { + /// + /// + /// + /// + /// + public virtual Task Locate(IPLocatorOption option) => Task.FromResult(string.Empty); + + /// + /// + /// + /// + /// + protected static async Task Locate(IPLocatorOption option) where T : class + { + string? ret = null; + try + { + if (!string.IsNullOrEmpty(option.Url) && !string.IsNullOrEmpty(option.IP) && option.HttpClient != null) + { + var url = string.Format(option.Url, option.IP); + using var token = new CancellationTokenSource(option.RequestTimeout); + var result = await option.HttpClient.GetFromJsonAsync(url, token.Token); + ret = result?.ToString(); + } + } + catch (Exception ex) + { + option.Logger?.LogError(ex, option.Url, option.IP); + } + return ret ?? string.Empty; + } + } +} diff --git a/src/BootstrapBlazor/Components/IPLocator/DefaultIPLocatorProvider.cs b/src/BootstrapBlazor/Components/IPLocator/DefaultIPLocatorProvider.cs new file mode 100644 index 000000000..96d00aa48 --- /dev/null +++ b/src/BootstrapBlazor/Components/IPLocator/DefaultIPLocatorProvider.cs @@ -0,0 +1,58 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +using Microsoft.Extensions.Logging; +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; + +namespace BootstrapBlazor.Components +{ + /// + /// 默认 IP 地理位置定位器 + /// + internal class DefaultIPLocatorProvider : IIPLocatorProvider + { + private readonly IPLocatorOption _option = new(); + + /// + /// 构造函数 + /// + /// + /// + public DefaultIPLocatorProvider(IHttpClientFactory factory, ILogger logger) + { + _option.HttpClient = factory.CreateClient(); + _option.Logger = logger; + } + + /// + /// 定位方法 + /// + /// + /// + public async Task Locate(string ip) + { + string? ret = null; + + // 解析本机地址 + if (string.IsNullOrEmpty(ip) || _option.Localhosts.Any(p => p == ip)) + { + ret = "本地连接"; + } + else + { + // IP定向器地址未设置 + _option.IP = ip; + if (string.IsNullOrEmpty(_option.Url)) + { + ret = string.Empty; + } + var locator = _option.LocatorFactory(_option.LocatorName); + ret = await locator.Locate(_option); + } + return ret ?? string.Empty; + } + } +} diff --git a/src/BootstrapBlazor/Components/IPLocator/IIPLocator.cs b/src/BootstrapBlazor/Components/IPLocator/IIPLocator.cs new file mode 100644 index 000000000..25c7bc70a --- /dev/null +++ b/src/BootstrapBlazor/Components/IPLocator/IIPLocator.cs @@ -0,0 +1,21 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +using System.Threading.Tasks; + +namespace BootstrapBlazor.Components +{ + /// + /// + /// + public interface IIPLocator + { + /// + /// + /// + /// 定位器配置信息 + /// 定位器定位结果 + Task Locate(IPLocatorOption option); + } +} diff --git a/src/BootstrapBlazor/Components/IPLocator/IIPLocatorProvider.cs b/src/BootstrapBlazor/Components/IPLocator/IIPLocatorProvider.cs new file mode 100644 index 000000000..27aa5f805 --- /dev/null +++ b/src/BootstrapBlazor/Components/IPLocator/IIPLocatorProvider.cs @@ -0,0 +1,21 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +using System.Threading.Tasks; + +namespace BootstrapBlazor.Components +{ + /// + /// IP 地址定位服务 + /// + public interface IIPLocatorProvider + { + /// + /// + /// + /// + /// + Task Locate(string ip); + } +} diff --git a/src/BootstrapBlazor/Components/IPLocator/IPLocatorOption.cs b/src/BootstrapBlazor/Components/IPLocator/IPLocatorOption.cs new file mode 100644 index 000000000..798f11710 --- /dev/null +++ b/src/BootstrapBlazor/Components/IPLocator/IPLocatorOption.cs @@ -0,0 +1,54 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +using Microsoft.Extensions.Logging; + +namespace BootstrapBlazor.Components +{ + /// + /// IP定位器配置项 + /// + public class IPLocatorOption + { + /// + /// 获得/设置 定位器名称 + /// + public string LocatorName { get; set; } = nameof(BaiDuIPLocator); + + /// + /// 获得/设置 定位器创建方法未设置使用内部定位器 + /// + public Func LocatorFactory { get; set; } = _ => new BaiDuIPLocator(); + + /// + /// 获得/设置 IP定位器请求地址 + /// + public string Url { get; set; } = "https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?resource_id=6006&query={0}"; + + /// + /// 获得/设置 IP地址请求超时时间 默认为 3000 毫秒 + /// + public int RequestTimeout { get; set; } = 3000; + + /// + /// 获得 本机地址列表 + /// + public List Localhosts { get; } = new List(new string[] { "::1", "127.0.0.1" }); + + /// + /// 获得/设置 IP地址 + /// + internal string? IP { get; set; } + + /// + /// 获得/设置 HttpClient 实体类 + /// + internal HttpClient? HttpClient { get; set; } + + /// + /// 获得/设置 ILogger 实体类 + /// + internal ILogger? Logger { get; set; } + } +} diff --git a/src/BootstrapBlazor/Components/Logger/BlazorLogger.cs b/src/BootstrapBlazor/Components/Logger/BlazorLogger.cs index 5bc804104..d538e8a95 100644 --- a/src/BootstrapBlazor/Components/Logger/BlazorLogger.cs +++ b/src/BootstrapBlazor/Components/Logger/BlazorLogger.cs @@ -88,7 +88,7 @@ namespace BootstrapBlazor.Components logger.AppendLine(); } - logger.AppendFormat("{0}: {1}", "Exception:", exception.Message); + logger.AppendFormat("{0}: {1}", "Exception", exception.Message); logger.AppendLine(); logger.Append(new string('*', 45)); diff --git a/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs b/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs index 6b0fddc9f..d5f1651ad 100644 --- a/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs +++ b/src/BootstrapBlazor/Extensions/BootstrapBlazorServiceCollectionExtensions.cs @@ -24,12 +24,13 @@ namespace Microsoft.Extensions.DependencyInjection /// /// /// - /// + /// + /// /// - public static IServiceCollection AddBootstrapBlazor(this IServiceCollection services, Action? configureOptions = null, Action? setupAction = null) + public static IServiceCollection AddBootstrapBlazor(this IServiceCollection services, Action? configureOptions = null, Action? localizationAction = null, Action? locatorAction = null) { services.AddAuthorizationCore(); - services.AddJsonLocalization(setupAction); + services.AddJsonLocalization(localizationAction); services.TryAddScoped(); services.TryAddScoped(); services.TryAddScoped(typeof(IDataService<>), typeof(NullDataService<>)); @@ -47,6 +48,13 @@ namespace Microsoft.Extensions.DependencyInjection { configureOptions?.Invoke(options); }); + + services.AddHttpClient(); + services.TryAddSingleton(); + services.Configure(options => + { + locatorAction?.Invoke(options); + }); return services; } diff --git a/src/BootstrapBlazor/Components/Logger/ConfigurationExtensions.cs b/src/BootstrapBlazor/Extensions/ConfigurationExtensions.cs similarity index 100% rename from src/BootstrapBlazor/Components/Logger/ConfigurationExtensions.cs rename to src/BootstrapBlazor/Extensions/ConfigurationExtensions.cs diff --git a/src/BootstrapBlazor/Extensions/StringExtensions.cs b/src/BootstrapBlazor/Extensions/StringExtensions.cs new file mode 100644 index 000000000..fb1340bb1 --- /dev/null +++ b/src/BootstrapBlazor/Extensions/StringExtensions.cs @@ -0,0 +1,100 @@ +// Copyright (c) Argo Zhang (argo@163.com). All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +// Website: https://www.blazor.zone or https://argozhang.github.io/ + +using System; +using System.Collections.Generic; + +namespace BootstrapBlazor.Components +{ + /// + /// + /// + internal static class StringExtensions + { + /// + /// SpanSplit 扩展方法 + /// + /// 源数组 + /// 分隔符数组 分割规则作为整体 + /// StringSplitOptions 选项 + /// 分割后的字符串数组 + public static List SpanSplit(this string source, string? splitStr = null, StringSplitOptions stringSplitOptions = StringSplitOptions.None) + { + var ret = new List(); + if (string.IsNullOrEmpty(source)) + { + return ret; + } + + if (string.IsNullOrEmpty(splitStr)) + { + splitStr = Environment.NewLine; + } + + var sourceSpan = source.AsSpan(); + var splitSpan = splitStr.AsSpan(); + + do + { + var n = sourceSpan.IndexOf(splitSpan); + if (n == -1) + { + n = sourceSpan.Length; + } + + ret.Add(stringSplitOptions == StringSplitOptions.None + ? sourceSpan.Slice(0, n).ToString() + : sourceSpan.Slice(0, n).Trim().ToString()); + sourceSpan = sourceSpan[Math.Min(sourceSpan.Length, n + splitSpan.Length)..]; + } + while (sourceSpan.Length > 0); + return ret; + } + + /// + /// SpanSplit 扩展方法 + /// + /// 源数组 + /// 分隔符数组 分割规则是任意一个 + /// StringSplitOptions 选项 + /// 分割后的字符串数组 + public static List SpanSplitAny(this string source, string splitStr, StringSplitOptions stringSplitOptions = StringSplitOptions.None) + { + var ret = new List(); + if (string.IsNullOrEmpty(source)) + { + return ret; + } + + if (string.IsNullOrEmpty(splitStr)) + { + ret.Add(source); + return ret; + } + + var sourceSpan = source.AsSpan(); + var splitSpan = splitStr.AsSpan(); + + do + { + var n = sourceSpan.IndexOfAny(splitSpan); + if (n == -1) + { + n = sourceSpan.Length; + } + + if (n > 0) + { + ret.Add(stringSplitOptions == StringSplitOptions.None + ? sourceSpan.Slice(0, n).ToString() + : sourceSpan.Slice(0, n).Trim().ToString()); + } + + sourceSpan = sourceSpan[Math.Min(sourceSpan.Length, n + 1)..]; + } + while (sourceSpan.Length > 0); + return ret; + } + } +} diff --git a/src/BootstrapBlazor/Extensions/ServiceProviderHelper.cs b/src/BootstrapBlazor/Utils/ServiceProviderHelper.cs similarity index 100% rename from src/BootstrapBlazor/Extensions/ServiceProviderHelper.cs rename to src/BootstrapBlazor/Utils/ServiceProviderHelper.cs