【问题标题】:How do you get a WCF proxy to ctor a child collection?你如何获得一个 WCF 代理来 ctor 一个子集合?
【发布时间】:2011-05-20 21:13:48
【问题描述】:

我今天正在学习,我做了我的第一个非常简单的 WCF 服务。我创建了几个非常简单的类如下(这被简化了一点)......

//contact class  
public class Contact
{
    public int Id { get; set; }


    private ObservableCollection<Phone> _contactPhones = new ObservableCollection<Phone>();
    public ObservableCollection<Phone> ContactPhones
    {
        get { return _contactPhones; }
        set { _contactPhones = value; }
    }

    public string FirstName { get; set; }

    public string LastName { get; set; }
}
// phone class  
public class Phone
{
    public string PhoneNumber { get; set; }
    public PhoneTypes PhoneType { get; set; }
}

我有一个模拟存储库类,它返回联系人类的集合

class ContactRepositoryMock : IContactRepository
{
    private readonly ObservableCollection<Contact> _contactList;

    public ContactRepositoryMock()
    {
        _contactList = new ObservableCollection<Contact>();

        Contact contact = this.Create();
        contact.Id = 1;
        contact.FirstName = "Seth";
        contact.LastName = "Spearman";
        contact.ContactPhones.Add(new Phone(){PhoneNumber = "864-555-1111",PhoneType = PhoneTypes.Mobile});
        contact.ContactPhones.Add(new Phone(){PhoneNumber = "864-555-2222",PhoneType = PhoneTypes.Home});

        this.Save(contact);

    }
    public ObservableCollection<Contact> GetContacts()
    {
        return _contactList;
    }

}

未显示 Save 和 Create 方法,但 Save 添加到 _contactList 集合中,并且 Create 创建了一个新的联系人实例(请注意,Contact ctor 正在使用预先加载来初始化电话 _contactPhones 集合)

最后我围绕 ContactRepositoryMock.GetContacts 方法创建了一个 WCF 服务包装器,如下所示...

[ServiceContract(Namespace = "")]
[SilverlightFaultBehavior]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ContactsService
{
    private ContactRepositoryMock _contactRepository = new ContactRepositoryMock();

    [OperationContract]
    public ObservableCollection<Contact> GetContacts()
    {
        return _contactRepository.GetContacts();
    }
}

另一个项目是 Silverlight 项目(这确实是我今天要研究的内容。)

在那个项目中,我向我的 WCF 类添加了一个 Web 引用,Visual Studio 像往常一样添加了代理类。

我在项目中添加了一个MainPageViewModel如下:

public class MainPageViewModel : ViewModelBase
{
    public MainPageViewModel()
    {
        if (!IsDesignTime)
        {
            //GetContacts();   //not shown               
        }
        else
        {
            var contactList = new ObservableCollection<Contact>();

            var contact = new Contact {Id = 1, FirstName = "Seth", LastName = "Spearman"};
            contact.ContactPhones.Add(new Phone() { PhoneNumber = "864-555-1111", PhoneType = PhoneTypes.Mobile });
            contact.ContactPhones.Add(new Phone() { PhoneNumber = "864-555-2222", PhoneType = PhoneTypes.Home }); 
            contactList.Add(contact);

            Contacts= contactList;
        }
    }

    private ObservableCollection<Contact> _contacts;
    public ObservableCollection<Contact> Contacts
    {
        get { return _contacts; }
        set
        {
            if (value!=_contacts)
            {
                _contacts = value;
                OnPropertyChanged("Contacts");
            }
        }
    }
}

以及以下 XAML

<UserControl x:Class="MVVMDemo.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    xmlns:viewModels="clr-namespace:MVVMDemo.ViewModels"
    d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.Resources>
        <viewModels:MainPageViewModel x:Key="ViewModels" />
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot" 
          DataContext="{Binding Source={StaticResource ViewModels}}"
          Background="White">
    </Grid>
</UserControl>

这是了解错误的很多背景知识,最终可能是一个简单的解释。

XAML 行 &lt;viewModels:MainPageViewModel x:Key="ViewModels" /&gt; 下方有一个波浪线,并返回错误“无法创建 MainPageViewModel 的实例”。

我什至知道该错误的原因。如果我禁用 MainPageViewModel ctor 中的 contact.ContactPhones.Add ... 行,那么错误就会消失。

最后,我什至知道错误消失的原因。这是因为创建 WCF 代理类的参考文件没有初始化 ContactPhones 集合。

换句话说,在代理中生成的类 Reference.cs 中如果我更改读取的行...

private System.Collections.ObjectModel.ObservableCollection<MVVMDemo.WSProxy.Phone> ContactPhonesField;

private System.Collections.ObjectModel.ObservableCollection<MVVMDemo.WSProxy.Phone> ContactPhonesField = new ObservableCollection<Phone>();

然后我可以重新启用 contact.ContactPhones.Add... 行,错误就消失了。项目编译并运行。

所以...所有这些都只是问...我如何让 Visual Studio 生成一个代理类来初始化我的集合。还是我这样做的方式有缺陷?我错过了什么?

抱歉所有细节,但我不确定调用链中的哪个位置可能出现故障。在这个问题得到回答后,我还将利用所有这些细节再问几个问题。

赛斯

【问题讨论】:

    标签: c# wcf visual-studio-2010 proxy


    【解决方案1】:

    WCF 不调用任何构造函数(完全)。两种选择:

    • 添加反序列化回调 (MSDN)
    • 在属性中处理

    IMO 第二个更容易:

    ObservableCollection<Phone> _contactPhones;
    [DataMember]
    public ObservableCollection<Phone> ContactPhones
    {
        get { return _contactPhones ?? (
            contactPhones = new ObservableCollection<Phone>());
    }
    

    【讨论】:

    • +1。正如 Marc 提到的,WCF,或者更准确地说,DataContract 反序列化,或任何反序列化,只是创建填充对象,它不调用构造函数。
    • @rally25rs - 注意 XmlSerializer、JavaScriptSerializer 等确实​​调用了ctors
    • 真的吗?呵呵,我猜我从来没有注意到 XmlSerializer 调用构造函数。属性设置器方法怎么样?为什么 XmlSerializer 和 DataContractSerializer 在设计上有区别?
    • @rally25rs - 重新设置器,这取决于您是否将 field 标记为 DataMember,而不是 property。如果您标记该属性,它将使用该属性。如果您不使用 DataMember 等,它的作用类似于 BinaryFormatter,即字段序列化器。重新为什么....谁知道呢。
    【解决方案2】:

    尝试在 MainPageViewModel 的构造函数中添加电话号码之前添加此行:

    contact.ContactPhones = new ObservableCollection();

    【讨论】:

      【解决方案3】:

      我不会花很多精力让 WCF 生成子集合。如果您必须重新生成代理服务,您的工作将被彻底清除。如果您将 WCF 类视为您的模型,我会创建您的模型并将其转换为 ViewModel。这样做的好处是您的 ViewModel 实现可以包含映射代码以将模型显式转换为 ViewModel。每次生成 Reference.cs 时都不必重写或更新 ViewModel 类。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-12-09
        • 1970-01-01
        • 1970-01-01
        • 2011-05-17
        • 2021-01-15
        • 2011-01-31
        相关资源
        最近更新 更多