Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 16, 2026

Issues

close #7533

Summary By Copilot

Replaced manual AttributeItem array maintenance with reflection-based automatic extraction from Circle component parameters. Implemented global static cache for performance.

Changes

AttributeItem class (src/BootstrapBlazor.Server/Data/AttributeItem.cs)

  • Added Version property for XML documentation version tags

ComponentAttributeCacheService (src/BootstrapBlazor.Server/Services/ComponentAttributeCacheService.cs)

  • Global ConcurrentDictionary cache for component attribute metadata
  • Reflection-based extraction of [Parameter] attributes
  • XML documentation parsing: summary, version (<para><version>), default values
  • Automatic enum value list generation
  • Security hardening: XXE prevention via XmlReaderSettings, assembly location validation, specific exception handling

Circles.razor.cs (src/BootstrapBlazor.Server/Components/Samples/Circles.razor.cs)

  • Replaced 52-line manual array with single reflection call:
private AttributeItem[] GetAttributes()
{
    return ComponentAttributeCacheService.GetAttributes(typeof(BootstrapBlazor.Components.Circle));
}

BootstrapBlazor.csproj (src/BootstrapBlazor/BootstrapBlazor.csproj)

  • Enabled GenerateDocumentationFile for XML comments

Regression?

  • Yes
  • No

Risk

  • High
  • Medium
  • Low

Isolated change to demo component attribute display. No API changes, backward compatible. Cache invalidation available via ClearCache().

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
Original prompt

目标

重构 Circles 示例组件,从手动维护 AttributeItem 列表改为使用反射自动获取 Circle 组件的参数信息,并通过全局静态字典缓存提升性能。

需要实现的功能

1. 扩展 AttributeItem 类添加 Version 属性

文件:src/BootstrapBlazor.Server/Data/AttributeItem.cs

在 AttributeItem 类中添加一个新的 Version 属性:

/// <summary>
/// 获得/设置 版本
/// </summary>
[DisplayName("版本")]
public string Version { get; set; } = "";

2. 创建全局静态缓存服务

创建新文件:src/BootstrapBlazor.Server/Services/ComponentAttributeCacheService.cs

实现一个全局静态字典缓存服务,用于缓存组件的 AttributeItem 列表:

using System.Collections.Concurrent;
using System.ComponentModel;
using System.Reflection;
using System.Xml.Linq;
using BootstrapBlazor.Server.Data;
using Microsoft.AspNetCore.Components;

namespace BootstrapBlazor.Server.Services;

/// <summary>
/// 组件属性缓存服务
/// </summary>
public static class ComponentAttributeCacheService
{
    private static readonly ConcurrentDictionary<Type, AttributeItem[]> _cache = new();

    /// <summary>
    /// 获取组件的 AttributeItem 列表(带缓存)
    /// </summary>
    public static AttributeItem[] GetAttributes(Type componentType)
    {
        return _cache.GetOrAdd(componentType, type =>
        {
            var attributes = new List<AttributeItem>();
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                .Where(p => p.GetCustomAttribute<ParameterAttribute>() != null);

            foreach (var property in properties)
            {
                var item = new AttributeItem
                {
                    Name = property.Name,
                    Type = GetFriendlyTypeName(property.PropertyType),
                    Description = GetSummary(property) ?? "",
                    DefaultValue = GetDefaultValue(property) ?? "",
                    ValueList = GetValueList(property) ?? "",
                    Version = GetVersion(property) ?? ""
                };
                attributes.Add(item);
            }

            return attributes.ToArray();
        });
    }

    /// <summary>
    /// 从 XML 注释获取 summary
    /// </summary>
    private static string? GetSummary(PropertyInfo property)
    {
        var xmlDoc = GetXmlDocumentation(property.DeclaringType?.Assembly);
        if (xmlDoc == null) return null;

        var memberName = $"P:{property.DeclaringType?.FullName}.{property.Name}";
        var element = xmlDoc.Descendants("member")
            .FirstOrDefault(x => x.Attribute("name")?.Value == memberName);

        return element?.Element("summary")?.Value.Trim();
    }

    /// <summary>
    /// 从 XML 注释的 para version 节点获取版本信息
    /// </summary>
    private static string? GetVersion(PropertyInfo property)
    {
        var xmlDoc = GetXmlDocumentation(property.DeclaringType?.Assembly);
        if (xmlDoc == null) return null;

        var memberName = $"P:{property.DeclaringType?.FullName}.{property.Name}";
        var element = xmlDoc.Descendants("member")
            .FirstOrDefault(x => x.Attribute("name")?.Value == memberName);

        // 查找 <para><version>10.0.0</version></para>
        var versionElement = element?.Descendants("para")
            .SelectMany(p => p.Elements("version"))
            .FirstOrDefault();

        return versionElement?.Value.Trim();
    }

