使用强类型数据集重试SQL Azure请求

时间:2016-02-09 15:02:15

标签: sql-server azure strongly-typed-dataset

我们最近开始使用SQL Azure数据库在Microsoft Azure中测试ASP.NET应用程序。我们不经常超时和失去联系。我们现在明白这是基于云的数据库的本质,建议使用瞬态故障处理应用程序块。但是,这似乎要求您的代码创建连接并发出访问请求。由于我们使用强类型数据集,因此该逻辑隐藏在Fill()内部,例如,在为数据集生成的代码中。我们有业务对象单元实际调用生成的代码中的方法,所以我们有一个放置重试逻辑的地方,但宁愿不在数百个地方放置相同的代码。

在这种情况下是否有办法使用TFHAB或以不需要太多代码的一般方式合并重试逻辑?

1 个答案:

答案 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。

现在已经生产了大约一年,没有任何问题。