Skip to content

feat(JuHeIpLocatorProvider): bump version 10.1.0#946

Merged
ArgoZhang merged 7 commits intomasterfrom
feat-ip
Mar 7, 2026
Merged

feat(JuHeIpLocatorProvider): bump version 10.1.0#946
ArgoZhang merged 7 commits intomasterfrom
feat-ip

Conversation

@ArgoZhang
Copy link
Member

@ArgoZhang ArgoZhang commented Mar 7, 2026

Link issues

fixes #945

Summary By Copilot

Regression?

  • Yes
  • No

Risk

  • High
  • Medium
  • Low

Verification

  • Manual (required)
  • Automated

Packaging changes reviewed?

  • Yes
  • No
  • N/A

☑️ Self Check before Merge

⚠️ Please check all items below before review. ⚠️

  • Doc is updated/provided or not needed
  • Demo is updated/provided or not needed
  • Merge the latest code from the main branch

Summary by Sourcery

Improve the JuHe IP locator provider’s configuration model, response types, and error handling while enhancing bilingual documentation and service registration naming.

Bug Fixes:

  • Correct the JuHe IP locator default API endpoint and ensure a fallback URL is applied when none is configured.
  • Handle missing configuration keys and API error responses by recording and logging descriptive error messages instead of throwing generic exceptions.

Enhancements:

  • Extract JuHe location result and data into dedicated types for clearer response modeling and reuse.
  • Make JuHe IP locator options properties nullable and centralize the default endpoint as a constant.
  • Add bilingual (Chinese/English) XML documentation comments to the JuHe IP locator provider, options, data models, and service registration extension.
  • Fix the JuHe IP locator service extension class name and update its summary to reflect the correct service.

Copilot AI review requested due to automatic review settings March 7, 2026 09:10
@bb-auto bb-auto bot added the enhancement New feature or request label Mar 7, 2026
@bb-auto bb-auto bot added this to the v9.2.0 milestone Mar 7, 2026
@sourcery-ai
Copy link

sourcery-ai bot commented Mar 7, 2026

Reviewer's Guide

Refactors the JuHe IP locator provider to use new JuHeLocation* DTOs, improves error handling/logging and option defaults, makes configuration properties nullable, and updates XML docs and naming for clearer bilingual documentation and corrected service extension naming.

Sequence diagram for JuHe IP lookup with new DTOs and error handling

sequenceDiagram
    actor Application
    participant Provider as JuHeIpLocatorProvider
    participant Options as JuHeIpLocatorOptions
    participant Factory as IHttpClientFactory
    participant Client as HttpClient
    participant Api as JuHeApi

    Application->>Provider: GetOptions()
    activate Provider
    Provider->>Options: read Key, Url
    alt Key is null or empty
        Provider->>Provider: set LastError
        Provider->>Provider: Log(LastError)
        Provider-->>Application: options with invalid Key
    else Key is valid
        opt Url is null or empty
            Provider->>Options: set Url to Url constant
        end
        Provider-->>Application: options
    end
    deactivate Provider

    opt Key is valid
        Application->>Factory: CreateClient()
        Factory-->>Application: HttpClient
        Application->>Provider: Fetch(url, Client, token)
        activate Provider
        Provider->>Client: GetFromJsonAsync JuHeLocationResult
        Client->>Api: HTTP GET ipNewV3
        Api-->>Client: JuHeLocationResult
        Client-->>Provider: JuHeLocationResult
        alt ErrorCode != 0
            Provider->>Provider: set LastError
            Provider->>Provider: Log(LastError)
        end
        Provider-->>Application: formatted location string
        deactivate Provider
    end
Loading

Class diagram for updated JuHe IP locator provider and DTOs

