2017-01-07 15 views
1

동기식으로 실행하면 내 코드가 제대로 작동하지만 QueueBackgroundWorkItem을 통해 트리거되면 오류가 발생합니다.IQueryable에 대한 ToList는 백그라운드에서 실행될 때 NullReferenceException을 발생시킵니다.

업데이트 :이 문제는 Sitefinity 동적 모듈 관리자와 관련이있는 것으로 보입니다. QueueBackgroundWorkItem에 의해 생성 된 스레드 내에서 HTTP 컨텍스트가 필요하므로이 사이트는 Sitefinity 관련 질문입니다. 나는 해결책을 가리 키도록 보인다 기사를 발견했습니다 내 코드의 http://www.sitefinity.com/developer-network/forums/sitefinity-sdk/errors-with-managers-when-multi-threading

관련 부분을

백그라운드 작업 시작

ApiController 액션 :

// GET: api/Sync/MFP 
[HttpGet] 
public IHttpActionResult MFP() 
{ 
    HostingEnvironment.QueueBackgroundWorkItem(ct => startMFPSync()); 
    return Ok("Sync Started!"); 
} 

private void startMFPSync() 
{ 
    var sourcesConfig = Config.Get<SyncSourcesSettingsConfig>(); 

    MFPApi api = new MFPApi(new MFPConfig 
    { 
     Url = sourcesConfig.MFPUrl, 
     Key = sourcesConfig.MFPKey, 
     Password = sourcesConfig.MFPPassword, 
    }); 

    DataSync dataSync = new DataSync(api); 
    dataSync.RunSync(); 
} 

데이터 싱크 클래스 :

public class DataSync 
{ 
    IDataSource dataSource; 

    public DataSync(IDataSource source) 
    { 
     dataSource = source; 
    } 

    public void RunSync() 
    { 
     dataSource.GetResponse(); 

     List<SyncContent> dataToSync = dataSource.GetDataForSync(); 
     SFDynamicModuleSync destinationSync = new SFDynamicModuleSync(dataToSync); 

     // function call where exception occurs 
     destinationSync.CacheModuleData(); 

     // other sync operations 
    } 
} 

아래 클래스의 CacheModuleData() 함수는 예외가 발생하는 곳입니다 :

public class SFDynamicModuleSync : IDataDestinationSync 
{ 
    /// <summary> 
    /// List of SyncContent objects to sync 
    /// </summary> 
    private List<SyncContent> dataToSync; 

    /// <summary> 
    /// Used to store results of CacheModuleData 
    /// </summary> 
    private List<List<DynamicContent>> modulesItems; 

    /// <summary> 
    /// Sitefinity dynamic module manager 
    /// </summary> 
    private DynamicModuleManager dynamicModuleManager; 

    /// <summary> 
    /// Initializes a new instance of the <see cref="SFDynamicModuleSync"/> class 
    /// </summary> 
    /// <param name="dataToSync">List of SyncContent objects to sync</param> 
    public SFDynamicModuleSync(List<SyncContent> dataToSync) 
    { 
     this.dataToSync = dataToSync; 
     this.modulesItems = new List<List<DynamicContent>>(); 
     this.dynamicModuleManager = DynamicModuleManager.GetManager(); 
    } 

    /// <summary> 
    /// Retrieves all data from dynamic modules and places in modulesItems 
    /// </summary> 
    public void CacheModuleData() 
    { 
     foreach (string contentType in this.dataToSync.Select(e => e.ContentTypeName)) 
     { 
      Type type = TypeResolutionService.ResolveType(contentType); 

      IQueryable<DynamicContent> moduleItems = this.dynamicModuleManager.GetDataItems(type) 
       .Where(i => i.Status == ContentLifecycleStatus.Master); 

      if(moduleItems != null) 
      { 
       // The .ToList() here causes a NullReferenceException when code is triggered by background job 
       List<DynamicContent> moduleItemsList = moduleItems.ToList(); 
       this.modulesItems.Add(moduleItemsList); 
      } 
     } 
    } 

    // other sync methods - not included here for abbrevity 
} 

스택 추적 :

