none
傅老师您好,请您帮我看看这个wcf的问题,我感觉像是wcf自身的问题导致的 RRS feed

  • 问题

  • 情况是这样的,公司的一个项目应用wcf作为数据传输架构,客户端传递自定义的类型数据,在服务端将其加入数据库,第一次编码后测试正常代码如下:

     

    Contract合约接口文件中:

    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
    [System.ServiceModel.ServiceContractAttribute(Namespace = "http://RMMSoft.RMM.Services", ConfigurationName = "RMMSoft.RMM.Services.IMembershipContract")]
    public interface IMembershipContract
    {

            [System.ServiceModel.OperationContractAttribute(Action = "http://RMMSoft.RMM.Services/IMembershipContract/AddMonitorSource", ReplyAction = "http://RMMSoft.RMM.Services/IMembershipContract/AddMonitorSourceResponse")]
            bool AddMonitorSource(Monitor_Source monitor_source);

    //这个就是我们传输用的函数,注意它的参数名monitor_source,以后它要出问题的

    }

     

        [System.Diagnostics.DebuggerStepThroughAttribute()]
        [System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
        public partial class MembershipContractClient : System.ServiceModel.ClientBase<RMMSoft.RMM.Services.IMembershipContract>, RMMSoft.RMM.Services.IMembershipContract
        {

            public bool AddMonitorSource(Monitor_Source monitor_source)
            {
                return base.Channel.AddMonitorSource(monitor_source);
            }
       }

     

    Service服务实现的文件:

     

        [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
        public class MembershipService : IMembershipContract
        {

    public bool AddMonitorSource(Monitor_Source monitor_source)
    {

    // 做增加数据到数据库的操作

    ...

    return true;

    }

    }

     

    如上代码在测试时运行正常!

     

     

    但事情没有结束,在后面的工作中,我重构每部分代码时使用了替换功能将部分monitor_source替换成了source,不知道大家意识有什么改变了吗?,在Contract合约接口文件中IMembershipContract中的函数参数被改写成source,而且其下面的MembershipContractClient 中函数参数名仍然叫monitor_source,就这么一点点不同,仅仅是参数名称不一致而以,结果是服务可以调用但是参数不能传递,服务端接收到的永远为Null,经过我一番仔细对比才找到这个不一致的地方,将其恢复成一致的参数名称后问题得以解决。

    我猜想这问题是和wcf将类型序列化成通用的xml描述有关,为了跨平台调用每个函数都要进行签名描述,参数个数,位置,类型,返回类型等,可能还特意的对参数名称进行显示描述,因此当两处名称不一致时导致xml的声明失败,以至于将函数描述成无参的了!

    根据已往的技术积累,我认为描述一个函数时我们只对其函数名称参数个数,每个参数的类型做为其‘函数签名’,甚至在c++中对函数的返回类型都忽略不计,其参数名称是没有意义的,因为在本地代码中,参数经过压栈和出栈的其顺序就确定了其身份,即便是在webservice的soap描述中也要说明参数的位置,因此没有必要特意申明参数名称,强制前后的参数名称要一致是没有什么意义的。

     

    以上是本人愚见,如有不同意见欢迎指正!

    • 已移动 孟宪会Moderator 2009年5月19日 9:55 ([Loc]From:Windows Vista 开发相关讨论)
    2008年3月7日 2:09

答案

  •  

     

    估计是SOAP的参数消息头变了吧,

    所以客户端永远无法把消息传递过去

     

    除非你为参数 命名 ,记得 有这个 attribute 来的

    2008年3月27日 2:45
  • Soap中的参数名称发生了变化。您可以通过类似于DataContract中通过Name属性来指定名字的方式来实现在SOAP消息中队应参数名称的自定义。

    WCF为了实现松耦合,其尽量保证SOAP消息中的特定域与具体编程语言无关的特性。这样可以尽可能屏蔽掉.NET CLR的特征,实现跨平台调用。c++中的做法主要是用于消除函数重载时可能发生的函数名混淆的问题,两者的目的不同。

    2008年4月2日 5:58
    版主
  • 其实你的理解是正确的

    如果想更清楚的弄清这个问题,最好是将请求和响应的soap消息记录出来,相比之下,你就更明白原因了。

    序列化的原则的确也和函数签名,参数签名,位置等有关系

    此类问题还有一个,就是参数,函数的命名与xml关键字冲突的时候,同样会引发此类问题

    2008年8月19日 4:32
  •  

    [OperationContract]
        int GetVal(int b);

     

    产生的soap报文为:

      <s:Body u:Id="_0">
        <GetVal xmlns="http://tempuri.org/">
          <b>1</b>
        </GetVal>
      </s:Body>

     

     

    [OperationContract]
        int GetVal(int monitor_source);

    的时候产生soap报文为:

    <s:Body u:Id="_0">
        <GetVal xmlns="http://tempuri.org/">
          <monitor_source>1</monitor_source>
        </GetVal>
      </s:Body>

    2008年8月19日 9:23

全部回复

  • 怎没人给回复呢?

    这样可不行,等傅老师了

    2008年3月10日 6:59
  • 客户端应该重新生成service reference。

     

    2008年3月25日 5:49
  •  

     

    估计是SOAP的参数消息头变了吧,

    所以客户端永远无法把消息传递过去

     

    除非你为参数 命名 ,记得 有这个 attribute 来的

    2008年3月27日 2:45
  • Soap中的参数名称发生了变化。您可以通过类似于DataContract中通过Name属性来指定名字的方式来实现在SOAP消息中队应参数名称的自定义。

    WCF为了实现松耦合,其尽量保证SOAP消息中的特定域与具体编程语言无关的特性。这样可以尽可能屏蔽掉.NET CLR的特征,实现跨平台调用。c++中的做法主要是用于消除函数重载时可能发生的函数名混淆的问题,两者的目的不同。

    2008年4月2日 5:58
    版主
  • 其实你的理解是正确的

    如果想更清楚的弄清这个问题,最好是将请求和响应的soap消息记录出来,相比之下,你就更明白原因了。

    序列化的原则的确也和函数签名,参数签名,位置等有关系

    此类问题还有一个,就是参数,函数的命名与xml关键字冲突的时候,同样会引发此类问题

    2008年8月19日 4:32
  •  

    [OperationContract]
        int GetVal(int b);

     

    产生的soap报文为:

      <s:Body u:Id="_0">
        <GetVal xmlns="http://tempuri.org/">
          <b>1</b>
        </GetVal>
      </s:Body>

     

     

    [OperationContract]
        int GetVal(int monitor_source);

    的时候产生soap报文为:

    <s:Body u:Id="_0">
        <GetVal xmlns="http://tempuri.org/">
          <monitor_source>1</monitor_source>
        </GetVal>
      </s:Body>

    2008年8月19日 9:23