classDiagram
    class JuHeIpLocatorProvider {
        -IHttpClientFactory httpClientFactory
        -IOptions~JuHeIpLocatorOptions~ juHeIpLocatorOptions
        -ILogger~JuHeIpLocatorProvider~ logger
        -JuHeIpLocatorOptions _options
        -string LastError
        -const string Url
        +JuHeIpLocatorOptions GetOptions()
        +Task~string~ Fetch(string url, HttpClient client, CancellationToken token)
        -void Log(string message)
    }

    class JuHeIpLocatorOptions {
        +string Key
        +string Url
        +TimeSpan Timeout
    }

    class JuHeLocationData {
        +string Continent
        +string Country
        +string ZipCode
        +string TimeZone
        +string Accuracy
        +string Owner
        +string Isp
        +string Source
        +string AreaCode
        +string AdCode
        +string AsNumber
        +string Lat
        +string Lng
        +string Radius
        +string Prov
        +string City
        +string District
    }

    class JuHeLocationResult {
        +string Reason
        +int ErrorCode
        +JuHeLocationData Result
        +string ToString()
    }

    class BootstrapBlazorJuHeIpLocatorExtensions {
        +IServiceCollection AddBootstrapBlazorJuHeIpLocatorService(IServiceCollection services)
    }

    JuHeIpLocatorProvider --> JuHeIpLocatorOptions : uses
    JuHeIpLocatorProvider --> JuHeLocationResult : deserializes
    JuHeLocationResult *-- JuHeLocationData : contains
    BootstrapBlazorJuHeIpLocatorExtensions ..> JuHeIpLocatorOptions : configures
    BootstrapBlazorJuHeIpLocatorExtensions ..> JuHeIpLocatorProvider : registers
Loading

Flow diagram for GetOptions defaulting and logging changes

flowchart TD
    A[GetOptions called] --> B[Read options from juHeIpLocatorOptions]
    B --> C{Key is null or empty}
    C -- Yes --> D[Set LastError message about missing Key]
    D --> E[Log LastError via Log]
    E --> F[Return options]
    C -- No --> G{Url is null or empty}
    G -- Yes --> H[Set Url to constant Url]
    H --> F
    G -- No --> F[Return options unchanged]
Loading

File-Level Changes

Change Details Files
Refactor JuHe IP locator provider implementation to use new DTO classes, centralize defaults, and improve error handling/logging.
  • Replace internal LocationResult/LocationData types with shared JuHeLocationResult and JuHeLocationData classes for deserialization
  • Introduce a constant for the default JuHe API URL and use it when options do not specify a URL
  • Change Fetch to deserialize JuHeLocationResult and record errors in LastError before logging via a new helper method
  • Adjust GetOptions to validate the API key, set LastError and log instead of throwing, and to only default the URL when missing
  • Remove unused configuration-related usings and Json serialization attributes that moved to the new DTO types
src/components/BootstrapBlazor.JuHeIpLocatorProvider/JuHeIpLocatorProvider.cs
src/components/BootstrapBlazor.JuHeIpLocatorProvider/JuHeLocationData.cs
src/components/BootstrapBlazor.JuHeIpLocatorProvider/JuHeLocationResult.cs
Relax and clarify JuHe IP locator configuration options and documentation.
  • Make Key and Url properties nullable instead of defaulting to empty strings or an old URL
  • Align timeout and option comments with bilingual XML docs for clarity
  • Ensure the default URL is now applied in code instead of as a property initializer
src/components/BootstrapBlazor.JuHeIpLocatorProvider/JuHeIpLocatorOptions.cs
src/components/BootstrapBlazor.JuHeIpLocatorProvider/JuHeIpLocatorProvider.cs
Improve service extension naming and documentation to better describe the JuHe IP locator service.
  • Fix the BootstrapBlazoJuHeIpLocatorExtensions type name typo to BootstrapBlazorJuHeIpLocatorExtensions
  • Update XML doc comments on the extension class and registration method to bilingual Chinese/English descriptions specific to the JuHe IP locator
src/components/BootstrapBlazor.JuHeIpLocatorProvider/Extensions/ServiceCollectionExtensions.cs

Assessment against linked issues

Issue Objective Addressed Explanation
#945 Update the JuHeIpLocatorProvider component to the 10.1.0 version of the JuHe IP API (including endpoint URL, data models, options, and related service extension).

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@ArgoZhang ArgoZhang merged commit 06728eb into master Mar 7, 2026
4 checks passed
@ArgoZhang ArgoZhang deleted the feat-ip branch March 7, 2026 09:11
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • In GetOptions, when Key is missing you set LastError and log but still return options and allow the request flow to continue; consider short‑circuiting or preventing the HTTP call when Key is null/empty so callers don’t attempt a doomed request.
  • The bilingual XML comments for JuHeLocationData.Lat and JuHeLocationData.Lng disagree (zh vs en describe opposite concepts); please align the Chinese and English summaries so latitude/longitude are consistently documented.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `GetOptions`, when `Key` is missing you set `LastError` and log but still return options and allow the request flow to continue; consider short‑circuiting or preventing the HTTP call when `Key` is null/empty so callers don’t attempt a doomed request.
- The bilingual XML comments for `JuHeLocationData.Lat` and `JuHeLocationData.Lng` disagree (zh vs en describe opposite concepts); please align the Chinese and English summaries so latitude/longitude are consistently documented.

