如何处理IQueryable中的后端异常<>方法?

时间:2012-06-21 09:28:35

标签: exception-handling iqueryable

使用HttpClient调用ASP.NET Web API方法,调用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();

那当然会被抓住。但是可查询的场景怎么样,我怎么能抓住它们呢?

1 个答案:

答案 0 :(得分: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();
    }

当然,这有可能使用更多内存的缺点。