ServiceHosts,在上下文模式下创建Single
这是一个坏主意。集成页面 状态 :
的 提示:对所有WCF服务使用InstanceContextMode.PerCall。这可以防止任何难以检测到WCF服务超出单个请求所导致的问题。 强>
在为应用程序的某些部分提供上下文数据(例如受请求影响的连接字符串)时,有两种选择。你可以使用 环境状态 ,或者你用它 流 具有对象图的数据。
环境状态意味着您将数据存储在某个可用于特定上下文的可变状态中。以下是几个选项:
注意:对于这个答案,我假设 ISecurityContext 定义如下:
ISecurityContext
public interface ISecurityContext { public Database Database { get; } }
使用第三个选项,您可以实现您的 SecurityContext 如下:
SecurityContext
public sealed class SecurityContext : ISecurityContext { private static readonly AsyncLocal<Database> db = new AsyncLocal<Database>(); Database ISecurityContext.Database => db.Value; internal void SetDatabase(Database database) => db.Value = database; }
因为使用 System.Threading.AsyncLocal ,你可以重复使用同一个单一的 SecurityContext 整个申请中的实例,注册为 Singleton 。
Singleton
你的内心 IDispatchMessageInspector ,您可以通过调用来设置数据库 SecurityContext.SetDatabase(db) 。
IDispatchMessageInspector
SecurityContext.SetDatabase(db)
另一种选择是使用对象图流动数据。在这种情况下,您将可变状态存储为上下文类中的私有字段(例如您的 SecurityContext 并将其注册为 Scoped 。这样,您可以在请求开始时设置它们的值,并且这些值可以在请求中的任何位置重复使用,其中 ISecuriryContext 注入,而另一个请求得到不同 SecurityContext 实例。
Scoped
ISecuriryContext
你可以改变你的 SecurityContext 以下内容:
public sealed class SecurityContext : ISecurityContext { // Just get/set with a private backing field. No ambient state public Database Database { get; set; } }
注册如下:
container.Register<SecurityContext>(Lifestyle.Scoped); container.Register<ISecurityContext, SecurityContext>(Lifestyle.Scoped);
你的内心 IDispatchMessageInspector ,你可以解决 SecurityContext 并设置 Database :
Database
container.GetInstance<SecurityContext>().Database = db;
您的应用程序的其余部分可以简单地依赖 ISecurityContext 并检索它 Database 值。