## Individual Comments

### Comment 1
<location path="src/components/BootstrapBlazor.JuHeIpLocatorProvider/JuHeIpLocatorProvider.cs" line_range="28" />
<code_context>

     private JuHeIpLocatorOptions? _options;

+    private const string Url = "http://apis.juhe.cn/ip/ipNewV3";
+
     /// <summary>
</code_context>
<issue_to_address>
**🚨 suggestion (security):** Consider using HTTPS instead of HTTP for the default JuHe API URL to avoid sending IP data over an unencrypted channel.

This constant currently uses plain HTTP. If `ipNewV3` supports HTTPS, please change it to `https://` so IP and key data aren’t sent in clear text and to meet modern security practices. If HTTPS truly isn’t available, consider documenting that limitation where this URL is defined.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.


private JuHeIpLocatorOptions? _options;

private const string Url = "http://apis.juhe.cn/ip/ipNewV3";
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 suggestion (security): Consider using HTTPS instead of HTTP for the default JuHe API URL to avoid sending IP data over an unencrypted channel.

This constant currently uses plain HTTP. If ipNewV3 supports HTTPS, please change it to https:// so IP and key data aren’t sent in clear text and to meet modern security practices. If HTTPS truly isn’t available, consider documenting that limitation where this URL is defined.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR bumps the BootstrapBlazor.JuHeIpLocatorProvider component to version 10.1.0, upgrading the JuHe IP geolocation API endpoint from V1 (ipNew) to V3 (ipNewV3). Along the way, the code is refactored to extract nested data model classes into separate files, XML doc comments are updated to use bilingual format, a class naming typo is fixed, and error handling is changed from throwing exceptions to logging and setting LastError.

Changes:

  • Upgraded the JuHe API endpoint from ipNew to ipNewV3 and set the component version to 10.1.0 with BootstrapBlazor dependency 10.4.0
  • Extracted LocationResult/LocationData nested classes into standalone JuHeLocationResult/JuHeLocationData files with bilingual XML documentation
  • Replaced exception-throwing error handling in GetOptions with LastError assignment and logging, and fixed the class name typo BootstrapBlazoJuHeIpLocatorExtensionsBootstrapBlazorJuHeIpLocatorExtensions

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
BootstrapBlazor.JuHeIpLocatorProvider.csproj Adds explicit Version 10.1.0, hardcodes BootstrapBlazor dependency to 10.4.0
JuHeIpLocatorProvider.cs Upgrades API URL to V3, refactors error handling to use LastError+logging, extracts nested types, adds bilingual docs
JuHeIpLocatorOptions.cs Changes Key and Url to nullable, removes inline defaults, adds bilingual docs
JuHeLocationResult.cs New file: extracted location result class with bilingual docs
JuHeLocationData.cs New file: extracted location data class with bilingual docs
ServiceCollectionExtensions.cs Fixes class name typo, adds bilingual docs

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


private JuHeIpLocatorOptions? _options;

private const string Url = "http://apis.juhe.cn/ip/ipNewV3";
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default URL uses http:// (unencrypted) which means the API key in the query parameter key=... will be transmitted in plaintext. Consider using https:// instead if the JuHe API supports it, to protect the API key from being intercepted in transit.

Suggested change
private const string Url = "http://apis.juhe.cn/ip/ipNewV3";
private const string Url = "https://apis.juhe.cn/ip/ipNewV3";

