2014-05-10 2 views
4

웹 서비스에 연결하는 비동기 메소드를 작성해야했습니다.프로세스를 두 번 수행 할 때 InvalidOperationException이 발생했습니다.

public static Task<int> SignIn(string username, string password) 
    { 

     try 
     { 
      TaskCompletionSource<int> tcs = new TaskCompletionSource<int>(); 
      service.LoginCompleted += (object sender, WebService.LoginCompletedEventArgs e) => 
      { 
       if (e.Error != null) tcs.SetResult(-1); 
       else 
        tcs.SetResult((int)e.Result); 

      }; 
      service.LoginAsync(username, password); 
      return tcs.Task; 
     } 
     catch (Exception ex) 
     { 

      MessageBox.Show("Error: " + ex.Message); 
      return null; 
     } 

    } 

그런 다음 나는이 같은 버튼 클릭 이벤트에서 호출 : 내가 한 때

private async void btLogIn_Click(object sender, RoutedEventArgs e) 
    {      
     try 
     { 
      int si = await WebServiceHelper .SignIn(tbUsername.Text, tbPassword.Text);    
      if (si != 0) MessageBox.Show("Signed in successfully!"); 
      else MessageBox.Show("Couldn't sign in"); 
     } 
     catch (Exception ex) 
     { 
      MessageBox.Show(ex.Message); 
     }    
    } 

그것은 내가 버튼을 클릭 처음에 잘 작동하지만,이 WebServiceHelper 클래스의 내 방법입니다 다시 한 번 오류가 발생했습니다 : "InvalidOperationException, 이미 완료된 작업을 최종 상태로 전환하려고했습니다."

는 좀 작은 검색을했고, 여기에 뭔가를 발견하기 전에 다시 시작하지만 정확히 어떻게 그리고 왜 모르는 Tasks seem to start automatically

내가 프로세스를 중지 뭔가를해야 이해합니다. 누군가 나를 위해 이것을 설명해 주시겠습니까? 나는이 문제를 의심

+0

실제로 로그인 단추를 여러 번 실행하거나 클릭하는 방법을 기다렸습니까? – user3373870

+0

프로세스가 완료 될 때까지 기다렸다가 다시 시도했습니다. 프로세스를 다시 시작하기 전에 프로세스를 중지해야한다고 생각합니다. 그러나 나는 그것을 멈출 방법을 모른다. – FlySoFast

+1

작업을 완료해야 코드가 다시 나타납니다. 수동으로 중지하지 않아도됩니다. Jon Skeet 솔루션이 질문에 게시 된 방법을 확인하십시오. http://stackoverflow.com/a/4429552/3373870 – user3373870

답변

0

나는 방법 TrySetResult를 (사용하려고해야 다음 예외를 던질 수 가능성이 경우!

0

는이

public static Task<int> SignIn(string username, string password) 
{ 
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>(); 
    EventHandler<WebService.LoginCompletedEventArgs> onLoginCompleted = null; 
    onLoginCompleted = (object sender, WebService.LoginCompletedEventArgs e) => 
    { 
     service.LoginCompleted += onLoginCompleted; 
     if(e.Error != null) 
     { 
     tcs.SetResult(-1); 
     } 
     else 
     { 
     tcs.SetResult((int)e.Result); 
     } 
    }; 
    service.LoginCompleted += onLoginCompleted; 
    service.LoginAsync(username, password); 
    return tcs.Task; 
} 
을 시도 당신은 당신이 service.LoginCompleted

에 새 익명 이벤트 핸들러를 추가하는이 방법으로 전화를 걸 이벤트 핸들러마다 등록을 취소하지 않을 것입니다

또는 여담으로, 아마도이

public static Task<int> SignIn(string username, string password) 
{ 
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>(); 
    EventHandler<WebService.LoginCompletedEventArgs> onLoginCompleted = (object sender, WebService.LoginCompletedEventArgs e) => 
    { 
     if(e.Error != null) 
     { 
     tcs.SetResult(-1); 
     } 
     else 
     { 
     tcs.SetResult((int)e.Result); 
     } 
    }; 
    service.LoginCompleted += onLoginCompleted; 
    tcs.Task.ContinueWith(task => service.LoginCompleted -= onLoginCompleted); 
    service.LoginAsync(username, password); 
    return tcs.Task; 
} 

, 당신은 또한 방법 일주하는 보편적 인 try/catch를 제거해야 모든 상황에서 tcs.Task을 반환하십시오.

실제로 service.LoginAsync(username, password) 당신이이 일을 대신 SetResult()의 등)이

... 
try 
{ 
    service.LoginAsync(username, password); 
} 
catch(SomeParticularException ex) 
{ 
    tcs.SetException(ex); 
} 
return tcs.Task; 
관련 문제