2012-06-21 1 views
3

Сценарий с HttpClient, вызывающий метод ASP.NET Web API, вызывающий репозиторий EF. У меня возникли проблемы с перехватом SQL-запросов.Как справиться с бэкэнд Исключения из методов IQueryable <>?

Клиент:

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 
    } 
} 

Repository:

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(); 

Это было бы, конечно, поймают. Но как насчет рассматриваемого сценария, как я могу их поймать?

+0

Я предполагаю, что вы получаете «WebException» на стороне клиента. Возможно, вы сможете получить ответ от «WebException» и проанализировать его, чтобы получить ошибку XML OData. –

ответ

1

Причина, по которой вы не можете справиться с любыми исключениями, заключается в том, что 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(); 
    } 

Это, конечно, имеет тот недостаток, что потенциально использовать больше памяти.

Смежные вопросы