4

HttpClientがASP.NETWebAPIメソッドを呼び出し、EFリポジトリを呼び出すシナリオ。SQL例外をキャッチするのに問題があります。

クライアント:

try
{
  var client = new HttpClient();
  var httpRequestMessage = new HttpRequestMessage();
  var response = await client.SendAsync(httpRequestmessage);
  response.EnsureSuccessStatusCode();
}
catch (Exception ex)
{
  // internal error 500 here
}

Web API:

[HttpGet]
public IQueryable<Data> GetData()
{
  try
  {
    return repository.Data();
  }
  catch (Exception ex)
  {
     // Nothing here
  }
}

リポジトリ:

public IQueryable<Data> GetData()
{
  try
  {
    return dbContext.Data.Where(d=>d.Id == 1)
  }
  catch (Exception ex)  
  {
    // nothing here
  }
}

SQL Serverの例外(接続の問題など)を処理するにはどうすればよいですか?APIレイヤーもリポジトリレイヤーもそれらをキャッチしません。クエリ可能オブジェクトをリポジトリ内の配列に変換する場合:

var arr = dbContext.Data.Where(d => d.Id == 1).ToArray();

もちろんそれは捕まるでしょう。しかし、クエリ可能なシナリオはどうですか、どうすればそれらをキャッチできますか?

4

1 に答える 1

2

例外を処理できない理由は、IQueryable の一般的な実装が遅延であるためです。それらを列挙しようとするまで、実際には何も起こりません。キャッチしたいのがクエリ評価の例外だけの場合は、継承による簡単なトリックを使用できますQueryableAttribute。コードは次のとおりです。

public class QueryableWithExceptionAttribute : QueryableAttribute
{
    public override IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions)
    {
        IQueryable result = base.ApplyQuery(queryable, queryOptions);
        try
        {
            result.GetEnumerator(); // eager evaluate to catch exceptions
        }
        catch(Exception)
        {
            // do stuff
        }

        return result;
    }
}

これにより、サーバー上でクエリが実行され、いくつかの結果も取得されると思います。結果セット全体をフェッチしないという利点/欠点がまだあります。つまり、結果セットが大きく、最初のフェッチ後に接続の問題がある場合、それらの例外をキャッチできません。ただし、小さな結果セットには十分なはずです。より堅牢なソリューションが必要な場合は、result = LoadIntoMemory(result);代わりに次のようにして、結果セット全体をメモリにロードできます。result.GetEnumerator();

    public static IQueryable LoadIntoMemory(IQueryable q)
    {
        MethodInfo mi = typeof(QueryableWithExceptionAttribute).GetMethod("LoadIntoMemoryInternal", BindingFlags.NonPublic | BindingFlags.Static);
        return mi.MakeGenericMethod(q.ElementType).Invoke(null, new[] { q }) as IQueryable;
    }

    private static IQueryable<T> LoadIntoMemoryInternal<T>(IQueryable<T> q)
    {
        return q.ToList().AsQueryable();
    }

もちろん、これにはより多くのメモリを使用する可能性があるという欠点があります。

于 2013-03-10T06:06:55.083 に答える