C# 具有数据库访问功能的soapwebservice
所以基本上我有一个Soap Web服务,它可以从SqlServer数据库中插入和检索一些数据 webservice使用一个负责DB内容的单例C# 具有数据库访问功能的soapwebservice,c#,.net,sql-server,web-services,asmx,C#,.net,Sql Server,Web Services,Asmx,所以基本上我有一个Soap Web服务,它可以从SqlServer数据库中插入和检索一些数据 webservice使用一个负责DB内容的单例 public class Service : System.Web.Services.WebService { private DBAccess dbaccess; public Service() { dbaccess = DBAccessLocalhost.GetInstance(); } [W
public class Service : System.Web.Services.WebService
{
private DBAccess dbaccess;
public Service()
{
dbaccess = DBAccessLocalhost.GetInstance();
}
[WebMethod]
public List<Profile> XXX(Guid a, uint b, DateTime c)
{
return dbaccess.XXX(a, b, c);
}
...
}
第二版:
public class DBAccessLocalhost : DBAccess
{
private static DBAccess instance = null;
private string connectionString;
public static DBAccess GetInstance()
{
if (instance == null)
instance = new DBAccessLocalhost();
return instance;
}
private DBAccessLocalhost()
{
connectionString = "Data Source=localhost;Initial Catalog=DBName;Integrated Security=True;Max Pool Size=2000;Pooling=true";
}
public override void XXX(Guid a, uint b, DateTime c)
{
string strSql = "SP_Name";
using (SqlConnection conn = new SqlConnection(connectionString))
{
using (SqlCommand cmd = new SqlCommand(strSql, conn))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@a", a.ToString());
cmd.Parameters.AddWithValue("@b", (int)b);
cmd.Parameters.AddWithValue("@c", c);
try
{
conn.Open();
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
//....
}
}
}
catch (Exception ex)
{
throw new DBError("Error: " + ex.Message);
}
finally
{
conn.Close();
}
}
}
问题是,有时我会遇到以下异常:
DBAccessWebSerice,System.ServiceModel.FaultException: Server was unable to process
request. ---> Errors: ExecuteNonQuery requires an open and available
Connection. The connection's current state is closed (Sometimes says connecting).
Server stack trace:
at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime
operation, ProxyRpc& rpc)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway,
ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage
methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
问题可能是因为同时有多个到数据库的连接
也许这不是最好的办法。但是,如果您有更好的方法或解决此问题的方法,请说。对于Db访问,单例模式不是一个好模式。使用静态方法检索数据。最有可能的是,您的问题是有两个线程访问了您的实例,而您没有锁来阻止它。 其他要点:
和
public override void XXX(Guid a, uint b, DateTime c)
{
string strSql = "SP_Name";
lock (lockObject) { // lock the code for the duration of execution so it is thread safe now (because you in singleton)
// But this is bad for DB access !!!! What if SP executes long - other threads have to wait
// Use simple static methods for data access and no `lock`
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(strSql, conn))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@a", a.ToString());
cmd.Parameters.AddWithValue("@b", (int)b);
cmd.Parameters.AddWithValue("@c", c);
// no need for any `try-catch` here because `using` is that and `finally`
using (SqlDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
//....
}
}
}
conn.Close();
}
}
}
如果您想更好地控制异常处理,另一个选项是使用try catch finally
,而不是使用。然后,在最后,您将执行另一个try catch
来清理您的资源。
//伪码
try
connection
command
datareader
catch (Exception ex)
prepare user message
log or
throw/throw new, etc // depends. This is Webservice, may be log and response with error message
finally
try
if datareader alive
close datareader
dispose datareader
catch // do nothing here
try
if command alive
dispose command
catch // do nothing here
try
if connection alive
close connection
dispose connection
catch // do nothing here
这里有一种方法,放弃了单身的想法,正如另一个答案所建议的那样:
- 将Func传递到您的服务中,该服务是数据访问对象的工厂
- 让DBAccess实现IDisposable,并使用using块
public class Service : System.Web.Services.WebService
{
private Func<DBAccess> getDBAccess;
public Service(Func<DBAccess> getDBAccess)
{
this.getDBAccess = getDBAccess;
}
[WebMethod]
public List<Profile> XXX(Guid a, uint b, DateTime c)
{
using(var dbaccess = this.getDBAccess())
{
return dbaccess.XXX(a, b, c);
}
}
...
}
公共类服务:System.Web.Services.WebService
{
私有Func getDBAccess;
公共服务(Func getDBAccess)
{
this.getDBAccess=getDBAccess;
}
[网络方法]
公共列表XXX(Guid a、uint b、日期时间c)
{
使用(var dbaccess=this.getDBAccess())
{
返回dbaccess.XXX(a,b,c);
}
}
...
}
关于第1点,名称“SP_”只是一个例子;)我添加了第二个版本,其中有一些更改,我认为这就是您所说的。如果这不是正确的方法,请给我举一些例子或类似的例子。看看我的编辑。如果您坚持使用实例方法的singleton-addlock{}
。或者,更好的方法是使您的方法静态
且不锁定
。我的意思是,将代码从XXX
移动到private static void execXXX
并从XXX
调用它。在web服务中,由于多线程,您在任何情况下都需要对单例实例的创建进行锁定。ASMX是一种传统技术,不应用于新的开发。WCF应用于web服务客户端和服务器的所有新开发。一个提示:Microsoft已停用MSDN上的。此外,在引发新异常时始终包含原始异常:throw new DBException(message,ex)代码>
public class Service : System.Web.Services.WebService
{
private Func<DBAccess> getDBAccess;
public Service(Func<DBAccess> getDBAccess)
{
this.getDBAccess = getDBAccess;
}
[WebMethod]
public List<Profile> XXX(Guid a, uint b, DateTime c)
{
using(var dbaccess = this.getDBAccess())
{
return dbaccess.XXX(a, b, c);
}
}
...
}