我们最近开始使用SQL Azure数据库在Microsoft Azure中测试ASP.NET应用程序。我们不经常超时和失去联系。我们现在明白这是基于云的数据库的本质,建议使用瞬态故障处理应用程序块。但是,这似乎要求您的代码创建连接并发出访问请求。由于我们使用强类型数据集,因此该逻辑隐藏在Fill()内部,例如,在为数据集生成的代码中。我们有业务对象单元实际调用生成的代码中的方法,所以我们有一个放置重试逻辑的地方,但宁愿不在数百个地方放置相同的代码。
在这种情况下是否有办法使用TFHAB或以不需要太多代码的一般方式合并重试逻辑?
答案 0 :(得分:0)
我所做的是我有一个名为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错误等等时调用TransientError。
现在已经生产了大约一年,没有任何问题。