You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 4.7 API通用字符串HTML编码方法实现求助

解决.NET 4.7 API中全局HtmlEncode所有提交对象字符串的问题

需要实现一个通用方法,能接收任意对象并遍历其所有值,对每个字符串执行HtmlEncode操作,且该方法要作用于提交到.NET 4.7 API控制器的所有对象。已创建ActionFilterAttribute并添加到全局过滤器,处理“扁平”对象正常,但无法处理包含IList成员或带字符串属性的嵌套对象的复杂结构,多次尝试未解决。

现有初始代码

public override void OnActionExecuting(HttpActionContext actionContext)
{
    // 对PUT或POST请求中的字符串进行编码
    if (actionContext.Request.Method.ToString() == WebRequestMethods.Http.Post
        || actionContext.Request.Method.ToString() == WebRequestMethods.Http.Put)
    {
        // 遍历PUT/POST中的每个参数
        foreach (var item in actionContext.ActionArguments.Values)
        {
            try
            {
                var type = item.GetType();

                // 遍历对象的每个属性,如果是字符串则执行HtmlEncode
                foreach (PropertyInfo propertyInfo in type.GetProperties())
                {
                    var prop = propertyInfo.GetValue(item);
                    if (prop is string str)
                    {
                        propertyInfo.SetValue(item, WebUtility.HtmlEncode(str));
                    }
                }
            }
            catch (Exception)
            {
                // 忽略异常
            }
        }
    }
    base.OnActionExecuting(actionContext);
}

存在问题的测试代码

该代码会将Int类型识别为Object,导致错误递归:

public class HttpStringDecodeFilter : ActionFilterAttribute
{
    private void HtmlEncodeAllStringsInObject(Object obj)
    {
        var type = obj.GetType();
        var properties = type.GetProperties();
        foreach (var property in properties)
        {
            var propValue = property.GetValue(obj);
            if (property.PropertyType.IsAssignableFrom(typeof(string)))
            {
                property.SetValue(obj, WebUtility.HtmlEncode(propValue?.ToString()));
            }
            else if (property.PropertyType.IsGenericType && property.PropertyType.GetGenericTypeDefinition() == typeof(IList<>))
            {
                if (propValue is not List<string> list) continue;
                for (var i = 0; i < list.Count; i++)
                {
                    list[i] = WebUtility.HtmlEncode(list[i]);
                }
                property.SetValue(obj, list);
            } else
            { 
                var typeCode = Type.GetTypeCode(property.PropertyType);
                if (typeCode.Equals(TypeCode.Object))
                {
                    HtmlEncodeAllStringsInObject(property);
                }
            }
        }
    }
}

修正后的完整实现

下面的代码解决了嵌套对象、泛型列表(包括非字符串元素的列表)、值类型误判的问题:

public class HtmlEncodeActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (actionContext.Request.Method == HttpMethod.Post || actionContext.Request.Method == HttpMethod.Put)
        {
            foreach (var argValue in actionContext.ActionArguments.Values)
            {
                if (argValue == null) continue;
                ProcessObject(argValue);
            }
        }
        base.OnActionExecuting(actionContext);
    }

    private void ProcessObject(object obj)
    {
        if (obj == null) return;
        
        var type = obj.GetType();
        
        // 处理泛型集合(IList<T>)
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(IList<>))
        {
            var list = (IEnumerable)obj;
            foreach (var item in list)
            {
                // 如果是字符串,直接编码并替换列表中的元素
                if (item is string str)
                {
                    var index = ((IList)obj).IndexOf(item);
                    ((IList)obj)[index] = WebUtility.HtmlEncode(str);
                }
                else
                {
                    // 非字符串元素,递归处理对象
                    ProcessObject(item);
                }
            }
            return;
        }
        
        // 处理值类型(除了字符串)和枚举,直接跳过
        if (type.IsValueType || type.IsEnum)
        {
            return;
        }
        
        // 处理嵌套对象的属性
        foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            if (!property.CanRead || !property.CanWrite) continue;
            
            var propValue = property.GetValue(obj);
            
            // 处理字符串属性
            if (property.PropertyType == typeof(string))
            {
                if (propValue is string strValue)
                {
                    property.SetValue(obj, WebUtility.HtmlEncode(strValue));
                }
                continue;
            }
            
            // 处理可空类型(比如int?),获取其底层值类型
            var underlyingType = Nullable.GetUnderlyingType(property.PropertyType);
            if (underlyingType != null && underlyingType.IsValueType)
            {
                continue;
            }
            
            // 递归处理嵌套对象或集合
            ProcessObject(propValue);
        }
    }
}

关键修复点

  • 集合处理优化:不再局限于List<string>,兼容所有IList<T>类型,遍历集合元素时,字符串直接编码替换,非字符串对象递归处理。
  • 值类型过滤:明确跳过值类型(字符串除外)和枚举,避免将int等值类型误判为Object触发无效递归。
  • 可空类型识别:处理Nullable<T>类型,跳过值类型的可空变体,防止不必要的递归操作。
  • 空值防护:全程增加空值判断,避免空引用异常。
  • 属性权限校验:仅处理可读可写的公共实例属性,避免操作只读或私有属性引发错误。

内容的提问来源于stack exchange,提问作者Nico

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 04:40:24