Question

In my mvc project I put together an action filter that takes the model, traverses the object graph and modifies all of the date time objects. My current code (within the last else block) is throwing a stackoverflow exception.

One of the properties in my model is an EF object with navigation properties and this should be ignoring properties that don't have a value or are a primitive, string, enum etc. Basically any type that doesn't have child properties of datetime.

    private void ProcessDateTimeProperties(object obj, ActionExecutedContext filterContext)
    {
        var properties = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);

        foreach (var property in properties)
        {
            var t = property.PropertyType;
            if (t.IsPrimitive || t == typeof(string) || t == typeof(Enum))
                continue;

            var p = property;
            if (p.PropertyType == typeof(DateTime))
            {
                var date = (DateTime)p.GetValue(obj, null);
                date.AddMinutes((int)filterContext.HttpContext.Cache["offset"]);
                p.SetValue(obj, date, null);
            }
            // Same check for nullable DateTime.
            else if (p.PropertyType == typeof(Nullable<DateTime>))
            {
                var date = (DateTime?)p.GetValue(obj, null);
                if (!date.HasValue) continue; ;

                date.Value.AddMinutes((int)filterContext.HttpContext.Cache["offset"]);
                p.SetValue(obj, date, null);
            }
            else
            {
                var v = property.GetValue(obj, null);
                if (v != null)
                    ProcessDateTimeProperties(v, filterContext);
            }
        }
    }

No correct solution

OTHER TIPS

The problem you have is circular reference.

You can solve your problem marking all the complex objects you already checked. like this:


private void ProcessDateTimeProperties(object obj, ActionExecutedContext filterContext, HashSet<object> processedObjects = null)
    {
        if (processedObjects == null)
            processedObjects = new HashSet<object>();

        if (processObjects.Contains(obj))
            return;

        processedObjects.Add(obj);

        var properties = obj.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);

        foreach (var property in properties)
        {
            var t = property.PropertyType;
            if (t.IsPrimitive || t == typeof(string) || t == typeof(Enum))
                continue;

            var p = property;
            if (p.PropertyType == typeof(DateTime))
            {
                var date = (DateTime)p.GetValue(obj, null);
                date.AddMinutes((int)filterContext.HttpContext.Cache["offset"]);
                p.SetValue(obj, date, null);
            }
            // Same check for nullable DateTime.
            else if (p.PropertyType == typeof(Nullable))
            {
                var date = (DateTime?)p.GetValue(obj, null);
                if (!date.HasValue) continue; ;

                date.Value.AddMinutes((int)filterContext.HttpContext.Cache["offset"]);
                p.SetValue(obj, date, null);
            }
            else
            {
                var v = property.GetValue(obj, null);
                if (v != null)
                    ProcessDateTimeProperties(v, filterContext, processedObjects);
            }
        }
    }

As you can see I'm adding the processedObjects optional parameter to the function to mark the objects that were already passed to the recursive function.

When you call the function you don't have to pass this parameter, it will be created inside the function and passed recursively.

Hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top