我在ASP.NET应用程序中使用第三方Web服务。必须同步对第三方Web服务的调用,但ASP.NET显然是多线程的,并且可以进行多个页面请求,从而同时调用第三方Web服务。对Web服务的调用封装在自定义对象中。我的想法是将对象存储在应用程序变量中,并使用C#lock关键字强制同步使用它。
我很紧张,因为我是多线程概念的新手,我读过你不应该锁定一个公共对象(我的应用程序变量是有效的)。我还读过,如果锁定的代码块失败(如果Web服务失败可能会失败),那么它可能会破坏应用程序域的稳定性并降低应用程序。
我应该提到第三方网络服务很少在我的网站上使用,并且很少会同时发出2个请求。
以下是我如何调用Web服务的粗略代码示例:
ThirdPartWebService objWebService = Application["ThirdPartWebService"] As ThirdPartWebService;
lock (objWebService)
{
objWebService.CallThatNeedsToBeSynchronized();
}
答案 0 :(得分:2)
如果它至关重要,您应该随时只需拨打一次电话,我建议您编写自己的Windows服务。这取决于您想要的容错程度。
例如,假设您调用Web服务,然后回收应用程序池。当有新请求进入时,它将由您的应用程序的新实例处理,然后该实例可以调用Web服务(即使另一个实例正在运行)。
您可以将其传递给Windows服务,然后使用客户端的轮询机制来检查服务是否已完成(客户端会问IIS你做完了,IIS会从Windows服务中寻找一些指示它是完成)。这种方法可以避免在IIS中锁定任何内容,并且不会浪费线程池中的线程等关键资源等待第三方服务。
您永远不应该锁定Web应用程序中的单个资源......这样做太冒险了。
另一种选择是直接使用Monitor对象:
if (System.Threading.Monitor.TryEnter(syncObj,10))
{
try
{
//CallWebService
}
finally
{
System.Threading.Monitor.Exit(syncObj);
}
}
else
{
//Tell Client they are still waiting
}
TryEnter将阻塞,直到锁定或已经过了10毫秒。然后,您可以在超时中告诉客户端他们需要重试。然后,您可以让您的客户端代码决定是否应该重新发出请求。你也可以使用信号量或互斥量(忘记哪一个更适合这里)。但它会假设你有权使用它们,给你一些你可以在机器级锁定的东西,这会阻止应用程序回收用例。
答案 1 :(得分:1)
您可以锁定静态共享对象。这是在.Net中使用lock的常用方法。通过使用静态对象,您知道它将在所有线程之间共享,并确保锁定。
如果呼叫失败,使应用程序不稳定,这必须是因为呼叫未正确处理。通过使用“using”语句,您可以确保在调用结束时调用dispose。请阅读此SO thread,了解为什么/为什么不应该处理有关性能的Web服务。
static readonly object _lockObj = new object();
...
lock( _lockObj )
{
ThirdPartWebService objWebService = Application["ThirdPartWebService"] As ThirdPartWebService;
objWebService.CallThatNeedsToBeSynchronized();
}
答案 2 :(得分:1)
您应该在进行Web服务调用的类中创建一个private static readonly object _lock = new object();
,并将其用作锁。由于对象是静态的,所以在整个应用程序中只有一个,如果你愿意,可以使用Singleton对象(http://en.wikipedia.org/wiki/Singleton_pattern)
public class MyWebServiceWrapper
{
private static readonly object _lock = new object();
public void CallWebService()
{
lock(_lock)
{
var objWebService = (ThirdPartWebService)Application["ThirdPartWebService"];
objWebService.CallThatNeedsToBeSynchronized();
}
}
}
如果您进行WebService调用的类没有执行任何其他操作,您也可以对此进行锁定(lock(this)
)。请记住,这意味着,如果你有几个方法,对一个方法的调用也将阻止所有其他方法,这就是你通常不应该锁定它的原因。
答案 3 :(得分:0)
lock()
不会阻止对您的网络服务的多次调用。它只会确保没有线程同时在lock() {}
内执行代码块。
那么问题是该Web服务的作用是什么?
1)对第三方执行某些操作(使用您提供的某些值更新其数据库?) 你可以按照自己的建议去做。虽然我会说,如果他们的服务不能同时处理呼叫,那么他们应该修复它。这真的不是你担心的问题。
2)它查询并返回一些数据供您使用。 在这种情况下,除非您计划缓存调用结果,否则锁是无用的。
var cachedValue = ReadValueFromCache();
if (cachedValue != null)
return cachedValue;
lock (objWebService)
{
// yes you need to do it second time inside the lock
cachedValue = ReadValueFromCache();
if (cachedValue != null)
return cachedValue;
cachedValue = objWebService.CallThatNeedsToBeSynchronized();
SaveValueToCache(cachedValue);
}
return cachedValue;
如何实现缓存有点次要。它可能是Web缓存对象,也可能只是一个静态变量。