Reputation: 11
Error : If the event originated on another computer, the display information had to be saved with the event.
The following information was included with the event:
Object reference not set to an instance of an object. at System.Data.Objects.ObjectStateManager.DetectConflicts(IList
1 entries) at System.Data.Objects.ObjectStateManager.DetectChanges() at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force) at System.Data.Entity.Internal.Linq.InternalSet
1.ActOnSet(Action action, EntityState newState, Object entity, String methodName) at System.Data.Entity.Internal.Linq.InternalSet1.Add(Object entity)
1.Add(TEntity entity) at ESHealthCheckService.BusinessFacade.BusinessOperationsLayer.AddErrorToDbObject(Exception ex, Server serverObj, Service windowsServiceObj)
at System.Data.Entity.DbSet
the message resource is present but the message is not found in the string/message table
public void CheckForServerHealth()
{
businessLayerObj.SetStartTimeWindowsService();
List<ServerMonitor> serverMonitorList = new List<ServerMonitor>();
serverList = businessLayerObj.GetServerList();
Parallel.ForEach(
serverList,
() => new List<ServerMonitor>(),
(server, loop, localState) =>
{
localState.Add(serverStatus(server, new ServerMonitor()));
return localState;
},
localState =>
{
lock (serverMonitorList)
{
foreach (ServerMonitor serverMonitor in localState)
{
serverMonitorList.Add(serverMonitor);
}
}
});
businessLayerObj.SaveServerHealth(serverMonitorList);
}
public ServerMonitor serverStatus(Server serverObj, ServerMonitor serverMonitorObj)
{
if (new Ping().Send(serverObj.ServerName, 30).Status == IPStatus.Success)
{
serverMonitorObj.Status = true;
try
{
PerformanceCounter cpu = new PerformanceCounter("Processor", "% Processor Time", "_Total", serverObj.ServerName);
serverMonitorObj.CPUUtlilization = (cpu.NextValue());
}
catch (Exception ex)
{
businessLayerObj.AddErrorObjectToStaticList(ex, serverObj);
}
serverMonitorObj.ServerID = serverObj.ServerID;
try
{
string[] diskArray = serverObj.DriveMonitor.ToString().Split(':');
if (diskArray != null && diskArray.Contains("NA"))
{
serverMonitorObj.DiskSpace = "NA";
}
else
{
serverMonitorObj.DiskSpace = ReadFreeSpaceOnNetworkDrives(serverObj.ServerName, diskArray);
}
}
catch (Exception ex)
{
businessLayerObj.AddErrorObjectToStaticList(ex, serverObj);
}
serverMonitorObj.CreatedDateTime = DateTime.Now;
}
else
{
serverMonitorObj.Status = false;
serverMonitorObj.ServerID = serverObj.ServerID;
//return serverMonitorObj;
}
return serverMonitorObj;
}
public void AddErrorObjectToStaticList(Exception ex, Server serverObj = null, Service windowsServiceObj = null)
{
EShelathLoging esLogger = new EShelathLoging();
esLogger.CreateDatetime = DateTime.Now;
if (ex.InnerException != null)
{
esLogger.Message = (windowsServiceObj == null ? ex.InnerException.Message : ("Service Name : " + windowsServiceObj.ServiceName + "-->" + ex.InnerException.Message));
//esLogger.Message = "Service Name : " + windowsServiceObj.ServiceName + "-->" + ex.InnerException.Message;
esLogger.StackTrace = (ex.InnerException.StackTrace == null ? "" : ex.InnerException.StackTrace);
}
else
{
esLogger.Message = (windowsServiceObj == null ? ex.Message : ("Service Name : " + windowsServiceObj.ServiceName + "-->" + ex.Message));
//esLogger.Message = "Service Name : " + windowsServiceObj.ServiceName + "-->" + ex.Message;
esLogger.StackTrace = ex.StackTrace;
}
if (serverObj != null)
{
esLogger.ServerName = serverObj.ServerName;
}
try
{
lock (lockObject)
{
esHealthCheckLoggingList.Add(esLogger);
}
}
catch (Exception exe)
{
string logEntry = "Application";
if (EventLog.SourceExists(logEntry) == false)
{
EventLog.CreateEventSource(logEntry, "Windows and IIS health check Log");
}
EventLog eventLog = new EventLog();
eventLog.Source = logEntry;
eventLog.WriteEntry(exe.Message + " " + exe.StackTrace, EventLogEntryType.Error);
}
}
And then the below function is called to add objects from static list to the db object.
public void AddErrorToDbObject() { try { foreach (EShelathLoging eslogObject in esHealthCheckLoggingList) { lock (lockObject) { dbObject.EShelathLogings.Add(eslogObject); } } } catch (DbEntityValidationException exp) { string logEntry = "Application";
if (EventLog.SourceExists(logEntry) == false)
{
EventLog.CreateEventSource(logEntry, "Windows and IIS health check Log");
}
EventLog eventLog = new EventLog();
eventLog.Source = logEntry;
eventLog.WriteEntry(exp.Message + " " + exp.StackTrace, EventLogEntryType.Error);
}
catch (Exception exe)
{
string logEntry = "Application";
if (EventLog.SourceExists(logEntry) == false)
{
EventLog.CreateEventSource(logEntry, "Windows and IIS health check Log");
}
EventLog eventLog = new EventLog();
eventLog.Source = logEntry;
eventLog.WriteEntry(exe.Message + " " + exe.StackTrace, EventLogEntryType.Error);
}`enter code here`
}
Upvotes: 1
Views: 768
Reputation: 7676
Please note that I received the same exception with the application I was working on, and determined that the best way to resolve the issue was to add an AsyncLock, because of what @svick mentioned about how DbSet is not threadsafe. Thank you, @svick!
I'm guessing that your DbContext is inside your businessLayerObj, so here is what I recommend, using Stephen Cleary's excellent Nito.AsyncEx (see https://www.nuget.org/packages/Nito.AsyncEx/):
using Nito.AsyncEx;
// ...
private readonly AsyncLock _dbContextMutex = new AsyncLock();
public void CheckForServerHealth()
{
using (await _dbContextMutex.LockAsync().ConfigureAwait(false))
{
await MyDbContextOperations(businessLayerObj).ConfigureAwait(false);
}
}
private async Task MyDbContextOperations(BusinessLayerClass businessLayerObj)
{
await Task.Run(() =>
{
// operations with businessLayerObj/dbcontext here...
});
}
Upvotes: 0
Reputation: 244767
DbSet<T>
is not thread-safe, so you can't use it from multiple threads at the same time. It seems you're trying to fix that by using a lock
, but you're doing that incorrectly. For this to work, all threads have to share a single lock object. Having separate lock object for each thread, like you do now, won't do anything.
Upvotes: 1