实现此目的的一种方法是使用 ServiceBehavior 添加一个实例来实现IInstanceContext初始化器 http://blogs.msdn.com/b/carlosfigueira/archive/2012/02/14/wcf-extensibility-initializers-instance-context-channel-call-context.aspx.
我的实现如下所示:
public class PerOperationThrottle: IInstanceContextInitializer
{
static MemoryCache cache = new MemoryCache("foo", null);
public void Initialize(InstanceContext instanceContext, Message message)
{
RemoteEndpointMessageProperty ep = message.Properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
// which action do we want to throttle
if (message.Headers.Action.EndsWith("register") &&
ep != null &&
ep.Address != null)
{
// get the IP address
var item = cache[ep.Address];
if (item == null)
{
// not found, so init
cache.Add(
ep.Address,
new Counter { Count = 0 },
new CacheItemPolicy
{
SlidingExpiration = new TimeSpan(0, 1, 0) // 1 minute
});
}
else
{
// how many calls?
var count = (Counter)item;
if (count.Count > 5)
{
instanceContext.Abort();
// not sure if this the best way to break
throw new Exception("throttle");
}
// add one call
count.Count++;
}
}
}
}
我用的是有点幼稚的内存缓存 https://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache(v=vs.110).aspx实现为我的自定义的每个 IP 地址保存一个实例Counter
class:
public class Counter
{
public int Count;
}
连接一个实例PerOperationThrottle
对于该服务,我有一个帮助程序类,它结合了服务行为 http://blogs.msdn.com/b/carlosfigueira/archive/2011/03/22/wcf-extensibility-iservicebehavior.aspx and I端点行为 http://blogs.msdn.com/b/carlosfigueira/archive/2011/04/05/wcf-extensibility-iendpointbehavior.aspx:
public class PerOperationThrottleBehaviorAttribute : Attribute, IServiceBehavior,IEndpointBehavior
{
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach(var ep in serviceDescription.Endpoints)
{
// add the EndpointBehavior
ep.EndpointBehaviors.Add(this);
}
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
// our PerOperationThrottle gets created and wired
endpointDispatcher.
DispatchRuntime.
InstanceContextInitializers.
Add(new PerOperationThrottle());
}
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
{
}
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
}
}
空方法属于接口,但不需要任何实现。确保删除throw new NotImplementedException();
though.
最后我们用我们的自定义属性注释Service实现类PerOperationThrottleBehavior
[PerOperationThrottleBehavior]
public class Service1 : IService1
{
public string register(int value)
{
return string.Format("You entered: {0}", value);
}
}
If the register
一分钟内调用操作超过 5 次,服务抛出异常。