为什么HttpContext.Current为空?

67

我在应用程序中使用一个值; 我在 application_start 中设置它。

  void Application_Start(object sender, EventArgs e)
  {
    Dictionary<int, IList<string>> Panels = new Dictionary<int, IList<string>>();
    List<clsPanelSetting> setting = clsPanelSettingFactory.GetAll();
    foreach (clsPanelSetting panel in setting)
    {
        Panels.Add(panel.AdminId, new List<string>() { panel.Phone,panel.UserName,panel.Password});
    }
    Application["Setting"] = Panels;

    SmsSchedule we = new SmsSchedule();
    we.Run();

  }

并且在SmsSchedule中

public class SmsSchedule : ISchedule
{
    public void Run()
    {           
        DateTimeOffset startTime = DateBuilder.FutureDate(2, IntervalUnit.Second);
        IJobDetail job = JobBuilder.Create<SmsJob>()
            .WithIdentity("job1")
            .Build();

        ITrigger trigger = TriggerBuilder.Create()
             .WithIdentity("trigger1")
             .StartAt(startTime)
             .WithSimpleSchedule(x => x.WithIntervalInSeconds(60).RepeatForever())
             .Build();

        ISchedulerFactory sf = new StdSchedulerFactory();
        IScheduler sc = sf.GetScheduler();
        sc.ScheduleJob(job, trigger);

        sc.Start();
    }
}

我想在一个类中获取这个值。(smsjob)

   public class SmsJob : IJob 
   {  
      public virtual void Execute(IJobExecutionContext context)
      {
          HttpContext.Current.Application["Setting"]; 
      }
   }

但我的问题是:HttpContext.Current为空,为什么HttpContext.Current为空?

编辑: 当我在页面的另一个类中使用此代码时,它可以工作,但在这个类中我会出现错误。

6个回答

122
显然,只有在处理传入请求的线程中访问 HttpContext.Current 才不会为 null。 这就是为什么在“当我在页面的另一个类中使用此代码时”它可以工作的原因。

在与调度相关的类中,它将无法工作,因为相关代码未在有效线程上执行,而是在没有关联HTTP上下文的后台线程上执行。

总的来说,不要使用 Application["Setting"] 存储全局信息,因为它们并非像您发现的那样全局性。

如果需要将某些信息传递到业务逻辑层,请将其作为相关方法的参数传递。 不要让业务逻辑层访问诸如 HttpContextApplication["Settings"] 的东西,因为这违反了隔离和解耦原则。

更新: 由于引入了 async/await,此类问题更加常见,因此您可能需要考虑以下提示:

一般来说,您应该仅在少数情况下调用 HttpContext.Current(例如在 HTTP 模块内部)。 在所有其他情况下,您应该使用

而不是使用 HttpContext.Current


22
请注意,使用async/await关键字时,跟在await后面的代码行不一定是处理传入请求的同一线程。在第一个await之前引用HttpContext.Current,以确保避免出现NullReferenceException(我见过有些函数可以正常工作,有些则不行,因此保持一致性非常关键)。 - Tewr
@Lex Li 但是将Session存储在单例类中,不会让所有用户共享同一个会话吗? - nraina
1
有没有解决方案,Lex?我想在类库中访问当前用户。 - Akbari
1
@Lex Li,你有什么建议? - NinjaOnSafari
3
更加简洁明了一些。你使用了不必要的华丽语言,这反而掩盖了你的回答。 - Timothy Gonzalez
@Lex Li。如果您有一个组件可以在多个模块中注册用户操作,但希望使用单个ID记录此信息并进行跟踪,您将如何解决这个问题?假设我们当然有控制器和线程。问候 - Guillermo Varini

7
在IIS7的集成模式下,Application_Start中不可用Current。这里有一个类似的线程(链接)

6
尝试实现Application_AuthenticateRequest而不是Application_Start
Application_Start不同,此方法具有HttpContext.Current的实例(在应用程序生命周期的早期就会触发Application_Start,所以此时可能还没有HttpContext.Current对象)。
希望这能帮到您。

谢谢,但是当我在另一个类中使用这段代码时,我可以得到值,但在这个类中 HttpContext.Current 为空。 - ar.gorgin
1
就像我说的,所有的东西都是从Application_Start中调用的。将它移动到global.asax中的Application_AuthenticateRequest下面,它就可以工作了! - geevee
“Object reference not set to an instance of an object.” 对于 HttpContext.Current - ar.gorgin
让我们在聊天室中继续这个讨论 - geevee

1
如果您正在使用asp.net webforms应用程序,请尝试在web.config中添加此行,可能会对您有所帮助:
  <appSettings>
   <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>
</appSettings>

1
如果这是WCF服务,您可以在web.config文件中添加以下内容。
<configuration>
    <system.serviceModel>
        <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    </system.serviceModel>
</configuration>

一个布尔值,指示当前应用程序是否已打开ASP.NET兼容模式。默认值为false

当将此属性设置为true时,对Windows Communication Foundation (WCF)服务的请求将通过ASP.NET HTTP管道流动,并禁止在非HTTP协议上进行通信。


0
System.Web.Hosting.HostingEnvironment.MapPath("~/File"); 你可以通过使用来解决你的问题。

根据目前的写法,你的回答不够清晰。请编辑以添加更多细节,以帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - undefined
这并没有回答问题。一旦你拥有足够的声望,你就可以评论任何帖子;相反,提供不需要提问者澄清的答案。- 来自评论 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接