System.NullReferenceException was unhandled by user code 
    HResult=-2147467261 
    Message=Object reference not set to an instance of an object. 
    Source=Unity_ILEmit_DynamicClasses 
    StackTrace: 
     at DynamicModule.ns.Wrapped_OpenAccessDynamicModuleProvider_81d3fcbe95dd4a47b8c1cb1cc5a692ab.ApplyFilters(IDataItem item) 
     at Telerik.Sitefinity.Security.FieldsPermissionsApplierEnumerator`1.Demand(T forItem) 
     at Telerik.Sitefinity.Security.PermissionApplierEnumeratorBase`1.MoveNext() 
     at Telerik.Sitefinity.Data.Linq.DataItemEnumerator`1.MoveNext() 
     at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) 
     at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) 
     at TeamSI.Sitefinity.DataSync.DataDestinations.SFDynamicModuleSync.CacheModuleData() in C:\Projects\SIEQ\TeamSI.Sitefinity.DataSync\DataDestinations\SFDynamicModuleSync.cs:line 75 
     at TeamSI.Sitefinity.DataSync.DataSync.RunSync() in C:\Projects\SIEQ\TeamSI.Sitefinity.DataSync\DataSync.cs:line 28 
     at SitefinityWebApp.Mvc.Controllers.SyncController.startMFPSync() in C:\Projects\SIEQ\Main_Site\Mvc\Controllers\SyncController.cs:line 72 
     at SitefinityWebApp.Mvc.Controllers.SyncController.<MFP>b__1_0(CancellationToken ct) in C:\Projects\SIEQ\Main_Site\Mvc\Controllers\SyncController.cs:line 52 
     at System.Web.Hosting.HostingEnvironment.<>c__DisplayClass91_0.<QueueBackgroundWorkItem>b__0(CancellationToken ct) 
     at System.Web.Hosting.BackgroundWorkScheduler.<RunWorkItemImpl>d__7.MoveNext() 
    InnerException: 
+0

인가가 내가 추가 할 수있는 것이 있다면 질문을 다른 사람들에게 더 이해할 수있게하거나 도움이 될 수 있을까요? 그것은 다소 구체적인 질문이지만, 유사한 상황에서 다른 사람들을 도울 수있는 질문으로 만들고 싶습니다. – jmotes

+0

왜 'moduleItems'가 null인지 확인하지 않는 이유는 무엇입니까? 질문이 아닌 질문처럼 보입니다. – Hogan

+0

@Hogan, 좋은 생각입니다. 그러나이 특별한 경우에는 데이터베이스에 모듈 항목이 있고 백그라운드 작업에 의해 트리거되지 않을 때 500 개 이상의 항목이 있으므로 null이 아니어야합니다. – jmotes

답변

1

이 내가 스레드 내에서 손실 물론이다 HTTP 컨텍스트를 필요로하는 데이터를 쿼리 된 Sitefinity CMS에 문제가 있었다 밝혀졌습니다. dynamicModuleManager.GetDataItems() 메서드 내에서 NullReferenceException이 발생했습니다.

@Igor, @Hogan, @PeterBons 및 @daramasala를 포함한 친구들로부터 멋진 도움을 받아 문제점을 이해하는 데 도움을주었습니다. SF로 권한을 부여하고 스레드 내에서 HttpContext를 시뮬레이션함으로써 문제를 해결할 수있었습니다. 나는이 방법을 사용하여 찾을 수있는 포럼의 외부

http://www.sitefinity.com/developer-network/forums/sitefinity-sdk/errors-with-managers-when-multi-threading

만 SF 설명서는 여기에 있습니다 : 는 http://docs.sitefinity.com/bug-tracker-create-the-savebug-action

내 데이터 싱크 클래스의

업데이트 RunSync() 메소드 :

public void RunSync() 
{ 
    SystemManager.RunWithElevatedPrivilegeDelegate worker = new SystemManager.RunWithElevatedPrivilegeDelegate(args => { 

     dataSource.GetResponse(); 
     List<SyncContent> dataToSync = dataSource.GetDataForSync(); 
     var destinationSync = new SFDynamicModuleSync(dataToSync); 

     destinationSync.CacheModuleData(); 

     // complete sync operations for each content type 
     for (int i = 0; i < dataToSync.Count; i++) 
     { 
      destinationSync.DeleteOldItems(i); 
      destinationSync.AddItems(i); 
      destinationSync.UpdateItems(i); 
     } 
    }); 

    SystemManager.RunWithElevatedPrivilege(worker); 
}