Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 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. ;)

like image 833
TrueWill Avatar asked Jan 20 '11 22:01

TrueWill


1 Answers

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>
like image 136
Neil Avatar answered Oct 12 '22 21:10

Neil