The only thing I can think of is a race condition but both the calling function and the line of code are synchronous to my knowledge.
/// <summary>
/// Gets the log format string for an info-level log.
/// </summary>
public static string Info<T>(string action, T obj)
{
var stringBuilder = new StringBuilder(String.Format(
"Action: {0} \tObject: {1} \tUser: {2} \tJson: ",
action, typeof(T).Name, User
));
// Set all virtual properties to null. This should stop circular references of navigation properties.
var virtualProperties = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(x => x.GetSetMethod().IsVirtual && !x.PropertyType.IsPrimitive);
foreach (var propInfo in virtualProperties)
{
propInfo.SetValue(obj, null); // This Line is the culprit.
}
GetJsonSerializer().Serialize(obj, stringBuilder);
return stringBuilder.ToString();
}
The line propInfo.SetValue(obj, null)
will execute if I just breakpoint before the loop and step through one-by-one (or just break on that line) however if I don't use a breakpoint it never sets the property(ies) to null. Why is this?
Specific Details:
propInfo.SetValue(obj, null);
it does work.null
to 5
(which isn't a valid value) it throws an exception telling my that it's not a valid value.To clarify, "Doesn't work" means that it doesn't set the property to null.
What I've tried:
default(T)
)EDIT
It's been narrowed down that EF Navigation properties are the cause of this behavior. The code is running but for some reason the navigation properties refuse to become null. So what about navigation properties are causing this behavior?
Lazy-Loading
The navigation properties were lazy-loading, so when the serializer looked at them they got overwritten by the original value. So the setting of null was working the whole time but was getting overwritten by the lazy-loading.
Debugging
The reason the debugging appeared the way it did was because I was looking at the value before I executed the SetValue line of code. This caused the navigation property to load the value before executing the line of code resulting in the null value not being overwritten.
Solution
foreach (var propInfo in virtualProperties)
{
propInfo.GetValue(obj); // Trigger any navigation property to load.
propInfo.SetValue(obj, null);
}
I had a VERY similar issue in a Many-to-many EF6 code first setup. In my Web API controller I had been setting an object's navigation property from values set from a DTO. One being passed into my repo, they properties weren't being updated because of the lazy loading, but in debug mode it would work if I stepped near that section of code. I ended up using:
try {
TheDatabase.Configuration.LazyLoadingEnabled = false;
...
...
}
finally {
TheDatabase.Configuration.LazyLoadingEnabled = true;
}
This appears to be working so far.. Since my dbContext is being disposed per controller, I don't think it will be an issue.