2014-08-29 16 views
10

La nostra applicazione ha un sacco di chiamate a Task.Factory.StartNew (Azione azione). Sfortunatamente, quando si fa questo, la cultura non è impostata, e inoltre, non vi è alcuna gestione degli errori. Ho iniziato con una classe di avviamento che fare entrambe le cose:Posso intercettare Task.Factory.StartNew?

public static class TaskBuilder 
{ 
    private static Action<System.Exception> _exceptionCallback; 

    public static Task StartNew(Action action, CultureInfo cultureInfo, Action<System.Exception> exceptionCallback) 
    { 
     _exceptionCallback = exceptionCallback; 

     return Task.Factory.StartNew(() => 
     { 
      Thread.CurrentThread.CurrentUICulture = cultureInfo; 
      Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name); 

      action.Invoke(); 
     }).ContinueWith(t => ManageException(t.Exception), TaskContinuationOptions.OnlyOnFaulted); 
    } 

    private static void ManageException(System.Exception e) 
    { 
     if (_exceptionCallback != null) 
     { 
      _exceptionCallback(e); 
     } 
    } 
} 

Ma poi ho capito che un approccio migliore sarebbe un intercettore. Vorrei intercettare la chiamata a StartNew in modo che il nuovo thread contenga il codice di gestione della cultura e degli errori. Il mio tentativo di questo prodotto il seguente codice:

public class TaskInterceptionHandler : ICallHandler 
{ 
    public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) 
    { 
     Thread.CurrentThread.CurrentUICulture = // How do I get parent cultureInfo?; 
     Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(cultureInfo.Name); 

     var methodReturn = getNext().Invoke(input, getNext); 

     if (methodReturn.Exception != null) 
     { 
      // How do I throw the exception to the calling thread here? 
     } 
     return methodReturn; 
    } 

    public int Order { get; set; } 
} 

Qui è dove io sono perplesso. Innanzitutto, come posso ottenere il genitore CultureInfo? In secondo luogo Come restituisco l'eccezione al thread chiamante? e Come uso questa classe nelle mie chiamate? Cioè come sostituire l'esistente Task.Factory.StartNew (..)

Sto utilizzando Unity e sono in un territorio sconosciuto qui. Qualunque aiuto o guida sarebbe apprezzato, o c'è anche una soluzione migliore? Forse sto iniziando con il piede sbagliato?

sto usando .NET 4.5

La maggior parte del feedback che ricevo qui sotto sembra evitare la rotta di intercettazione. È sicuro assumere che usare un intercettore è la strada sbagliata? Se qualcuno mi può guidare in quella direzione, mi permetterebbe di fare un confronto. Se la risposta alla domanda è sì, mi piacerebbe sapere come?

+0

Quale versione di .NET stai usando? .NET 4.5 ha una proprietà 'CultureInfo.DefaultThreadCurrentCulture' (e la sua UICulture equivvalent) che ti permette di impostare la cultura per tutti i thread nel dominio dell'app. –

+0

Sto usando .NET 4.5 – Ray

+1

L'eccezione dovrebbe essere gestita dal codice che chiama 'StartNew' ispezionando il' Task' restituito, non passando una callback da eseguire quando c'è un'eccezione. Stai girando la gestione degli errori del TPL, che è una delle sue funzioni più utili. – Servy

risposta

1

Piuttosto che impostare la cultura in ogni attività, suggerisco di impostare le proprietà CultureInfo.DefaultThreadCurrentCulture e CultureInfo.DefaultThreadCurrentUICulture per impostare la cultura globalmente per tutti i thread futuri.

Per quanto riguarda la gestione degli errori, è probabilmente più facile da usare await in un blocco try/catch, invece di passare un delegato per gestire l'eccezione:

try 
{ 
    // Task.Run is similar to Task.Factory.StartNew, but easier to use 
    await Task.Run(...); 
} 
catch(Exception ex) 
{ 
    // handle it... 
} 

BTW, il meccanismo di gestione degli errori corrente non funziona se hai più di una attività in esecuzione allo stesso tempo, poiché c'è solo una _exceptionCallback per tutte le attività ...

+0

Ma dove posso mettere questo try catch? – Ray

+0

@Ray, mettilo nei punti in cui chiami 'Task.Factory.StartNew' (e non dimenticare l'attesa) –

Problemi correlati