我们最近开始使用SQL Azure数据库在Microsoft Azure中测试 ASP.NET 应用程序。我们很少超时并失去连接。我们现在明白这是基于云的数据库的本质,建议使用暂时性故障处理应用程序块。但是,这似乎要求代码创建连接并发出访问请求。由于我们使用强类型数据集,因此此逻辑隐藏在 Fill() 中,例如,在为数据集生成的代码中。我们有业务对象单元,它们实际调用生成的代码中的方法,因此我们有一个放置重试逻辑的地方,但宁愿不要在数百个位置放置相同的代码。
在这种情况下,有没有办法使用 TFHAB,或者有办法以不需要太多代码的一般方式合并重试逻辑?
我所做的是我有一个名为 TransientError 的静态类,其中包含以下两个静态方法(我借用了 MSDN 的大部分代码):
internal static void Try(DbContext context)
{
int wait = 800;
bool retry = true;
while (retry)
{
try
{
using (SqlConnection con = new SqlConnection(context.Database.Connection.ConnectionString))
{
con.Open();
using (SqlCommand com = new SqlCommand("declare @i int;", con))
{
com.ExecuteNonQuery();
}
}
retry = false;
}
catch (SqlException)
{
Clear(context);
Thread.Sleep(wait);
}
catch (Exception)
{
retry = false;
}
// break after we reach 6.4 secs (for a total as 12 secs)
if (wait == 6400)
{
retry = false;
}
wait = wait * 2;
}
}
private static void Clear(DbContext context)
{
// This is a client side operation so won't cause an exception
// with a server side error.
// If it does fail, probably should throw!
using (SqlConnection con = new SqlConnection(context.Database.Connection.ConnectionString))
{
SqlConnection.ClearPool(con);
}
}
这解决了暂时性网络错误在连接池中留下"断开"(且不可重用)连接的问题。
我正在使用 Linq,我的每个访问方法如下所示:
public StructureElement ForId(int elementId)
{
TransientError.Try(this.context);
StructureElement element = (from se in this.context.StructureElements
where se.Id == elementId
select se).FirstOrDefault<StructureElement>();
return element;
}
使用 TransientError.Try 测试连接(如果出现问题,则会清除 ConnectionPool,然后运行 Linq 查询。如果这有问题,则调用方的异常处理将接管。
其他方法也是可能的 - 仅在实际的 Linq 错误等情况下调用瞬态错误。
它已经投入生产了大约一年,没有任何问题。