我正在尝试创建我的应用程序将使用的第三方许可证池(因为这些许可证是有限的)。我一直指this来编写我的代码。
基本上,我的Web应用程序连接到中间层WCF服务(每次调用实例)以执行所有业务功能。现在,要将此第三方工具与我的应用程序集成,我将创建第二个单独的WCF(自托管)服务作为许可证池来保存所有可用的许可证。因此,当web-app用户需要利用第三方功能进行任何活动时,我的中间层服务将首先从单身许可证池中获取许可证,执行业务任务,将许可证返回到池中,然后最终返回对用户的响应。
public class SessionPoolService : IDisposable
{
//This holds the sessions currently in pool
private BlockingCollection<AxSessionTicket> _pool;
private int _blockingTimeout;
public CancellationToken _cancel;
private Guid Id;
private static SessionPoolService _instance = null;
//Factory
public static SessionPoolService GetInstance()
{
int availableLicenses = int.Parse(System.Configuration.ConfigurationManager.AppSettings["AvailableLicenses"]);
int blockingTimeOutInMS = int.Parse(System.Configuration.ConfigurationManager.AppSettings["BlockingTimeOutInMilliSecs"]);
if (_instance == null)
_instance = new SessionPoolService(new CancellationToken(), availableLicenses, blockingTimeOutInMS);
return _instance;
}
private SessionPoolService(CancellationToken ct, int availableLicenses, int blockingTimeOutInMS)
{
_pool = new BlockingCollection<AxSessionTicket>(new ConcurrentQueue<AxSessionTicket>(), availableLicenses);
_blockingTimeout = blockingTimeOutInMS;
_cancel = ct;
Id = Guid.NewGuid();
Init(availableLicenses);
}
public string GetObject()
{
AxSessionTicket retObj = new AxSessionTicket(string.Empty);
if (this._pool.IsCompleted)
{
ExceptionMgmtService.GetInstance().Error("Error occured at GetObject: Could not acquire License within specified time.");
throw new FaultException("Adding has been marked completed and there are no more items available in the collection.");
}
else
try
{
if (!this._pool.TryTake(out retObj, _blockingTimeout, _cancel))
{
ExceptionMgmtService.GetInstance().Error("Error occured at GetObject: Could not acquire License within specified time.");
throw new FaultException("Could not acquire License within specified time.");
}
else
{
var sessionId = LicensePool.AuthenticationService.GetInstance().DoLogin(retObj.SessionId);
retObj = new AxSessionTicket(sessionId);
//HealthMonitorService.GetInstance().AddItem(retObj);
}
}
catch (OperationCanceledException) // This will happen when operation is cancelled via the token.
{
//Logout all sessions
ForceLogOutEntirePool();
ExceptionMgmtService.GetInstance().Error("Error occured at GetObject: 'Get' operation has been cancelled.");
throw new FaultException("'Get' operation has been cancelled.");
}
TracerService.GetInstance().TraceToConsole.TraceInformation("Instance #{1}: '{0}' issued. Pool strength: {2}", retObj.SessionId, this.Id, this._pool.Count);
return retObj.SessionId;
}
public void ReturnObject(string lic, bool addToTransaction = true)
{
var sessionObj = new AxSessionTicket(lic);
try
{
if (!_pool.TryAdd(sessionObj, _blockingTimeout, _cancel))
{
ExceptionMgmtService.GetInstance().Error("Error occured at ReturnObject: Could not add License within specified time.");
throw new FaultException("Could not add License within specified time.");
}
else
{
TracerService.GetInstance().TraceToConsole.TraceInformation("Instance #{1}: Adding '{0}' to pool. Pool strength: {2}", lic, this.Id, this._pool.Count);
//if (addToTransaction)
// HealthMonitorService.GetInstance().RemoveItem(new AxSessionTicket(lic));
}
}
catch (OperationCanceledException)
{
//Logout the passed-in session.
LicensePool.AuthenticationService.GetInstance().DoLogout(lic);
//Logout all sessions
ForceLogOutEntirePool();
ExceptionMgmtService.GetInstance().Error("Error occured at ReturnObject: 'Return' operation has been cancelled.");
throw new FaultException("'Return' operation has been cancelled.");
}
}
public void ForceLogOutEntirePool()
{
//Stop any further additions.
this._pool.CompleteAdding();
foreach (var item in this._pool.GetConsumingEnumerable())
{
TracerService.GetInstance().TraceToConsole.TraceInformation("Logging out '{0}'.", item.SessionId);
LicensePool.AuthenticationService.GetInstance().DoLogout(item.SessionId);
}
}
private void Init(int availableLicenses)
{
TracerService.GetInstance().TraceToConsole.TraceInformation("Pool initializing..... ");
// Fill till half the capacity.
var authManager = LicensePool.AuthenticationService.GetInstance();
for (int i = 0; i < availableLicenses; i++)
{
if (i < Math.Floor(availableLicenses / 2.0))
{
var sessionId = Guid.NewGuid().ToString();
ReturnObject(sessionId, false); //Fill-in dummy guids in first half and actual license-keys in second half.
}
else
{
var sessionId = authManager.DoLogin(string.Empty);
ReturnObject(sessionId, false);
}
}
//Start Monitor service
//HealthMonitorService.GetInstance().RunMonitor();
TracerService.GetInstance().TraceToConsole.TraceInformation("Pool ready for use...");
}
public void Dispose()
{
ForceLogOutEntirePool();
HealthMonitorService.GetInstance().Dispose();
}
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, ConcurrencyMode=ConcurrencyMode.Multiple)]
public class SessionPool : ISessionPool, IDisposable
{
public SessionPoolService pool = SessionPoolService.GetInstance();
public string GetSessionKey()
{
TracerService.GetInstance().TraceToConsole.TraceInformation("Caller #{0}: Request to acquire sessionTicket.", System.Threading.Thread.CurrentThread.ManagedThreadId);
return pool.GetObject();
}
public void ReturnSessionKey(string sessionKey)
{
TracerService.GetInstance().TraceToConsole.TraceInformation("Caller #{0}: Request to release sessionTicket - '{1}'", System.Threading.Thread.CurrentThread.ManagedThreadId, sessionKey);
pool.ReturnObject(sessionKey);
}
public void Dispose()
{
pool.Dispose();
}
}
Q1 - 这是处理有限许可的正确方法吗?如果没有,有哪些替代方案?
Q2 - 只要我的单件服务顺序调用,池工作正常,但当我尝试发出并行调用时,我开始收到错误 - 比如,2个调用者被发出相同的许可证密钥,池发出空白密钥等我试图将并发 - 呼叫限制设置为我的池的大小,但它没有帮助。 你能帮忙指出上面的问题吗?