Copilot uses AI. Check for mistakes.
Comment on lines +80 to +86
/// <para lang="zh">获得/设置 经度</para>
/// <para lang="en">Gets or sets the latitude</para>
/// </summary>
public string? Lat { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 纬度</para>
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Chinese and English XML comments for Lat and Lng are swapped. Lat is latitude (纬度) but the Chinese comment says "经度" (longitude). Conversely, Lng is longitude (经度) but the Chinese comment says "纬度" (latitude). The Chinese comments for these two properties should be swapped: Lat should have "获得/设置 纬度" and Lng should have "获得/设置 经度".

Suggested change
/// <para lang="zh">获得/设置 经度</para>
/// <para lang="en">Gets or sets the latitude</para>
/// </summary>
public string? Lat { get; set; }
/// <summary>
/// <para lang="zh">获得/设置 纬度</para>
/// <para lang="zh">获得/设置 纬度</para>
/// <para lang="en">Gets or sets the latitude</para>
/// </summary>
public string? Lat { get; set; }
/// <summary>
/// <para lang="zh">获得/设置 经度</para>

Copilot uses AI. Check for mistakes.
public string? AdCode { get; set; }

/// <summary>
/// <para lang="zh">获得/设置 国家代码</para>
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Chinese comment says "获得/设置 国家代码" (country code) but the property is AsNumber, which represents an Autonomous System number, not a country code. The English comment "Gets or sets the AS number" is correct. The Chinese comment should be updated to match, e.g., "获得/设置 AS 编号".

Suggested change
/// <para lang="zh">获得/设置 国家代码</para>
/// <para lang="zh">获得/设置 AS 编号</para>

Copilot uses AI. Check for mistakes.
Comment on lines +56 to 61
if (string.IsNullOrEmpty(options.Key))
{
if (string.IsNullOrEmpty(options.Key))
{
throw new InvalidOperationException($"{nameof(JuHeIpLocatorOptions)}:Key not value in appsettings configuration file. 未配置 {nameof(JuHeIpLocatorOptions)}:Key 请在 appsettings.json 中配置 {nameof(JuHeIpLocatorOptions)}:Key");
}
if (string.IsNullOrEmpty(options.Url))
{
options.Url = "http://apis.juhe.cn/ip/ipNewV3";
}
LastError = $"{nameof(JuHeIpLocatorOptions)}:Key not value in appsettings configuration file. 未配置 {nameof(JuHeIpLocatorOptions)}:Key 请在 appsettings.json 中配置 {nameof(JuHeIpLocatorOptions)}:Key";
Log(LastError);

}
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When Key is empty/null, the method logs an error but still returns the options object. The caller LocateByIp then proceeds to construct a URL with an empty key and makes a pointless HTTP request that will fail. Previously, this code threw an InvalidOperationException, which would prevent the HTTP call. Consider either returning early (e.g., returning null and checking in LocateByIp) or short-circuiting the LocateByIp call when Key is missing, to avoid unnecessary network requests.

Copilot uses AI. Check for mistakes.

<ItemGroup>
<PackageReference Include="BootstrapBlazor" Version="$(BBVersion)" />
<PackageReference Include="BootstrapBlazor" Version="10.4.0" />
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This component hardcodes BootstrapBlazor version 10.4.0 while every other component in the repository uses $(BBVersion) (currently 10.0.0, defined in src/Directory.Build.props:25). This breaks the convention for centralized dependency version management and could lead to version inconsistencies across the solution. Consider using $(BBVersion) here as well, or updating BBVersion centrally if a newer version is needed.

Suggested change
<PackageReference Include="BootstrapBlazor" Version="10.4.0" />
<PackageReference Include="BootstrapBlazor" Version="$(BBVersion)" />

Copilot uses AI. Check for mistakes.
{
options.Url = "http://apis.juhe.cn/ip/ipNewV3";
}
LastError = $"{nameof(JuHeIpLocatorOptions)}:Key not value in appsettings configuration file. 未配置 {nameof(JuHeIpLocatorOptions)}:Key 请在 appsettings.json 中配置 {nameof(JuHeIpLocatorOptions)}:Key";
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The English portion of the error message "Key not value in appsettings configuration file" is grammatically incorrect. It should read something like "Key has no value in appsettings configuration file" or "Key is not configured in appsettings configuration file".

Suggested change
LastError = $"{nameof(JuHeIpLocatorOptions)}:Key not value in appsettings configuration file. 未配置 {nameof(JuHeIpLocatorOptions)}:Key 请在 appsettings.json 中配置 {nameof(JuHeIpLocatorOptions)}:Key";
LastError = $"{nameof(JuHeIpLocatorOptions)}:Key has no value in appsettings configuration file. 未配置 {nameof(JuHeIpLocatorOptions)}:Key 请在 appsettings.json 中配置 {nameof(JuHeIpLocatorOptions)}:Key";

Copilot uses AI. Check for mistakes.
class JuHeLocationResult
{
/// <summary>
/// <para lang="zh">获得/设置 结果状态返回码</para>
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Chinese comment "获得/设置 结果状态返回码" (result status return code) is misleading for a string? Reason property. The Reason property contains the textual reason/message, not a code. Consider updating to something like "获得/设置 结果状态描述" to be consistent with the English "Gets or sets the result status reason".

Suggested change
/// <para lang="zh">获得/设置 结果状态返回码</para>
/// <para lang="zh">获得/设置 结果状态描述</para>

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(JuHeIpLocatorProvider): bump version 10.1.0

2 participants