- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我开始使用 ninject 拦截器来用各种行为包装我的一些异步代码,但在让一切正常工作时遇到了一些麻烦。
这是我正在使用的拦截器:
public class MyInterceptor : IInterceptor
{
public async void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
//check that method indeed returns Task
await (Task) invocation.ReturnValue;
RecordSuccess();
}
catch (Exception)
{
RecordError();
invocation.ReturnValue = _defaultValue;
throw;
}
}
这似乎在大多数正常情况下都能正常运行。我不确定这是否会达到我的预期。虽然它似乎将控制流异步返回给调用者,但我仍然有点担心代理无意中阻塞线程或其他东西的可能性。
除此之外,我无法使异常处理正常工作。对于这个测试用例:
[Test]
public void ExceptionThrown()
{
try
{
var interceptor = new MyInterceptor(DefaultValue);
var invocation = new Mock<IInvocation>();
invocation.Setup(x => x.Proceed()).Throws<InvalidOperationException>();
interceptor.Intercept(invocation.Object);
}
catch (Exception e)
{
}
}
我可以在拦截器中看到 catch block 被命中,但我的测试中的 catch block 从未被重新抛出命中。我更困惑,因为这里没有代理或任何东西,只有非常简单的模拟和对象。我还在测试中尝试了 Task.Run(() => interceptor.Intercept(invocation.Object)).Wait();
之类的东西,但仍然没有变化。测试顺利通过,但 nUnit 输出确实有异常信息。
我想我把事情搞砸了,而且我并不像我认为的那样完全理解正在发生的事情。有没有更好的方法来拦截异步方法?关于异常处理,我做错了什么?
最佳答案
我建议您阅读我的 async
/await
intro ,如果您还没有这样做的话。您需要很好地掌握 async
方法如何与其返回的 Task
相关,以便拦截它们。
考虑您当前的 Intercept
实现。正如 svick 评论的那样,最好避免 async void
。原因之一是错误处理不寻常:async void
方法的任何异常都会直接在当前 SynchronizationContext
上引发。
在您的情况下,如果 Proceed
方法引发异常(就像您的 mock 那样),那么您的 async void Intercept
实现将引发异常,该异常将被发送直接到 SynchronizationContext
(which is a default - or thread pool - SynchronizationContext
since this is a unit test,正如我在我的博客中解释的那样)。因此,您会看到该异常是在某个随机线程池线程上引发的,而不是在单元测试的上下文中引发的。
要解决此问题,您必须重新考虑 Intercept
。常规拦截只允许您拦截 async
方法的 first 部分;要响应 async
方法的结果,您需要在返回的 Task
完成时做出响应。
这是一个简单的示例,它只捕获返回的 Task
:
public class MyInterceptor : IInterceptor
{
public Task Result { get; private set; }
public void Intercept(IInvocation invocation)
{
try
{
invocation.Proceed();
Result = (Task)invocation.ReturnValue;
}
catch (Exception ex)
{
var tcs = new TaskCompletionSource<object>();
tcs.SetException(ex);
Result = tcs.Task;
throw;
}
}
}
您可能还想运行 NUnit 2.6.2 or later, which added support for async
unit tests .这将使您能够等待
您的MyInterceptor.Result
(这将在单元测试上下文中正确引发异常)。
如果你想要更复杂的异步拦截,你可以使用async
- 而不是async void
。 ;)
// Assumes the method returns a plain Task
public class MyInterceptor : IInterceptor
{
private static async Task InterceptAsync(Task originalTask)
{
// Await for the original task to complete
await originalTask;
// asynchronous post-execution
await Task.Delay(100);
}
public void Intercept(IInvocation invocation)
{
// synchronous pre-execution can go here
invocation.Proceed();
invocation.ReturnValue = InterceptAsync((Task)invocation.ReturnValue);
}
}
不幸的是,拦截必须同步进行,所以不可能有异步预执行(除非你同步等待它完成,或者使用IChangeProxyTarget
)。不过,即使有这个限制,您也应该能够使用上述技术做几乎任何您需要做的事情。
关于c# - 使 Ninject 拦截器与异步方法一起工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13630548/
有人在 monodroid 项目中使用 ninject 吗? 如果是这样,将不胜感激有关实现这一目标的任何指示/细节。 最佳答案 我还没有尝试在 Mono For Android 中使用 Ninjec
我找到了this article关于 Ninject 早期版本中的上下文变量。我的问题有两个方面。首先,如何使用 Ninject 2 获得这种行为?其次,上下文变量是否沿着请求链传递?例如,假设我想替
我有一个场景,只要一个对象上的方法返回 true,多个并发 Web 请求就应该重用一个对象。有问题的对象是线程安全的。 所以我需要当前范围内的对象来确定它是否仍在范围内。使用 Ninject 完成此任
我刚刚使用 Ninject 3 更新了我的应用程序。将 App_Start 中的文件从 NinjectMVC3 更改为 NinijectWebCommon.cs。移动了我的文件,更新了 DLLs..
我在 MVC4 应用程序中使用 Ninject 进行 DI 和 Ninject.MVC3 扩展,特别是版本 3.0.0.6。 阅读documentation在 Ninject 的 wiki 上,使用
如何绑定(bind)InitializerForXXX (非通用实现)到 IInitializer (通用接口(interface))使用 Ninject Conventions以便请求 IIniti
我正在开发一个框架扩展,它使用 Ninject 作为 IoC 容器来处理动态注入(inject),但是我在尝试解决如何实现这一点时遇到了一些麻烦。 我的框架的期望是您将传递 IModule(s)所以它
我确信这是一个愚蠢的问题,因为我假设答案是“当对象被 Ninject 实例化时”......但我想仔细检查...... 为了提供更多关于我为什么问这个问题的背景信息,我有一个实现 NinjectHtt
与其手动绑定(bind)每个类,不如推荐哪些方法和模式(如果有)来自动设置绑定(bind)? 例如,绝大多数绑定(bind)看起来像这样: Bind.To(); 一旦模块变大,您最终可能会得到 100
我试图找到一种将构造函数参数传递给子类的构造函数的方法。 这些对象是不可变的,所以我更喜欢使用构造函数参数。 我遇到的问题是 ConstructorArgument 不继承到子实例化,并且以下语句不可
我正在尝试为事件代理/消息代理的开发找到最新的 Ninject 扩展。 我至少可以找到 3 个:messagebroker , weakeventmessagebroker和 bbveventbrok
我有一个 WebApi 服务,我正在尝试使用 Ninject BindHttpFilter 添加身份验证。 使用 BindHttpFilter 允许我将身份验证过滤器绑定(bind)到特定属性。 Au
Autofac 自动为 Func 生成工厂;我什至可以传递参数。 public class MyClass { public MyClass(Func a, Func b) {
我有一个类需要为其类中的一个方法使用 IRepository。 理想情况下,我希望避免将这种依赖关系解析到类的构造函数中,因此我在 Ninject 中发现了方法级注入(inject),并且想知道这是如
我看到了枚举给定服务(类型)的绑定(bind)列表的方法,但我找不到返回已加载模块中绑定(bind)的所有内容列表的方法。我正在寻找类似Kernel::IEnumerable GetAllRegist
对于初学者,我正在使用这个模块: public class AutoMapperModule : NinjectModule { public override void Load()
我想知道 ninject 是否有可能拦截我类的私有(private)方法。我正在尝试进行一些 aop 编程以动态注入(inject)日志记录机制。 最佳答案 不幸的是,所有要拦截的方法都必须是virt
我是 Ninject 的新手,正在努力让这个测试通过。 (此测试通过 Autofac,但行为在 Ninject 中似乎有所不同)。 [Test] public void RegisterInstanc
我在一个小项目中使用过 Ninject,但现在正在将一个较大的 Web 应用程序转换为 mvc,并且需要有关使用 Ninject 的帮助。在新的解决方案中,我拥有 mvc 站点并将一些功能拆分到单独的
目前,我正在使用 ninject 执行以下绑定(bind)的命令模式: kernel.Bind>().To(); kernel.Bind>().To(); kernel.Bind>().To(); 我
我是一名优秀的程序员,十分优秀!