2017-02-07 1 views
0

Я выполнил имя службы ExamClient, которые имеют две операции один является Ping, которые возвращают основной string который означает сервис доступен и один FindStudy который поиск в БД может занять долго продолжаться.Лучший способ справиться с исключением в нескольких задач вызвать операцию WCF

В другой стороны, я несколько оконечных ExamClient я палочка запустить FindStudy за конечную точку по задаче так в Dispatcher у меня есть что-то вроде этого:

public FindStudies_DTO_OUT FindStudies(FindStudies_DTO_IN findStudies_DTO_IN) 
{ 
    List<Study_C> ret = new List<Study_C>(); 
    List<Task> tasks = new List<Task>(); 
    foreach (var sp in Cluster) 
    { 
     string serviceAddress = sp.GetLibraryAddress(ServiceLibrary_C.PCM) + "/Exam.svc"; 
     var task = Task.Run(() => 
     { 
      ExamClient examClient = new ExamClient(serviceAddress.GetBinding(), new EndpointAddress(serviceAddress), Token); 
      var ping = Task.Run(() => 
      { 
       examClient.Ping(); 
      }); 
      if (!ping.Wait(examClient.Endpoint.Binding.OpenTimeout)) 
      { 
       Logging.Log(LoggingMode.Warning, "Timeout on FindStudies for:{0}, address:{1}", sp.Name, serviceAddress); 
       return new List<Study_C>(); // if return null then need to manage it on ret.AddRange(t.Result); 
      } 
      return (examClient.FindStudies(findStudies_DTO_IN).Studies.Select(x => 
      { 
       x.StudyInstanceUID = string.Format("{0}|{1}", sp.Name, x.StudyInstanceUID); 
       x.InstitutionName = sp.Name; 
       return x; 
      })); 
     }); 
     task.ContinueWith(t => 
     { 
      lock (ret) 
      { 
       ret.AddRange(t.Result); 
      } 
     }, TaskContinuationOptions.OnlyOnRanToCompletion); 
     task.ContinueWith(t => 
     { 
      Logging.Log(LoggingMode.Error, "FindStudies failed for :{0}, address:{1}, EXP:{2}", sp.Name, serviceAddress, t.Exception.ToString()); 
     }, TaskContinuationOptions.OnlyOnFaulted); 

     tasks.Add(task); 
    } 
    try 
    { 
     Task.WaitAll(tasks.ToArray()); 
    } 
    catch (AggregateException aggEx) 
    { 
     foreach (Exception exp in aggEx.InnerExceptions) 
     { 
      Logging.Log(LoggingMode.Error, "Error while FindStudies EXP:{0}", exp.ToString()); 
     } 
    } 

    return new FindStudies_DTO_OUT(ret.Sort(findStudies_DTO_IN.SortColumnName, findStudies_DTO_IN.SortOrderBy)); 
} 

Сначала я должен запустить Ping в конечной точке чтобы узнать подключение установлено после этого FindStudy.

Если есть три конца пинты в Cluster, то шесть задач должны выполняться в параллельном режиме, 3 для Ping и 3 для FindStudy.

Я думаю, что что-то не так с моим кодом, чтобы справиться с исключением ... Итак, каков наилучший способ реализации этого сценария?

благодарит заранее.

+0

Вы не должны использовать 'Wait()' внутри своих задач, чтобы получить доступ к логике тайм-аута .... см. Ответ [здесь] (http://stackoverflow.com/questions/4238345/asynchronously-wait-for -taskt-to-complete-with-timeout) –

+0

Посмотрите также на комментарии относительно материала маркера отмены. Это действительно важно! –

+0

Я думаю, что я должен ждать, потому что время открытия составляет 3 секунды, если доступна конечная точка «Ping» получить ответ в течение 3 секунд. – Aria

ответ

1

Позвольте мне ответить, чтобы упростить и удалить ненужный блок кода. И немного объяснений по коду.

public FindStudies_DTO_OUT FindStudies(FindStudies_DTO_IN findStudies_DTO_IN) 
{ 
    // Thread-safe collection 
    var ret = new ConcurrentBag<Study_C>() 

    // Loop cluster list and process each item in parallel and wait all process to finish. This handle the parallism better than task run 
    Parallel.Foreach(Cluster, (sp) => 
    { 
     var serviceAddress = sp.GetLibraryAddress(ServiceLibrary_C.PCM) + "/Exam.svc"; 

     ExamClient examClient = new ExamClient(serviceAddress.GetBinding(), new EndpointAddress(serviceAddress), Token); 

     try 
     { 
      examClient.Ping();    
      // declare result variable type outside try catch to be visible below    
      var result = examClient.FindStudies(findStudies_DTO_IN); 
     } 
     catch(TimeoutException timeoutEx) 
     { 
      // abort examclient to dispose channel properly 
      Logging.Log(LoggingMode.Warning, "Timeout on FindStudies for:{0}, address:{1}", sp.Name, serviceAddress); 
     } 
     catch(FaultException fault) 
     { 
      Logging.Log(LoggingMode.Error, "FindStudies failed for :{0}, address:{1}, EXP:{2}", sp.Name, serviceAddress, fault.Exception.ToString()); 
     } 
     catch(Exception ex) 
     { 
      // anything else 
     } 
     // add exception type as needed for proper logging 

     // use inverted if to reduce nested condition 
     if(result == null) 
      return null; 

     var study_c = result.Studies.Select(x => 
     { 
      x.StudyInstanceUID = string.Format("{0}|{1}", sp.Name, x.StudyInstanceUID); 
      x.InstitutionName = sp.Name; 
      return x; 
     })); 

     // Thread-safe collection 
     ret.AddRange(study_c);  
    }); 

    // for sorting i guess concurrentBag has orderby; if not working convert to list 
    return new FindStudies_DTO_OUT(ret.Sort(findStudies_DTO_IN.SortColumnName, findStudies_DTO_IN.SortOrderBy)); 
} 

Примечание: код не проверял, но суть там. Также я чувствую, что task.run внутри task.run - плохая идея, не могу вспомнить, какую статью я прочитал (вероятно, от Стивена Клири не уверен).

+0

Спасибо за ваш ответ. Но я думаю, что это неправильное решение, потому что, если конечная точка недоступна, 'Ping' занимает много времени, чтобы получить ответ равным' receivetimeout'. – Aria

+0

Если im не ошибается, если конечная точка недоступна, он сразу же генерирует исключение. – jtabuloc

+0

Нет, вы ошибаетесь, это проверено по этой причине, я должен запустить задачу в другую задачу. – Aria

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