我有一个遗产System.Web.Services.WebService(不是WCF),我必须维护。
偶尔我会遇到一些我称之为竞争条件的有线行为。
服务挂起并且必须重新启动。
有时我会遇到这个例外:
System.NotSupportedException: Multiple simultaneous connections
or connections with different connection strings inside the same
transaction are not currently supported.
at MySql.Data.MySqlClient.MySqlConnection.Open()
...
我知道根本原因是什么。该服务使用一个与mysql对话的lib,并没有考虑到webservices。不幸的是我无法改变这个lib。
一个webmethod示例如下:
[WebMethod(EnableSession = true)]
public void DoSomething()
{
var login = this.Session["login"] as LoginDetails;
ExternalLib.SetLoginData(login.Schema, login.User, login.Pass);
ExternalLib.PerformTask();
}
所以这里的问题是:
ExternalLib.SetLoginData
只是设置了一些全局变量ExternalLib.PerformTask
执行数据库调用,有些是在事务内部。1. Create MySqlConnection or take it from cache 2. Create MySqlCommand 3. Execute Command 4. Dispose command
客户a)拨打DoSomething()
并初始化他的连接。完成他的工作的一半客户端b)调用DoSomething()
,显然更改了客户端a的登录数据,并且事务中的下一个调用将使用来自客户端b)的登录,这将导致事务。
无论如何,我知道这是一个糟糕的设计,但我的问题是如何解决这个问题。 目前(因为我只有10个客户端)我在不同的端口上创建了一个专用网站,它们都指向相同的根目录,但这是一个不方便的解决方案。
也许有可能在其领域内运行每个会话。有什么建议。如果我正确理解此页面的WCF是默认行为:http://msdn.microsoft.com/en-us/magazine/cc163590.aspx
每次通话服务
每次呼叫服务是Windows通信 基础默认实例化模式。当服务类型是 配置为每次呼叫激活,服务实例,常见 语言运行时(CLR)对象,仅在客户端调用时存在 进展。每个客户端请求都会获得一个新的专用服务实例。
答案 0 :(得分:0)
由于这可能是一个线程问题,您可以锁定ExternalLib
以防止单独的实例调用代码。
public class ExtenalLibWrapper
{
private static object Locker = new object();
public void DoSomething(LoginDetails details)
{
lock(Locker)
{
ExternalLib.SetLoginData(login.Schema, login.User, login.pass);
ExternalLib.PerformTask();
}
}
}
答案 1 :(得分:0)
我已经将所有公共方法都包装在一个整洁的执行包装器中,以提供全局异常日志记录。
这迫使我的web服务一个接一个地处理一个请求,但就像我提到的那样,最大值。同时客户的数量是10
public class MyService : System.Web.Services.WebService
{
[WebMethod(EnableSession = true)]
public static int Add(int value1, int value2)
{
return Execute(() =>
{
var calculator = new Calculator();
return calculator.Add(value1, value2);
});
}
private static Logger logger =
LogManager.GetLogger(typeof(MyService).Name);
private static System.Threading.SemaphoreSlim ss =
new System.Threading.SemaphoreSlim(1, 1);
private void Execute(Action method)
{
ss.Wait();
try { method.Invoke(); }
catch (Exception ex)
{
logger.FatalException(method.Method + " failed", ex); throw;
}
finally { ss.Release(); }
}
private T Execute<T>(Func<T> method)
{
ss.Wait();
try { return method.Invoke(); }
catch (Exception ex)
{
logger.FatalException(method.Method + " failed", ex); throw;
}
finally
{
ss.Release();
}
}
}