-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Sometimes there's an exception thrown on first page request #7
Comments
I don't have the project running anywhere to test. But bear with me. Our stack trace looks like: 51612 2017:03:29 03:27:02 ERROR System.NullReferenceException: Object reference not set to an instance of an object. The exception is thrown in MapModelProperties, seems to be as it tries to use the modelMeta.PropertyMap When the modelMeta is created I think there is a race. private ModelMeta EnsureModelDictionaryEntryExists<TModel>(IDictionary<string, ModelMeta> metadataDictionary)
{
var modelType = typeof(TModel);
var modelMetaKey = modelType.AssemblyQualifiedName;
*** HERE IT IS NULL - the default ***
var modelMeta = default(ModelMeta);
*** 1st request this is false
*** 2nd request this is still false, 1st request is still busy in the lock below
if (metadataDictionary.ContainsKey(modelMetaKey))
{
modelMeta = metadataDictionary[modelMetaKey];
}
else
{
lock (MetaSyncRoot)
{
*** 1st request this is true
*** 2nd request this is now false, as we had to wait for the lock
if (!metadataDictionary.ContainsKey(modelMetaKey))
{
modelMeta = new ModelMeta();
var propertyMetaBuilder = new PropertyMetaBuilder();
modelMeta.PropertyMap = propertyMetaBuilder.BuildPropertyMetaMap<TModel>();
metadataDictionary.Add(modelMetaKey, modelMeta);
}
}
}
*** 1st request is OK
*** 2nd request is null :disappointed:
return modelMeta;
} If we move the declarations closer to where they are used: private ModelMeta EnsureModelDictionaryEntryExists<TModel>(IDictionary<string, ModelMeta> metadataDictionary)
{
// check first to avoid locking, can you use TryGetValue instead? Avoid having to lookup twice.
// https://msdn.microsoft.com/en-us/library/bb347013(v=vs.110).aspx
if (metadataDictionary.ContainsKey(modelMetaKey))
{
return metadataDictionary[modelMetaKey];
}
lock (MetaSyncRoot)
{
if (!metadataDictionary.ContainsKey(modelMetaKey))
{
var modelType = typeof(TModel);
var modelMetaKey = modelType.AssemblyQualifiedName;
var modelMeta = new ModelMeta();
var propertyMetaBuilder = new PropertyMetaBuilder();
modelMeta.PropertyMap = propertyMetaBuilder.BuildPropertyMetaMap<TModel>();
metadataDictionary.Add(modelMetaKey, modelMeta);
return modelMeta;
}
}
return metadataDictionary[modelMetaKey];
} If/When I get time I'll try actually test this and get a PR together |
I think I can reproduce this. In the EnsureModelDictionaryEntryExists method, add a Thread.Sleep(1000) inside the lock. I pretty reliably get a null reference exception then. |
|
You are a living legend @benmcevoy. Let me know if you want to patch it yourself, or send me the fix I can create a PR from my fork :P |
Fix looks great, thanks @benmcevoy! PR has been merged in and I no longer get the exception. |
(placeholder - detail to be added)
The text was updated successfully, but these errors were encountered: