我在IOperationInvoker
和之间有点纠结IInstanceProvider
。
事实证明,对于我需要的东西来说,这IOperationInvoker
相当复杂,因为我需要扩展同步和异步调用。但它的优点是它专门用于在每个方法调用之前和之后执行操作。虽然我仍然不完全确定如何将对象传递给任何服务方法,我可以用它来跟踪使用,在层次结构中较低。不幸的是,Carlos Figueira 关于 WCF 可扩展性的博客在他的示例中没有涉及到这一点(他展示了如何缓存调用)。
结果IInstanceProvider
证明对我来说实现起来更简单,并且还可以在每次操作之前和之后执行操作 - 只要InstanceContextMode
是PerCall
. 如果我将其更改为PerSession
,我会突然在每个会话中执行一次操作。但就我而言,这是可以接受的,因为主要目标是尽可能多地合并数据:
我的一个 Service 类具有自定义ServiceBehavior
Attribute
并继承了一个抽象类型,该类型指示我们有一个构造函数,该构造函数采用PerformanceContext
:
[ServiceContract]
public interface IJobsService { ... }
[PerformanceInstanceProviderBehavior]
public partial class JobsService : PerformanceMonitoredService, IJobsService
{
public PerformanceContext PerformanceContext { get; protected set; }
JobsService() { ... }
JobsService(PerformanceContext perfContext) : this()
{
PerformanceContext = perfContext;
}
...
}
IInstanceProvider
它允许调用特定的构造函数并将一个IExtension
注入管道,我们可以在服务实例释放后获取:
public class ServiceInstanceProvider : IInstanceProvider
{
public Type ServiceType { get; set; }
public ServiceInstanceProvider(Type serviceType) { ServiceType = serviceType; }
public object GetInstance(InstanceContext instanceContext)
{
return this.GetInstance(instanceContext, null);
}
public object GetInstance(InstanceContext instanceContext, Message message)
{
var perfContext = new PerformanceInstanceContext();
instanceContext.Extensions.Add(new PerformanceInstanceExtension(perfContext));
return ServiceFactory.Create(ServiceType, perfContext);
//return new JobsService(perfContext);
}
public void ReleaseInstance(InstanceContext instanceContext, object instance)
{
var perfContext = (instanceContext.Extensions.FirstOrDefault(ice =>
ice is PerformanceInstanceExtension)
as PerformanceInstanceExtension
)?.PerformanceContext;
//Handle the object which has been through the pipeline
//Note (IErrorHandler):
//This is called after "ProvideFault", but before "HandleError"
}
}
将添加IServiceBehavior
到Attribute
所有需要PerformanceContext
注入的服务中。
public class PerformanceInstanceProviderBehaviorAttribute : Attribute, IServiceBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
if (!ed.IsSystemEndpoint)
{
//Each Service Type is getting their own InstanceProvider,
//So we can pass the type along,
//and let a factory create the appropriate instances:
ed.DispatchRuntime.InstanceProvider =
new ServiceInstanceProvider(serviceDescription.ServiceType);
}
}
}
}
...
}
我们IExtension
可以InstanceContext
通过实例提供者管道附加到:
public class PerformanceInstanceExtension : IExtension<InstanceContext>
{
public PerformanceInstanceExtension()
{
PerformanceContext = new PerformanceContext();
}
public PerformanceInstanceExtension(PerformanceContext perfContext)
{
PerformanceContext = perfContext;
}
public PerformanceContext PerformanceContext { get; private set; }
public void Attach(InstanceContext owner) {}
public void Detach(InstanceContext owner) {}
}
应该允许这种注入的抽象服务类型:
public abstract class PerformanceMonitoredService
{
public abstract PerformanceContext PerformanceContext { get; protected set; }
public PerformanceMonitoredService() {}
public PerformanceMonitoredService(PerformanceContext perfContext) {}
}
继承的服务工厂PerformanceMonitoredService
:
public class PerformanceServiceFactory
{
private static ConcurrentDictionary<Type, ConstructorInfo> Constructors
= new ConcurrentDictionary<Type, ConstructorInfo>();
public static object Create(Type type, PerformanceContext perfContext)
{
ConstructorInfo ctor;
if(Constructors.TryGetValue(type, out ctor))
{
return InvokeConstructor(ctor, perfContext);
}
else if (type.IsSubclassOf(typeof(PerformanceMonitoredService))
||type.IsAssignableFrom(typeof(PerformanceMonitoredService)))
{
ConstructorInfo newCtor = type.GetConstructor(
new[] { typeof(PerformanceContext) }
);
if(Constructors.TryAdd(type, newCtor))
{
return InvokeConstructor(newCtor, perfContext);
} else if(Constructors.TryGetValue(type, out ctor))
{
return InvokeConstructor(ctor, perfContext);
}
}
throw new ArgumentException(
$"Expected type inheritable of {typeof(PerformanceMonitoredService).Name}"}",
"type");
}
private static object InvokeConstructor(ConstructorInfo ctor,
PerformanceContext perfContext)
{
return ctor.Invoke(new object[] { perfContext });
}
}