    /// <summary>
    /// 获取默认值
    /// </summary>
    private static string? GetDefaultValue(PropertyInfo property)
    {
        var defaultValueAttr = property.GetCustomAttribute<DefaultValueAttribute>();
        if (defaultValueAttr != null)
        {
            return defaultValueAttr.Value?.ToString() ?? "";
        }

        // 从 XML 注释中提取 DefaultValue
        var xmlDoc = GetXmlDocumentation(property.DeclaringType?.Assembly);
        if (xmlDoc == null) return null;

        var memberName = $"P:{property.DeclaringType?.FullName}.{property.Name}";
        var element = xmlDoc.Descendants("member")
            .FirstOrDefault(x => x.Attribute("name")?.Value == memberName);

        var defaultElement = element?.Element("value");
        return defaultElement?.Value.Trim();
    }

    /// <summary>
    /// 获取可选值列表
    /// </summary>
    private static string? GetValueList(PropertyInfo property)
    {
        // 如果是枚举类型,返回枚举值
        if (property.PropertyType.IsEnum)
        {
            return string.Join(" / ", Enum.GetNames(property.PropertyType));
        }

        return "";
    }

    /// <summary>
    /// 获取友好的类型名称
    /// </summary>
    private static string GetFriendlyTypeName(Type type)
    {
        if (type.IsGenericType)
        {
            var genericTypeName = type.GetGenericTypeDefinition().Name;
            genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf('`'));
            var genericArgs = string.Join(", ", type.GetGenericArguments().Select(GetFriendlyTypeName));
            return $"{genericTypeName}<{genericArgs}>";
        }

        return type.Name switch
        {
            "Int32" => "int",
            "String" => "string",
            "Boolean" => "bool",
            "Double" => "double...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

@bb-auto
Copy link

bb-auto bot commented Jan 16, 2026

Thanks for your PR, @copilot. Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

Copilot AI changed the title [WIP] Refactor Circles example component to use reflection for parameters Refactor Circles component to use reflection-based attribute extraction with caching Jan 16, 2026
Copilot AI requested a review from ArgoZhang January 16, 2026 07:12
@codecov
Copy link

codecov bot commented Jan 16, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (91466d0) to head (6c8cf2b).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main     #7529   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          748       748           
  Lines        33012     33012           
  Branches      4588      4588           
=========================================
  Hits         33012     33012           
Flag Coverage Δ
BB 100.00% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

# Conflicts:
#	src/BootstrapBlazor/Components/Circle/Circle.razor.cs
@ArgoZhang ArgoZhang changed the title Refactor Circles component to use reflection-based attribute extraction with caching doc(AttributeTable): auto generate AttributeTable content Jan 16, 2026
@ArgoZhang ArgoZhang marked this pull request as ready for review January 16, 2026 13:41
Copilot AI review requested due to automatic review settings January 16, 2026 13:41
@bb-auto bb-auto bot unassigned Copilot Jan 16, 2026
@bb-auto bb-auto bot added the documentation Improvements or additions to documentation label Jan 16, 2026
@bb-auto bb-auto bot added this to the v10.2.0 milestone Jan 16, 2026
Copy link
Contributor

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 pull request refactors the attribute documentation system from manual maintenance to automatic reflection-based generation. It introduces a caching service that extracts component parameter information dynamically from XML documentation.

Changes:

  • Added reflection-based automatic extraction of component attributes via ComponentAttributeCacheService
  • Extended AttributeItem with a Version property for version tracking
  • Enhanced AttributeTable to accept a Type parameter for automatic attribute generation
  • Configured XML documentation file copying during publish

Reviewed changes

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

Show a summary per file
File Description
ComponentAttributeCacheService.cs New static caching service for extracting component attributes via reflection with XML doc parsing
AttributeItem.cs Added Version property to support XML version tags
AttributeTable.razor.cs Added Type parameter to enable automatic attribute generation
AttributeTable.razor Added Version column to display version information
Circles.razor.cs Replaced manual 52-line attribute array with single reflection call
Circles.razor Changed from manual GetAttributes() call to Type parameter
Directory.Build.targets Added XML documentation copying task for publish

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

@ArgoZhang ArgoZhang merged commit 8de47f9 into main Jan 17, 2026
3 checks passed
@ArgoZhang ArgoZhang deleted the copilot/refactor-circles-example-component branch January 17, 2026 05:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

doc(AttributeTable): auto generate AttributeTable content

2 participants