Autofac WCF-CloseChannel在负载测试下多次调用

Autofac WCF-CloseChannel在负载测试下多次调用,wcf,autofac,asp.net-web-api2,Wcf,Autofac,Asp.net Web Api2,我正在分析一个webapi应用程序,该应用程序在负载(每秒100个请求)下速度严重减慢 应用程序调用第三方WCF服务 我使用的是dottrace,请注意,Autofac.Integration.Wcf.RegistrationExtensions.CloseChannel(T)在我的测试中被调用了>22k次(100个客户端/秒,持续1分钟) DotTrace已将其标识为热点 我根据Autofac WCF集成文档注册我的WCF: var bookingManagerFactory = new Ch

我正在分析一个webapi应用程序,该应用程序在负载(每秒100个请求)下速度严重减慢

应用程序调用第三方WCF服务

我使用的是dottrace,请注意,
Autofac.Integration.Wcf.RegistrationExtensions.CloseChannel(T)
在我的测试中被调用了>22k次(100个客户端/秒,持续1分钟)

DotTrace已将其标识为热点

我根据Autofac WCF集成文档注册我的WCF:

var bookingManagerFactory = new ChannelFactory<IBookingManager>("IBookingManager");

builder.Register(c => bookingManagerFactory).SingleInstance();

builder.Register(c => c.Resolve<ChannelFactory<IBookingManager>>().CreateChannel()).UseWcfSafeRelease();
var bookingManagerFactory=newchannelfactory(“IBookingManager”);
Register(c=>bookingManagerFactory).SingleInstance();
Register(c=>c.Resolve().CreateChannel()).UseWcfSafeRelease();
这种行为是预期的吗

在整个应用程序中,有许多类依赖于
IBookingManager


我的理解是,
InstancePerDependency
是默认的生存期-这适合我的场景吗?.InstancePerRequest()是否更适用(在CreateChannel()方法上?

简短的回答是:这是预期的,我认为这不是问题。

再深入一点:

Autofac会保留一次性对象,直到生命周期范围被释放,此时任何一次性对象都会被释放。(如果您将对象注册为
所有
,则可以手动处置对象,但如果是WCF内容,则我会将其保留。)

WCF通道是一个臭名昭著的挑战,因为它们是一次性的,但是
IDisposable
实现将在通道出现故障(例如,如果您得到错误响应)时引发异常,这实际上是非常糟糕的处理设计。无论如何,这就是
UseWcfSafeRelease
处理的内容-它通过根据频道的状态正确关闭和/或中止频道来确保正确处理频道
CloseChannel
只是处理正确清理的方法

如果你正在解析一组通道,这些通道都必须以某种方式清理。如果您看到
CloseChannel
被调用22000次,这意味着您解决了22000个需要安全清理的实例

我不知道我会改变生命范围。WCF的另一个问题是,如果通道出现故障,则无法重用(或重新打开)客户端代理。你完成了,你需要一个新的频道

优化解决方案的更好选择是在构造函数中解析
Func
每当需要代理时,调用该函数以获取新代理

public class MyConsumer
{
  private Func<IBookingManager> _factory;
  public MyConsumer(Func<IBookingManager> factory)
  {
    this._factory = factory;
  }
  public void DoWork()
  {
    this._factory().CallOperation(input);
  }
}
公共类消费者
{
私营Func_工厂;
公共消费者(Func工厂)
{
这个工厂=工厂;
}
公共工作
{
此._factory().调用操作(输入);
}
}
这有两个好处:

  • 如果类上的方法不需要解析通道,则可以保存通道的创建(和处置)
  • 如果处理错误(例如超时/重试),则可以在旧代理出现故障时创建新代理,并且类可以更容错

  • 除此之外,我不认为我会担心如何避免
    CloseChannel
    呼叫。如果需要优化,请优化您创建的通道数。

    传入惰性通道是否相同?惰性延迟解析,但仅适用于一个实例。如果您只需要一个,并且只需要用它打一个电话(或者不需要容错),那么懒惰是可以的。然而,它同样易于使用Func,并为您提供了更大的灵活性。根据你的情况,我强烈推荐Func而不是Lazy。当我通过Func时,我应该使用BeginInvoke吗?调用?都不是。我答案中的示例代码准确地显示了要做什么-就像调用函数一样调用它。啊,是的,我错过了()-谢谢,我会尝试的。我将注册更改为使用.InstancePerLifetimeScope()(在CreateChannel上)-这会导致问题吗?