IOperationInvoker
と の間で少し迷っていIInstanceProvider
ます。
同期呼び出しと非同期呼び出しのIOperationInvoker
両方を拡張する必要があるため、必要なものに対してかなり複雑であることが判明しました。ただし、各メソッド呼び出しの前後にアクションを実行するように特別に作成されているという利点があります。オブジェクトを任意のサービス メソッドに渡す方法はまだ完全にはわかりませんが、階層の下位にある使用状況を追跡するために使用できます。残念ながら、Carlos Figueira の WCF Extensibility に関するブログでは、彼の例ではこれに触れていません (彼は呼び出しをキャッシュする方法を示しています)。
を実装するのIInstanceProvider
がより簡単であることが判明し、各操作の前後にアクションを実行することも可能になりましInstanceContextMode
たPerCall
。に変更するとPerSession
、代わりにセッションごとに 1 回突然アクションを実行することになります。しかし、私の場合、主な目的はデータを可能な限りマージすることであるため、それは受け入れられます。
カスタムの Service クラスの 1 つで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
てパイプラインに挿入できます。これは、 Service インスタンスがリリースされた後に取得できます。
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 });
}
}