C# .ToList on IQueryable在后台执行时会导致NullReferenceException

C# .ToList on IQueryable在后台执行时会导致NullReferenceException,c#,linq,sitefinity,asp.net-apicontroller,tolist,C#,Linq,Sitefinity,Asp.net Apicontroller,Tolist,我的代码在同步执行时工作正常,但在通过QueueBackgroundWorkItem触发时失败 更新:问题似乎与我正在使用的Sitefinity动态模块管理器有关,该管理器需要QueueBackgroundWorkItem创建的线程中的HTTP上下文,因此这是一个特定于Sitefinity的问题。我发现一篇文章似乎指向了一个解决方案: 我的代码的相关部分 启动后台作业的ApiController操作: // GET: api/Sync/MFP [HttpGet] public IHttpActi

我的代码在同步执行时工作正常,但在通过QueueBackgroundWorkItem触发时失败

更新:问题似乎与我正在使用的Sitefinity动态模块管理器有关,该管理器需要QueueBackgroundWorkItem创建的线程中的HTTP上下文,因此这是一个特定于Sitefinity的问题。我发现一篇文章似乎指向了一个解决方案:

我的代码的相关部分

启动后台作业的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();
}
//GET:api/Sync/MFP
[HttpGet]
公共IHttpActionResult MFP()
{
HostingEnvironment.QueueBackgroundWorkItem(ct=>startMFPSync());
返回Ok(“同步已启动!”);
}
私有void startMFPSync()
{
var sourcesConfig=Config.Get();
MFPApi api=新MFPApi(新MFPConfig
{
Url=sourcesConfig.MFPUrl,
Key=sourcesConfig.MFPKey,
密码=sourcesConfig.MFPPassword,
});
DataSync DataSync=新的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
    }
}
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);
}
公共类数据同步
{
IDataSource数据源;
公共数据同步(IDataSource源)
{
数据源=源;
}
public void RunSync()
{
dataSource.GetResponse();
List dataToSync=dataSource.GetDataForSync();
SFDynamicModuleSync destinationSync=新的SFDynamicModuleSync(dataToSync);
//发生异常的函数调用
destinationSync.CacheModuleData();
//其他同步操作
}
}
下面类中的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 
}
公共类SFDynamicModuleSync:IDataDestinationSync
{
/// 
///要同步的SyncContent对象列表
/// 
私有列表数据同步;
/// 
///用于存储CacheModuleData的结果
/// 
私有列表模块项;
/// 
///Sitefinity动态模块管理器
/// 
私有DynamicModuleManager DynamicModuleManager;
/// 
///初始化类的新实例
/// 
///要同步的SyncContent对象列表
公共SFDynamicModuleSync(列表数据同步)
{
this.dataToSync=dataToSync;
this.moduleItems=新列表();
this.dynamicModuleManager=dynamicModuleManager.GetManager();
}
/// 
///从动态模块中检索所有数据,并将其放置在ModuleItems中
/// 
public void CacheModuleData()
{
foreach(this.dataToSync.Select(e=>e.ContentTypeName)中的字符串contentType)
{
Type Type=TypeResolutionService.ResolveType(contentType);
IQueryable moduleItems=this.dynamicModuleManager.GetDataItems(类型)
.Where(i=>i.Status==ContentLifecycleStatus.Master);
if(moduleItems!=null)
{
//当后台作业触发代码时,此处的.ToList()会导致NullReferenceException
List moduleItemsList=moduleItems.ToList();
this.moduleItems.Add(moduleItemsList);
}
}
}
//其他同步方法-此处不包括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: 
System.NullReferenceException未由用户代码处理
HResult=-2147467261
Message=对象引用未设置为对象的实例。
Source=Unity\u ILEmit\u dynamicclass
堆栈跟踪:
在DynamicModule.ns.Wrapped_openaccess dynamicmoduleprovider_81d3fcbe95dd4a47b8c1cb1cc5a692ab.应用过滤器(IDataItem项)
在Telerik.Sitefinity.Security.FieldsPermissionsApplierEnumerator`1.Demand(T for Item)
在Telerik.Sitefinity.Security.PermissionApplierEnumeratorBase`1.MoveNext()
在Telerik.Sitefinity.Data.Linq.DataItemEnumerator`1.MoveNext()中
位于System.Collections.Generic.List`1..ctor(IEnumerable`1集合)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
在C:\Projects\SIEQ\TeamSI.Sitefinity.DataSync\DataDestinations\SFDynamicModuleSync.CacheModuleData()中的TeamSI.Sitefinity.DataSync.DataDestinations.SFDynamicModuleSync.CacheModuleData()处:第75行
在C:\Projects\SIEQ\TeamSI.Sitefinity.DataSync\DataSync.cs中的TeamSI.Sitefinity.DataSync.DataSync.RunSync()处:第28行
在C:\Projects\SIEQ\Main\u Site\Mvc\Controllers\SyncController.cs中的SitefinityWebApp.Mvc.Controllers.SyncController.startMFPSync()处:第72行
在C:\Projects\SIEQ\Main\u Site\Mvc\Controllers\SyncController.b\uu 1\u 0(CancellationToken ct)中的SitefinityWebApp.Mvc.Controllers.SyncController.cs:第52行
在System.Web.Hosting.HostingEnvironment.c\uuu DisplayClass91\u0.b\u0(CancellationToken ct)
在System.Web.Hosting.BackgroundWorkScheduler.d_u7.MoveNext()中
内部异常:

事实证明,这是Sitefinity CMS的一个问题,我正在查询需要HTTP上下文的数据,这当然在线程中丢失了。在dynamicModuleManager.GetDataItems()方法中发生NullReferenceException

在朋友和了不起的SO贡献者的帮助下,包括@Igor、@Hogan、@PeterBons和@daramasala,他们帮助我理解了这个问题,我通过提高SF的权限并在线程中模拟HttpContext解决了这个问题

使用此方法,我只能在论坛之外找到SF文档:

更新了我的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
    }
}
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);
}
public void RunSync()
{
SystemManager.RunWithLevelatedPrivilegeDelegate worker=新系统管理员。RunWithLevelatedPrivilegeDelegate(args=>{
dataSource.GetResponse();
List dataToSync=dataSource.GetDataForSync();
var destinationSync=新的SFDynamicModuleSync(dataToSync);
destinationSync.CacheModuleData();
//完成每种内容类型的同步操作
for(int i=0;i