0

錯誤所謂的DbContext對象: 如果該事件源於另一臺計算機上,顯示信息必須與事件被保存。錯誤,同時增加實體對象從Parallel.Foreach循環

下面的信息包括與所述事件:

對象引用不設置爲一個對象的一個​​實例。在在 System.Data.Entity.Internal.Linq.InternalSet 1.Add(Object entity)
at System.Data.Entity.DbSet
1.增加 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(行動行動, EntityState newState,對象實體,字符串方法名)(TEntity實體)在 ESHealthCheckService.BusinessFacade.BusinessOperationsLayer.AddErrorToDbObject(例外 前,服務器serverObj,服務windowsServiceObj)

消息資源存在,但該消息未在串/消息表中找到

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); 
      } 
     } 

然後調用下面的函數將對象從靜態列表添加到數據庫對象。

公共無效AddErrorToDbObject() { 嘗試 { 的foreach(EShelathLoging eslogObject在esHealthCheckLoggingList) { 鎖(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` 

    } 
+0

你是如何調用此方法?我沒有看到'Parallel.ForEach'? – 2014-10-01 17:14:26

+0

這個函數是從一個在Parallel.Foreach循環中調用的方法調用的,即在一個多線程環境中...... – Harry 2014-10-01 17:51:56

+0

當你在共享上下文中使用鎖定時,沒有必要使用'Parallel.ForEach'。另外,你使用'lock'語句錯誤。 – 2014-10-01 18:50:07

回答

1

DbSet<T>不是線程安全的,所以在同一時間,你不能從多個線程中使用它。看起來你試圖通過使用lock來解決這個問題,但是你做得不正確。爲此,所有線程必須共享一個鎖對象。爲每個線程設置單獨的鎖定對象,就像現在一樣,不會執行任何操作。

+0

感謝您的點...你plesae讓我知道如何做到這一點,我在多線程環境中的鎖真的很困惑...... – Harry 2014-10-01 18:10:13

+0

@Harry嗯,這很難說沒有看到你的'Parallel.ForEach( )'代碼或更多你的代碼。但通常情況下,鎖對象應該是你的線程不安全的對象(我假設它是一個實例字段),或者,甚至更好的,它應該是線程不安全的對象本身(即'lock(dbObject) ')。 – svick 2014-10-01 18:17:09

+0

啊!是的,我錯過了鎖的基本目的..它可能會減慢我的線程,但再次感謝指向正確的方向..我會嘗試... – Harry 2014-10-01 18:37:30

0

請注意,我收到了與我正在處理的應用程序相同的異常,並確定解決此問題的最佳方法是添加AsyncLock,因爲@svick提到了DbSet如何不是線程安全。謝謝@svick!

我猜你的DbContext是你businessLayerObj裏面,所以這裏是我的建議,用斯蒂芬·克利裏的優秀Nito.AsyncEx(見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... 
     }); 
}