【IT168 评论】这确实是一个让人觉得“无语”的BUG,甚至让我觉得微软在故意和我们开玩笑。这个问题在我刚刚接触WCF的时候就遇到过,换言之,这个问题一直存在于.NET 3.0、3.5和现在的4.0。这是一个关于在你对WCF进行扩展的时候会经常碰到的问题,读者朋友们可以根据下面的步骤来再现这一个问题。
创建自定义行为(服务行为、终结点行为、契约行为和操作行为)是对WCF进行扩展最为常用的形式。通过下面的代码,我们创建了一个自定义的服务行为,为了简单我们没有编写任何逻辑代码。
namespace Artech.Bug4BehaviorExtension
{
public class FooBehavior : IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { }
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
}
}
{
public class FooBehavior : IServiceBehavior
{
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters) { }
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { }
}
}
自定义服务行为可以通过两种方式应用到WCF运行时框架中:自定义特性(Attribute)和配置。现在我们采用后面一种,为此我们需要为上面创建的FooBehavior创建相应的BehaviorExtensionElement(本质上是一个ConfigurationElement):FooBehaviorElement。
namespace Artech.Bug4BehaviorExtension
{
public class FooBehaviorElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(FooBehavior); }
}
protected override object CreateBehavior()
{
return new FooBehavior();
}
}
}
{
public class FooBehaviorElement : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(FooBehavior); }
}
protected override object CreateBehavior()
{
return new FooBehavior();
}
}
}
接下来,我们创建一个简单的WCF服务来使用上面的服务行为,下面是服务和服务契约的定义。
namespace Artech.Bug4BehaviorExtension
{
[ServiceContract(Namespace="http://www.artech.com/")]
public interface ICalculator
{
[OperationContract]
double Add(double x, double y);
}
public class CalculatorService : ICalculator
{
public double Add(double x, double y)
{
return x + y;
}
}
}
{
[ServiceContract(Namespace="http://www.artech.com/")]
public interface ICalculator
{
[OperationContract]
double Add(double x, double y);
}
public class CalculatorService : ICalculator
{
public double Add(double x, double y)
{
return x + y;
}
}
}
我采用IIS寄宿(Host)的方式来寄宿CalculatorService服务,为此我们创建一个.svc文件。该文件的内容如下:
<%@ ServiceHost Service="Artech.Bug4BehaviorExtension.CalculatorService"%>
通过如下的配置,上面定义的FooBehavior被应用到了CalculatorService服务上面。行为扩展的类型为:“Artech.Bug4BehaviorExtension.FooBehaviorElement, Artech.Bug4BehaviorExtension”(注意这是关键)。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="myServiceBehavior">
<foo/>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="foo" type="Artech.Bug4BehaviorExtension.FooBehaviorElement, Artech.Bug4BehaviorExtension" />
</behaviorExtensions>
</extensions>
<services>
<service behaviorConfiguration="myServiceBehavior" name="Artech.Bug4BehaviorExtension.CalculatorService">
<endpoint binding="ws2007HttpBinding" contract="Artech.Bug4BehaviorExtension.ICalculator" />
<host>
<baseAddresses>
<add baseAddress="http://127.0.0.1:3721/calculatorservice" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="myServiceBehavior">
<foo/>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="foo" type="Artech.Bug4BehaviorExtension.FooBehaviorElement, Artech.Bug4BehaviorExtension" />
</behaviorExtensions>
</extensions>
<services>
<service behaviorConfiguration="myServiceBehavior" name="Artech.Bug4BehaviorExtension.CalculatorService">
<endpoint binding="ws2007HttpBinding" contract="Artech.Bug4BehaviorExtension.ICalculator" />
<host>
<baseAddresses>
<add baseAddress="http://127.0.0.1:3721/calculatorservice" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>