我可以拦截 Task.Factory.StartNew 吗?

Posted

技术标签:

【中文标题】我可以拦截 Task.Factory.StartNew 吗?【英文标题】:Can I intercept Task.Factory.StartNew? 【发布时间】:2014-10-23 21:32:43 【问题描述】:

我们的应用程序有很多对 Task.Factory.StartNew(Action action) 的调用。不幸的是,这样做时,没有设置文化,而且没有错误处理。我从一个可以同时做这两件事的入门课程开始:

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);
        
    

但后来我意识到更好的方法是拦截器。我想拦截对 StartNew 的调用,以便新线程包含文化和错误处理代码。我对此的尝试产生了以下代码:

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; 

这就是我难过的地方。首先,我如何获得父 CultureInfo?其次如何将异常返回给调用线程?以及如何在通话中使用此类? IE。如何替换现有的 Task.Factory.StartNew(..)

我正在使用 Unity,但在这里我处于陌生的领域。任何帮助或指导将不胜感激,或者是否有更好的解决方案?也许我的出发点不对?

我正在使用 .NET 4.5

我在下面得到的大部分反馈似乎都避开了拦截器路线。假设使用拦截器是错误的方法是否安全?如果有人可以指导我朝那个方向发展,那将允许我进行比较。如果问题的答案是肯定的,我想知道如何?

【问题讨论】:

您使用的是哪个版本的 .NET? .NET 4.5 有一个 CultureInfo.DefaultThreadCurrentCulture 属性(及其 UICulture 等效项),可让您为应用程序域中的所有线程设置区域性。 异常的东西应该由调用StartNew的代码检查返回的Task来处理,而不是在出现异常时传入回调来执行。您正在关闭 TPL 的错误处理,这是它最有用的功能之一。 @Ray 你应该看看implementing a custom TaskScheduler @Servy,他并没有真正“关闭”TPL 的错误处理,因为他正在传递一个委托来处理异常。然而,他这样做的方式不是线程安全的,这对于与线程相关的类来说可能不是一件好事;) @ThomasLevesque 他正在关闭 TPL 错误处理。他正在从返回的任务中抑制异常。他正在用他自己单独的错误处理形式替换 TPL 的错误处理,并传入一个委托。我在第一条评论中说过。他不只是完全抑制所有错误,他正在做的是将错误处理机制从 TPL 转变为他自己的。我是说他不应该那样做。哦,他所做的事情本身并没有什么不安全的地方,只是不太方便。 【参考方案1】:

建议您设置CultureInfo.DefaultThreadCurrentCultureCultureInfo.DefaultThreadCurrentUICulture 属性,以便为所有未来线程全局设置文化,而不是在每个任务中设置文化。

关于错误处理,在 try/catch 块中使用 await 可能比传递委托来处理异常更容易:

try

    // Task.Run is similar to Task.Factory.StartNew, but easier to use
    await Task.Run(...);

catch(Exception ex)

    // handle it...

顺便说一句,如果您同时运行多个任务,您当前的错误处理机制将不起作用,因为所有任务只有一个 _exceptionCallback...

【讨论】:

但是我应该把这个 try catch 放在哪里? @Ray,把它放在你打电话给Task.Factory.StartNew的地方(别忘了await

以上是关于我可以拦截 Task.Factory.StartNew 吗?的主要内容,如果未能解决你的问题,请参考以下文章

我可以拦截 Task.Factory.StartNew 吗?

fiddler怎么拦截修改数据

Axios 拦截器不会在页面加载时拦截

@AroundInvoke拦截器在@WebService类上被调用两次

mybatis 实现 SQL 查询拦截修改详解

vue设置了全局http拦截器,如何使某个页面不使用拦截器进行拦截,可以直接敲url访问?