Modify each string property in flat object, complex object, list, etc

232 Views Asked by At

I need to write a generic method that will take any object, loop over its values, and, for each string, modify it (HtmlEncode it in this case). (this need to execute on all objects submitted to my.net 4.7 API controllers)

So I created an ActionFilterAttribute, and added it to my global filters, and it works fine on "flat" objects.

However, the object can be something like an object with an IList member (each of which will need to be modified) or a nested object/s with its own string properties.

Anyone done anything like this? Got like 10 commented out failed experiments. lol

public override void OnActionExecuting(HttpActionContext actionContext)
{
    // Decode strings from PUT or POST requests
    if (actionContext.Request.Method.ToString() == WebRequestMethods.Http.Post
        || actionContext.Request.Method.ToString() == WebRequestMethods.Http.Put)
    {
        // For each of the items in the PUT/POST
        foreach (var item in actionContext.ActionArguments.Values)
        {
            try
            {
                var type = item.GetType();

                // For each property of this object, html decode it if it is of type string
                foreach (PropertyInfo propertyInfo in type.GetProperties())
                {
                    var prop = propertyInfo.GetValue(item);
                    if (prop is string str)
                    {
                        propertyInfo.SetValue(item, WebUtility.HtmlEncode(str));
                    }
                }
            }
            catch (Exception)
            {
                // ignored
            }
        }
    }
    base.OnActionExecuting(actionContext);
}

UPDATE:

Currently testing this: update: no good...an Int will be identified as 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);
                    }
                }
            }
        }
0

There are 0 best solutions below