Mon code fonctionne correctement lorsqu'il est exécuté de manière synchrone, mais échoue lorsqu'il est déclenché via QueueBackgroundWorkItem. MISE À JOUR: le problème semble provenir du gestionnaire de module dynamique Sitefinity que j'utilise et qui nécessite un contexte HTTP dans le thread créé par QueueBackgroundWorkItem. Il s'agit donc d'une question spécifique à Sitefinity. Je l'ai trouvé un article qui semble pointer vers une solution: http://www.sitefinity.com/developer-network/forums/sitefinity-sdk/errors-with-managers-when-multi-threading.ToList sur IQueryable provoque NullReferenceException lorsqu'il est exécuté en arrière-plan
parties pertinentes de mon code
action ApiController qui commence tâche de fond:
// 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();
}
classe DataSync:
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
}
}
La fonction CacheModuleData() dans la classe ci-dessous est l'endroit où l'exception se produit:
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
}
Trace de la pile:
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:
est-il tout ce que je peux ajouter qui rendrait la question plus compréhensible ou utile aux autres? Je réalise que c'est une question plutôt spécifique, mais j'aimerais en faire une question qui pourrait aider les autres dans des situations similaires. – jmotes
pourquoi ne pas simplement vérifier si 'moduleItems' est null? Cela ressemble à une question sans question. – Hogan
@Hogan, ce serait une bonne idée - mais dans ce cas précis, il ne devrait pas être nul puisqu'il y a des éléments de module dans ma base de données et qu'il y a plus de 500 éléments quand ils ne sont pas déclenchés par le travail d'arrière-plan. – jmotes