wcf - Inheritance in callback contract

3 篇文章 0 订阅

I have a service decorated with a ServiceContract attribute, and the interface definition is something like this:

    [ServiceContract(CallbackContract = typeof(ITabularPushCallback))]
    public interface ITabularPushService
    {
        [OperationContract(IsOneWay = true)]
        void Subscribe(int tableId);

        [OperationContract(IsOneWay = true)]
        void UnSubscribe(int tableId);

        [OperationContract(IsOneWay = false)]
        bool IsSubscribed(int tableId);

    }

the callback contract of the interface ITabularPushService is ITabularCallback, the definition of the interface is like this:

    public interface ITabularPushCallback
    {
        // this will ensure that the Datagram transport will be used, the Callback does not rquire that the server to block 
        // and this is far more effecient than Bidirectional connection
        [OperationContract(IsOneWay = true)]
        void NotifyMessage(object[][] messages, int tableId);
    }

 

 

Notice it is not necessary to decorate the callback contract with the [ServiceContract] attribute, because 

msdn 写道
you don't need the [ServiceContract] attribute on the callback interface. The callback interface is just "an extra bad of [OperationContract] methods", and not really a contract entity itself. Think of it as merely an auxiliary part of the [ServiceContract] 'forward' interface. Second, all of the inheritance is through the [ServiceContract] ('forward') interfaces. When reflecting on the type, WCF will look through the contract's type hierarchy for parent interfaces that have [ServiceContract], and also pick up those parents' CallbackContracts.

 

This is just an side note, let's get back to our question before.
Now suppose that we have a new requirement to add a new method to the ITabularCallback, something like the Server heartbeat, we don't want to directly extend the interface because we feel this is so general that we want to make a separate interface for the heartbeat. so we go ahead to implement the code as such.

    /// <summary>
    /// Server HeartBeat interface
    /// </summary>
    public interface IHeartbeat
    {
        /// <summary>
        /// Server heartbeat
        /// </summary>
        /// <param name="timestamp">heartbeat timestamp</param>
        [OperationContract(IsOneWay = true)]
        void Heartbeat(long timestamp);
    }

 

 

then we will make our ITabularCallback interface to inherit from the IHeartbeat, quick and easy, shouldn't it be ? however, you might be greeted with a NotSupportedException. The messgae may contains the following.

Callback method Heartbeat is not supported, this can happen if the method is not marked with OperationContractAttribute or if its interface type is not the target of the ServiceContractAttribute's CallbackContract.

 Huh?

 

So we figured out somehow that WCF does not walk the tree of interface and do reflection to get all Operatoin members. (For details, please see the References on topic Inheritance not supported on callback contracts?)


since as we have pointed out, the ServiceContract willl forward interface to WCF system, so we can leverage this point. we can make a marker interface and decorate that with a ServiceContract attribute, which shall binds to Callback we have in mind - IHeartbeat, we caller the new interface IHeartbeatService, it is an empty interface, which serves here only for its side effect of ServiceContract attribute to forward its callback contract. 

    // Check 
    //   http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/ef896836-dec1-4fa6-9956-e3a4958643ce
    [ServiceContract(CallbackContract = typeof(IHeartbeat))]
    public interface IHeartbeatService
    {
    }

 

 

Now we have to refine the Service and its contract together...

 

    [ServiceContract(CallbackContract = typeof(ITabularPushCallback))]
    public interface ITabularPushService : IHeartbeatService
    {
        // same as before
    }

 and the new ITabularCallback interface.

    public interface ITabularPushCallback  : IHeartbeat
    {
        // ... same as before.
    }

 

 

now that both the IHeartbeat and ITabularCallback is forwarded you will not worry about getting the NotSupported excetion.

 

 

Explain on the Design: 

Suppose that we have 

 

 

[ServiceContract(Namespace="foo", CallbackContract=typeof(IBaseCB))] 
interface IBaseC { ... }

interface IBaseCB : IBaseBaseCB { ... }

interface IBaseBaseCB { [OperationContract] void F(); }

 

 

If we have reflection which goes up the tree, then it will have a F method in the namespace foo.

Now, if we add more interface, such as 

 

[ServiceContract(Namespace="bar", CallbackContract=typeof(IBaseBaseCB))]
interface IOther { ... }

 
then we might have another F in namespace "bar".

 

Now, we refine as such 

interface IDerivedCB : IBaseCB { ...}

[ServiceContract(CallbackContract=typeof(IDerivedCB))]
interface IDerivedC : IBaseC, IOther { ... }

 

 

Then how can wcf know which namespace F now in IDerviedC is?

 

Some other tips:

1.  putting [ServiceContract] attribute on a callback contract

msdn 写道
Yes, [ServiceContract] will be ignored when being referenced from another [SC]'s CallbackContract. But you can indeed still put it there if the CC is also an SC. Thus is it possible to model two servers that talk to each other:

 

To model two servers

[ServiceContract(CallbackContract=typeof(IPong)] interface IPing { ... }
[ServiceContract(CallbackContract=typeof(IPing)] interface IPong { ... }

 

Or even make that to a single contract (Peerchannel does this a bit)

[ServiceContract(CallbackContract=typeof(ISelf)] interface ISelf { ... }

 

 

References:Inheritance not supported on callback contracts?

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值