2017-09-29 1 views
2

: AsyncContextThread 정말 스레드가 시작될 때 발생하는 예외를 잡기 처리하는 방법에 대해 다루지 않습니다AsyncContext -> AsyncContextThread 예외 사항에 대해서는

https://github.com/StephenCleary/AsyncEx/wiki/AsyncContext

https://github.com/StephenCleary/AsyncEx/blob/master/src/Nito.AsyncEx.Context/AsyncContextThread.cs

.

public partial class MyService : ServiceBase 
{ 
    private readonly AsyncContextThread _thread = new AsyncContextThread(); 

    private readonly CancellationTokenSource _cts = new CancellationTokenSource(); 

    public MyService() 
    { 
     InitializeComponent(); 
    } 

    public void Start() 
    { 
     OnStart(null); 
    }  

    protected override void OnStart(string[] args) 
    { 
     try 
     {  
      _thread.Factory.Run(StartAsync); 
     } 
     catch (Exception ex) 
     {     
      // Exception? 
     } 
    } 

    private async Task StartAsync() 
    { 
     throw new Exception("things went wrong"); 
    } 

    protected override void OnStop() 
    { 
     if (!_cts.IsCancellationRequested) 
      _cts.Cancel(); 
     _thread.JoinAsync().GetAwaiter().GetResult(); 
    } 
} 

나는뿐만 아니라 내 Program.cs (주 진입 점)에 다음을 추가하는 시도는 catch{} 블록에서 아무것도 잡을 것 같지 않습니다.

TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException; 
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; 

그러나 위의 코드에서 이벤트 처리기 메서드가 트리거되지 않습니다.

Q)이 상황에서 어떻게 예외를 올바르게 처리합니까?

부수적으로 이전에 AsyncContext을 사용하고 Visual Studio에서 디버깅을하면 예외가 발생했기 때문에 동기화가 있는지 확실하지 않습니다. 문맥 나는 예외 처리기를 추가하려고 할 때 실종되었다.

편집

나는 내가 StartAsync 메소드 내 try/catch을 할 수있는 알고,하지만 난에 받고 있어요 지점은 처리되지 않은 예외를 잡아 내가 그들을 로그인 할 수 있는지 확인 할 수있는 것입니다.

+0

나는이 질문에 대한 Stephen Cleary의 대답을 필사적으로 바라보고있다. – peteski

+1

예외를 잡으려고'try'에서 메소드를'기다려야한다고 생각한다. 현재 비동기 메서드는 호출자에게 즉시 반환되며 throw 된 오류는 손실됩니다. – Equalsk

+0

@Equalsk Windows 서비스의'OnStart' 메소드에서 무엇이든 '대기'할 수 없습니다. 오버라이드이며 예상되는 서명과 일치해야합니다. AsyncContext/AsyncContextThread (내가 이해하는 한)의 전체 아이디어는 허용하지 않는 곳 (예 : 콘솔 앱 또는 Windows 서비스)에서 비동기 메소드를 스핀 업하도록 허용하는 것입니다. – peteski

답변

2

... :)

정말 잡기 예외를 처리하는 방법에 대해 다루지 않습니다

그 스레드가 시작될 때 발생합니다.

실제로 AsyncContextThread은 생성시 즉시 시작됩니다. OnStart에서 수행중인 작업은 해당 컨텍스트에 대한 대기열 작업입니다.

그 일에 대한 예외

Run에서 반환 된 Task에 관찰하고 관찰 할 수있는 적절한 방법은 await을 사용하고 있습니다 :

protected override async void OnStart(string[] args) 
{ 
    try 
    {  
     await _thread.Factory.Run(StartAsync); 
    } 
    catch (Exception ex) 
    {     
     // Exception! 
    } 
} 

몇 가지 참고 사항 :

보통을, 당신은 avoid async void을해야한다. 이 룰의 예외는 이벤트 핸들러 또는 이벤트와 유사한 메소드 (예 : OnStart)입니다. 으로 사용할 경우 async void을 사용하는 경우 전체 async void 방법 본문 (예 : Google)에서 try/catch을 고려해야합니다.

await is superior to ContinueWith.이 경우에 ContinueWith은 정상적으로 작동하지만 일반적인 경우 적절하지 않습니다. async 대리자를 이해하지 못하고 적절한 기본값 인 TaskScheduler을 사용하지 않으며 적절한 기본 연속 플래그를 사용하지 않습니다. 이것들은 await이 당신을 위해 처리하는 모든 것입니다.

+0

답장을 보내 주셔서 감사합니다 Stephen, 그냥 후속 조치, Visual Studio에서 디버그를 실행할 때 물건을 걷어차 기 위해 'public void Start()'메서드가 있습니다. 그냥 service.Start();로 남겨주세요; – peteski

+1

'Start()'를 사용해야 할 것 같아요. 작업을 반환하지 않으므로 작업을 차단할 수 없습니다. –

3

예외를 처리하려면 Continuation을 사용할 수 있습니다. 내가 지금 몇 년 동안 비동기는 Win32 서비스 ...의 블로그 게시물을 했었어

protected override void OnStart(string[] args) 
{ 
    _thread.Factory.Run(StartAsync).ContinueWith(t => 
    { 
     var aggregate = t.Exception.Flatten(); 
     foreach(var exception in aggregate.InnerExceptions) 
     { 
      // Handle exception 
     } 
    }, TaskContinuationOptions.OnlyOnFaulted); 
} 
+0

내가 스티븐의 질문에 대한 답변을 얻기를 바라고 있다고 생각하는 이유는 "C# Cookbook의 동시성 (Concurrency in C# Cookbook)"(35/36 페이지)에서 비동기 void 형식 메서드에서 예외를 처리하는 방법에 대해 논의했기 때문입니다. 주어진 코드 예제에서는 제시 한대로 연속을 사용하지 않고 내 코드 샘플에서 try/catch를 사용하므로 정확하지 않습니다. – peteski

관련 문제