每分钟,每种方法,每个IP限制对WCF服务的呼叫 [英] Restrict calls to WCF service per minute, per method, per IP
问题描述
我想通过任意不同的IP将WCF服务上对特定方法的调用次数限制为在每个时间段 y 中 x 个调用。
I'd like to restrict the number of calls to a particular method on my WCF service, by any distinct IP, to x calls per timeframe y.
例如,如果IP 10.0.1.1
调用方法 register
在特定分钟内超过5次(称为分钟 x
),当它尝试在该分钟内第六次调用该方法时,被阻塞直到分钟( x + 1
)。
So for example, if IP 10.0.1.1
calls the method register
more than 5 times in a particular minute (call it minute x
), when it it tries to call that method a sixth time in that minute it is blocked until minute (x + 1
).
这是因为我系统上唯一的非令牌授权呼叫是注册
调用。我担心尝试用调用淹没此方法会使我的服务器在负载下挣扎。该方法背后有很多处理,并且只能偶尔调用。
This is because the only non-token authorized call on my system is the register
call. I am worried that attempts to flood this method with calls will my server to struggle under load. There is quite a lot of processing behind this method, and it is designed to only be called occasionally.
我已经考虑添加 ServiceThrottlingBehavior code>到配置文件,但这对于服务是全局的,而不是服务方法的本地。
I have looked into adding ServiceThrottlingBehavior
to the config file, but this is global to the service, rather than local to a service method.
是否有一种很好的/标准化的方法
Is there a good / standardized way to do this, whether programatically or in a configuration file?
推荐答案
做到这一点的一种方法是让ServiceBehavior添加一个实例,实现 IInstanceContextInitializer 。
One way to do this is by having a ServiceBehavior that adds an instance that implements IInstanceContextInitializer.
我的实现如下:
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++;
}
}
}
}
I使用有些天真的 MemoryCache 实现,该实现针对我的自定义 Counter
类的每个IP地址保存一个实例:
I use a somewhat naïve MemoryCache implementation that holds an instance per IP address of a my custom Counter
class:
public class Counter
{
public int Count;
}
连接 PerOperationThrottle $ c的实例$ c>服务,我有一个帮助器类,它结合了 IServiceBehavior 和 IEndpointBehavior :
To wire an instance of PerOperationThrottle
to the service I have an helper class that combines the implementation for a IServiceBehavior and IEndpointBehavior:
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)
{
}
}
空方法属于接口,但不需要任何实现。确保确保删除抛出新的NotImplementedException();
。
The empty methods belong to the interfaces but don't need any implementation. Make sure to remove the throw new NotImplementedException();
though.
最后,我们用我们的Service注释类自定义属性 PerOperationThrottleBehavior
Finally we annotate the Service implementation class with our custom attribute PerOperationThrottleBehavior
[PerOperationThrottleBehavior]
public class Service1 : IService1
{
public string register(int value)
{
return string.Format("You entered: {0}", value);
}
}
如果注册一分钟内code>操作被调用5次以上,该服务将引发异常。
If the register
operation gets called more than 5 times within a minute, the service throws an exception.
这篇关于每分钟,每种方法,每个IP限制对WCF服务的呼叫的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!