为什么当前的ASP.NET MVC应用程序根虚拟路径在另一个线程/任务中不可用?

问题描述:

我最近的一个项目是根据一些提醒配置发送提醒电子邮件。电子邮件发送是通过使用Quartz.net.的异步作业实现的,它需要在应用程序中为实体包含永久链接。为什么当前的ASP.NET MVC应用程序根虚拟路径在另一个线程/任务中不可用?

但是,为了获得这个永久链接,我必须能够根据存储在作业队列中的标识符来计算完整的URL。答案并不简单,因为HttpContext在线程的上下文中不可用。

一种解决方案是将应用程序根路径存储在队列中并从那里使用它。另一种方法是使用一个函数如下所示:

public static String GetCurrentBasePath(String prefix = "http://") 
{ 
    return String.Format("{0}{1}{2}", 
     prefix,           // protocol 
     System.Net.Dns.GetHostEntry("").HostName,   // host 
     System.Web.HttpRuntime.AppDomainAppVirtualPath // virtual application path 
    ); 
} 

然而,这具有(重度)的限制,因为必须提供协议,并且还返回hostname,而不是domain name,从而使之无用具有多个时Web应用程序绑定到同一主机。

问题:在另一个线程/任务中是否可以使用Web应用程序的基本路径?。我认为其他线程/任务上下文以某种方式连接到ApplicationPool而不是WebApp,并且因为多个WebApp可以使用相同的ApplicationPool,所以在线程上下文和WebApp之间没有直接连接。

我不知道你是如何调用这个。但从我的经验来看,并行(如你所提到的)失去了HttpContext。也就是说,没有什么可以阻止你使用带有你需要的字符串值的配置变量。当然,取决于这个值如何动态化,这可能不是最佳的行动方案。但请记住,上面所做的计算很昂贵,所以请记住在本地存储值。

我相信这里的最佳解决方案(假设你知道上下文值,我不明白你为什么不能/不会)将设置一些变量并完全避免计算。

static readonly string hostName = "your-host"; 
static readonly string virtualPath = "your-virtual-path"; 
public static String GetCurrentBasePath(String prefix = "http://") 
{ 
    return String.Format("{0}{1}{2}", 
     prefix,           // protocol 
     hostName,   // host 
     virtualPath // virtual application path 
    ); 
} 
+0

我使用Quarz.net,但它使用一个新的线程,任务(TPL)或异步/ AWAIT是重复的。基本上,它在IIS中运行作业,而不是创建Windows服务或类似的东西。 – Alexei

+0

没错。正如我所说,对我来说,我认为如果你知道你想要计算的值是什么,我认为你最好将它们设置为内部只读值。为您提供线程安全并节省您的周期。 – pimbrouwers