摆脱HttpContext依赖 - 我可以使用线程存储

时间:2015-12-07 17:07:00

标签: c# multithreading asp.net-web-api2

我正在编写使用大量遗留组件的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)。我担心的是线程安全 - 我可以像这样使用它而没有任何令人讨厌的副作用吗?

0 个答案:

没有答案