【问题标题】:What does adding Name and Namespace to DataContract do?将 Name 和 Namespace 添加到 DataContract 有什么作用?
【发布时间】:2010-09-27 20:18:48
【问题描述】:

我尝试调用一个名为 Register 的 WebInvoke 方法,该方法返回一个用户对象并立即返回该对象。如下所示:

User Register(User user)
{
    return user;
}

例如,当调用http://localhost:8081/user/register 时,我不确定 Name 和 Namespace 属性对 DataContract 属性有何作用?

我问的原因是因为我最初用 DataContract 属性装饰了我的类,如下所示:

[DataContract]
public class User
{
   // Properties
}

当我打开 Fiddler 并发送一个 Post 请求时,它说方法不允许,但是当我将 DataContract 更改为:

[DataContract(Name="User", Namespace="")]

成功了。

【问题讨论】:

    标签: c# wcf


    【解决方案1】:

    除了其他答案之外,DataContract 中的命名空间允许在不同的命名空间中使用两个同名对象 - 即版本控制。

    这两个对象可以作为不同的属性存在于 WSDL 中,并且只要它们具有不同的命名空间,它们就会成为已知的可反序列化类型:

    [DataContract(Namespace = "http://myservice/v1/thing")]
    V1.Thing
    
    [DataContract(Namespace = "http://myservice/v2/thing")]
    V2.Thing
    

    当然,它们也需要存在于您的 C# 代码中才能使其有效。或者,为了清楚起见,您也可以使用 Name 属性更改对象已知的名称。

    [DataContract(Name = "Thing")]
    V1.Thing
    
    [DataContract(Name= = "newThing")]
    V2.Thing
    

    当您的项目中的类名称发生更改时,您可以使用它,但您需要支持使用“旧”名称的现有客户端。

    总之,Name 和 Namespace 属性控制着您的对象在通过网络传输时如何被序列化和反序列化。当您设置它们时,您将控制客户端如何查看您的数据协定。

    【解决方案2】:

    Johann 的回答,IMO 是正确的。

    之所以如此,是因为当您发送 SOAP 消息时,元素需要有命名空间限定,否则 WCF 不知道如何将 SOAP 反序列化为用户数据协定,因为命名空间不匹配。

    在 C# 中,这两个对象是不同的,因为它们位于不同的命名空间中......

    namespace UserServices
    {
        public class User
        {
            public string FirstName { get; set; }
        }
    }
    
    namespace TempuriServices
    {
        public class User
        {
            public string FirstName { get; set; }
        }
    }
    

    XML / SOAP 中的命名空间具有相同的目的,以确保对象来自相同的“主体”/“公司”/“组织”/“域”等。

    根据我的发现,当我构建 SOAP 服务时,我倾向于将所有数据协定、服务协定和绑定命名空间保存在同一个命名空间中,例如"http://mycompany.com/services/serviceName"

    这里有一些很棒的资源... 数据合约等价 => http://msdn.microsoft.com/en-us/library/ms734767.aspx 数据契约版本控制最佳实践 => http://msdn.microsoft.com/en-us/library/ms733832.aspx

    希望这会有所帮助。

    【讨论】:

    • 我发现将我的服务合同(包括操作)放在一个命名空间中,并将我的数据对象放在另一个命名空间(通常只是添加“数据”)之后会更好。这是因为基础服务命名空间中有一些保留字,您可能会在不经意间与之发生冲突 - 会想到 methodnameResponse。
    【解决方案3】:

    这些属性控制 WSDL 中元素的名称空间和名称。代码中的重要部分是 Namespace="":这将覆盖默认命名空间 (http://tempuri.org) 并将其值设置为空 URL。

    最后,User 类将在 WSDL 中从 http://tempuri.org/User 重命名为简单的 User。

    【讨论】:

    • 但是,它是如何工作的?我的意思是,当命名空间是tempuri.org/User 而不是用户时,为什么它说方法不允许?
    【解决方案4】:

    除了其他答案,我会尝试将我所知道的添加到这个主题中。 简而言之,它们都使用您提供给这些属性的任何内容来覆盖 [DataContract] 和 [DataMember] (Name) 的默认名称和命名空间。 根据 MS 的 DataContractAttribute.Namespace 属性文档(它们被称为属性的 properties,而不是属性),在“提示”部分它指出 link,“为了成功传输数据, 数据协定中的数据名称在客户端和服务器端必须相同。默认情况下,Visual Basic 项目会为每个文件中定义的命名空间添加一个前缀(称为“根命名空间”,以project). 添加这个前缀会导致同一类型的客户端和服务端命名空间不同。解决方法是将Namespace属性设置为“”,或者在该属性中显式设置数据协定命名空间。” 据我了解,要使 DataContract 属性能够序列化/反序列化数据,数据必须在客户端和服务器端都具有匹配的命名空间,这在现实世界中可能并非总是如此。例如,如果以可读和合理的方式命名,您在服务器端的数据可能位于名称类似于“NameOfTheSolution.Server.NameOfTheProject”的名称空间下,而在客户端,它可能类似于“ NameOfTheSolution.Client.NameOfTheProject。”由于 DataContracts 所在的命名空间不同,[DataContract] 属性将无法序列化/反序列化客户端和服务器之间的数据。我不是肯定的,但这可能是它说在你的情况下不允许使用方法的原因,因为命名空间不匹配。在命名空间不匹配的情况下,可以在使用 [DataContract] 属性时使用“命名空间”属性,并为任一端(客户端/服务器)的类提供相同的命名空间,尽管它们实际上位于不同的命名空间中。

    [DataContract (Namespace = “Whatever you want, usually uri”)]
    public class User
    {}
    

    就 [DataContract] 属性的“名称”属性而言,它会使用您提供给该属性的名称覆盖您的数据合同的名称。在 DataMember 属性的上下文中,它的一种用途是重载数据协定中的方法。 DataContract 不允许两个 DataMember 具有相同的名称,因此在这种情况下,“Name”属性很有用。

    【讨论】:

      【解决方案5】:

      基于另一个问题和:

      我不确定名称和 命名空间属性对 调用时的 DataContract 属性 http://localhost:8081/user/register 例如?

      我建议您使用 REST 服务。当您在没有将命名空间设置为空字符串的情况下调用服务时,您是否使用命名空间 xmlns="http://tempuri.org" 定义了用户 XML?如果不是,您发送到服务不同/未知的“数据类型”,这可能是返回错误的原因。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-08-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多