我正在编写使用大量遗留组件的WEB API服务。遗留组件严重依赖于对ContextInfo.ContextID
的调用(这被引用为数十亿次)。
public static class ContextInfo
{
public static int ContextID
{
get { return (int)HttpContext.Current.Items["ContextID"]; }
}
}
// sample legacy class
public class Legacy
{
public void Foo()
{
if (ContextInfo.ContextID == 7)
{
Bar();
}
}
}
然后,每个旧版Web应用程序都会根据当前网址(域)和某些数据库设置初始化HttpContext.Current.Items
中的Application_BeginRequest
。
void Application_BeginRequest()
{
HttpContext.Current.Items["ContextID"] = QueryDb(HttpContext.Current.Request.Url);
}
我的网络API服务将具有“动态”上下文。即:
// sample web api method
void Get()
{
int contextID = GetContextBasedOnHttpHeader();
// Works but just icky
HttpContext.Current.Items["ContextID"] = context;
new Legacy().Foo();
}
依赖web api中的http上下文是错误的。另一方面,重写所有遗留组件以很好的方式注入contextID就是太多的工作。
我正在考虑滥用Thread.SetData
方法 - 即:
// sample web api method
void Get()
{
// filter would be better, but for simplicity sake
ContextInfo.ContextID = GetContextBasedOnHttpHeader();
new Legacy().Foo();
}
并将ContextInfo
重写为以下内容:
public interface IContextInfoProvider { int ContextID { get; set; } }
public class LegacyContextInfoProvider : IContextInfoProvider { ... }
public static class ContextInfo
{
public static IContextInfoProvider Provider = new LegacyContextInfoProvider();
public static int ContextID
{
return Provider.ContextID;
}
}
public class WebApiContextInfoProvider : IContextInfoProvider
{
public int ContextID {
get { return (int)Thread.GetData(Thread.AllocateNamedDataSlot("ContextID")); }
set { Thread.SetData(Thread.AllocateNamedDataSlot("ContextID"), value);
}
}
// on startup
ContextInfo.Provider = new WebApiContextInfoProvider();
我们还可以假设遗留组件将在同一个线程中运行(因为一旦你解雇了新线程就无法引用HttpContext.Current.Items
- 它将为null)。我担心的是线程安全 - 我可以像这样使用它而没有任何令人讨厌的副作用吗?