2015-03-06 5 views
1

У меня есть сервис, основанный на следующий контракте (в сокращенном виде):Почему мой WCF FaultException не обрабатывается?

[ServiceContract] 
public interface ISchedulerService 
{ 
    [OperationContract] 
    void Process(bool isForced); 
} 

германа (ИМХО) часть реализации является:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = false)] 
public class SchedulerService : ISchedulerService 
{ 
    public async void Process(bool isForced) 
    { 
     try 
     { 
      var prevStatus = Status; 
      Status = SchedulerStatus.Processing; 
      await ProcessListings(); 
      Status = prevStatus; 
     } 
     catch (Exception ex) 
     { 
      throw new FaultException(ex.Message); 
     } 
    } 

    private static Task ProcessListings() 
    { 
     throw new Exception("ProcessListings failed.");   
     return Task.Delay(5000); 
    } 
} 

Служба в настоящее время размещается в крошечном консольном приложении :

class Program 
{ 
    private static readonly SchedulerService Scheduler = SchedulerService.Instance; 
    private static ServiceHost schedulerHost; 

    protected static void OnStart() 
    { 
     try 
     { 
      if (schedulerHost != null) 
      { 
       schedulerHost.Close(); 
       schedulerHost = null; 
      } 
      schedulerHost = new ServiceHost(Scheduler); 
      schedulerHost.Open(); 
      Scheduler.Start(); 
     } 
     catch (Exception ex) 
     { 
      //EventLog.WriteEntry("Exception: " + ex.Message); 
      throw; 
     } 
    } 
} 

И, наконец, клиент:

private readonly SchedulerServiceClient _proxy= new SchedulerServiceClient(); 
... 
void ExecuteProcessNowCommand() 
{ 
    try 
    { 
     _proxy.Process(true); 
    } 
    catch (Exception ex) 
    { 
     if (exception is SchedulerException) 
     { 
      MessageBoxFacility.ProcessingError((SchedulerException)exception); 
     } 
    } 
} 

где SchedulerServiceClient - это прокси-сервер, сгенерированный при добавлении ссылки на службу. До сих пор я успешно размещал WCF внутри живой службы Windows и тестировал функции без исключений. Все было нормально, пока я не добавил обработку исключений. Я знаю, что это сложный сценарий, но большинство примеров, которые я видел, показывают, что FaultException по крайней мере был бы пойман общим обработчиком Exception в клиенте. Мой отладчик заставляет меня угадать, что исключение даже не делает его прокси, и оно остается необработанным в коде MVC. Когда я нажимаю «продолжить», я заканчиваю на экране, говоря, что стек содержит только внешний код. Это трассировку стека для этого внешнего кода:

at System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__1(Object state) 
at System.Threading.QueueUserWorkItemCallback.WaitCallback_Context(Object state) 
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem() 
at System.Threading.ThreadPoolWorkQueue.Dispatch() 
at System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()</ExceptionString></Exception></TraceRecord> 

Это заставляет меня думать, что мое использование async в службе MCV может мне играть определенную роль, но, возможно, это всего лишь невинная посредник. Пожалуйста, помогите мне попытаться определить, почему исключение даже не распространяется на клиента.

ответ

2

Исключения в методах async хранятся в возвращенной задаче. async void методы не возвращают задачу, поэтому исключение выбрасывается на поток ThreadPool, срывающий AppDomain.

Не используйте async void в любом месте, кроме обработчиков событий.

Если вы вернете задание, вы можете сделать await эту задачу, и исключение будет сброшено.

+0

Исключение должным образом улавливается методом, ожидающим метода асинхронизации, то есть 'Process' блокирует исключение, созданное' ProcessListings'. «AppDomain» все еще кажется прекрасным, в то время как 'Process' выдает исключение, которое он ловит. – ProfK

+0

@ProfK 'ProcessListings' не является методом async. Он просто возвращает задачу. «Процесс» - это метод «async», выдающий исключение, которое не было обнаружено. – i3arnon

+0

Ага, спасибо! Я только что удалил всю асинхронность, и исключение попадает на клиент. Итак, должен ли я скорее создать задачу в 'Process' и' await' сгенерированный метод async в прокси? – ProfK

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