Is a generic BehaviorExtensionElement possible?
I have some service behaviors for WCF services that I just want to register; there's no configuration. I figured I could skip creating a BehaviorExtensionElement开发者_Python百科 descendant each time by using generics:
public class SimpleBehaviorExtensionElement<TBehavior> : BehaviorExtensionElement
where TBehavior: new()
{
protected override object CreateBehavior()
{
return new TBehavior();
}
public override Type BehaviorType
{
get { return typeof(TBehavior); }
}
}
And in Web.config:
<behaviorExtensions>
<add name="myBehavior2"
type="WcfService1.SimpleBehaviorExtensionElement`1[[WcfService1.MyBehavior,
WcfService1]], WcfService1"/>
</behaviorExtensions>
WcfService1.MyBehavior exists, implements IServiceBehavior, and has been tested.
But when I reference <myBehavior2/> in the behavior section of the config file, I get:
An error occurred creating the configuration section handler for system.serviceModel/behaviors: Extension element 'myBehavior2' cannot be added to this element. Verify that the extension is registered in the extension collection at system.serviceModel/extensions/behaviorExtensions. Parameter name: element
Everything works if I create a non-generic BehaviorExtensionElement descendant, which I can do. But now it bugs me. ;)
Unfortunately this is not possible with config files, at least not in a reliable fashion.
The reason is that if you have a generic class class A<T>
and a class parameter class B
the framework will not create a the class A<B>
until you declare a type of A<B>
by using it. The name in the format A`1[[B, Assm]] is just the name that gets created at run time - it means the generic "A" that takes 1 parameter created with the following types. It is not a cue to a type factory - which is what you need for what you are doing. So you might be able to get this to work if you are lucky and A<B>
happens to have been declared, but I would not rely on it.
This is, I believe, fixed in the data contract serialization that is used by later parts of the framework, but config is old. If you look at XAML there is the ability to use a type arguments with a type:
<scg3:Dictionary x:TypeArguments="x:String, x:Object">
Note this is an Explicit instruction to a type factory - something that the config parser does not have.
So sadly this leaves you with the expense of declaring a concrete type for each extension - but it is not a lot of work :
public class MyBehaviorExtensionElement :
SimpleBehaviorExtensionElement<MyBehavior> {}
And on the plus side it makes your config file more readable.
<behaviorExtensions>
<add name="myBehavior"
type="BehaviorTest.MyBehaviorExtensionElement, ServiceLibrary"/>
</behaviorExtensions>
Yes, it is possible.
I guess the reason the exception is getting thrown is because of way behavior elements are added WCF extensions without including the assembly version.
When specifying the type of the behavior, Version, Culture and PublicKeyToken attributes MUST be added as well. Please also note that there MUST be exactly one space after each , (comma), and the attributes MUST appear in aforementioned order.
So, in your example, following should work:
<behaviorExtensions>
<add name="myBehavior2"
type="WcfService1.SimpleBehaviorExtensionElement`1[[WcfService1.MyBehavior, WcfService1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], WcfService1" />
</behaviorExtensions>
精彩评论