8

这个问题与结合IIS 7.5的动态语言运行时中的Bug有关

ChannelFactory如果我为它提供正确类型的动态对象,则会挂起。

dynamic src = "MSFT";

var binding = new BasicHttpBinding();
var endpoint = new EndpointAddress("http://www.restfulwebservices.net/wcf/StockQuoteService.svc");
var channel = new ChannelFactory<IStockQuoteService>(binding, endpoint).CreateChannel();

// this will print just fine
Console.WriteLine(channel.GetStockQuote(src as string));

// this will print just fine
Console.WriteLine(new StockQuoteServiceClient().GetStockQuote(src));

// this will never print and the application will hang with no exceptions
Console.WriteLine(channel.GetStockQuote(src));
  • 上面的服务是公开的,不是我的,你可以自己测试这段代码,只要在代码中提供的endpoint添加服务引用即可;
  • StockQuoteServiceClient由 Add Service Reference 菜单项创建,并采用动态对象就好了;
  • 当我在调试时使用 F5 启动应用程序时,这神奇地不会发生,所有行都打印并且程序正确退出;
  • 如果我运行它,然后在执行期间附加调试器,我可以看到它挂在调用channel.GetStockQuote(src);
  • 如果我不管它,程序会吃掉我所有的记忆;
  • 仅当我将自己ChannelFactory的对象与动态对象一起使用时,它才会挂起,如评论中所述。

ChannelFactory当添加服务引用创建的对象运行良好时,为什么当它以动态对象作为参数时我的挂起?

4

1 回答 1

3

当您使用动态关键字时,与动态变量相关的每个代码都将由 DLR 在运行时编译。当您使用动态变量调用方法时,实际的方法签名在编译时是未知的,并且方法返回类型以及与之相关的所有内容都会创建 Eric Lippert 称为“动态传染”的东西:

“正如我上次指出的那样,当调用的参数是动态的时,编译器也很有可能将调用的结果分类为动态的;污点传播开来。事实上,当您使用几乎任何运算符时一个动态表达式,结果是动态类型,除了少数例外。(例如,“is”总是返回一个布尔值。)您可以“治愈”一个表达式,通过将其强制转换为对象或其他任何东西来防止它传播动态主义您想要的非动态类型;将动态转换为对象是一种身份转换。”

WCF 内部使用大量接口和抽象,并且 DLR 存在关于抽象和接口的已知限制,其中 DLR 无法解析正确的类型。(也看看这个 SO 讨论

我能够使用反射正确调用 ChannelFactory 并将参数转换为其他类型(并且还尝试使用错误的类型调用服务)。该问题必须与 DLR 相关。

我无法调试 DLR 编译,但问题可能与“动态传染”和接口解析错误有关。使用“传染”,WCF 调用的每个部分都可能在运行时编译,并且类型解析错误可能会在某些极端情况下创建一些 endles 循环,例如调用基方法的重写方法实现,而基类被错误地解析为同一个孩子班级。

当附加调试器 ( Debugger.IsAttached )时,一些 WCF 内部会执行额外的指令,这些指令通常包含在断言、检查和属性中。额外的指令可能会提供一些信息来杀死“动态传染”并避免虚假的无限循环。

于 2013-05-22T01:58:57.293 回答