【问题标题】:WCF defines it's own version of a DataObject in the Service ReferenceWCF 在服务参考中定义了它自己的 DataObject 版本
【发布时间】:2016-10-14 15:55:28
【问题描述】:

我创建了一个对象,我想在 WCF 调用中传递它……但在 ServiceReference1 中……这个对象被重新定义……有没有办法在任何地方都使用原始对象……似乎人们已经这样做了,但我无法弄清楚我做错了什么。

该对象用作服务合同中函数的参数。

    [OperationContract(IsOneWay = true)]
    void UpdateInformation(MyObject myObject);

当我尝试从客户端调用函数时出现的错误是“参数 1:无法从‘MyNameSpaceDTO.MyObject’转换为‘MyNameSpace.ServiceReference1.MyObject’”

对象在它自己的类库dll中,并用[DataObject]和[DataMember]属性标记。

namespace MyNameSpaceDTO
{
    [DataContract]
    public class MyObject
    {
        [DataMember]
        public string Name { get; set; }
    ….

但是,在将服务引用添加为之后,也会在 Reference.cs 中结束:

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="MyObject", Namespace="http://schemas.datacontract.org/2004/07/MyNameSpaceDTO")]
[System.SerializableAttribute()]
public partial class MyObject : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {

    [System.NonSerializedAttribute()]
    private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

    [System.Runtime.Serialization.OptionalFieldAttribute()]
    private string NameField;
    ...

另外,我确实在“添加服务参考”的“高级”部分设置了以下内容:

[x] 在引用的程序集中重用类型

(o) 在所有引用的程序集中重用类型

【问题讨论】:

  • 您的解决方案结构如何?我想有几个程序集:一个包含 DTO 的合同程序集,另一个托管服务的程序集和第三个作为该服务的客户端的程序集?
  • 我有一个用于 DTO...一个包含客户端和服务代码的库...然后是两个 WinForms 应用程序,一个实例化并使用客户端函数,另一个实例化和使用服务功能。
  • 好的,您在客户端应用程序中通过添加服务引用对话框引用了该服务?

标签: c# wcf idataobject


【解决方案1】:

对于使用 WCF 服务,您经常会看到示例(它们无疑是可取的!),其中指示您通过 添加服务引用 对话框添加该服务。通过以这种方式引用服务,您的客户端应用程序从服务公开的 WSDL 创建代理类。

因此,您最终会获得例如合同程序集中的类MyNameSpaceDTO.MyObject 和客户端应用程序中的MyNameSpace.ServiceReference1.MyObject 是从WSDL 生成的。这可能似乎有些多余。

您可能需要此行为的一种情况可能如下:假设您想要使用您无法控制的任意公共 Web 服务。您无权访问定义类型等的合约程序集。在这种情况下,从公开的 WSDL 创建您自己的本地代理类是最佳的,因为这是您获取所需类型等的唯一方法。

但你的具体情况似乎有点不同。我认为您正在寻找的是共享合同。由于您控制着客户端服务器代码(并且两者都在同一个解决方案中愉快地生活在一起),因此您可以轻松地分享合同:

因此,您无需在客户端应用程序中添加服务引用(通过添加服务引用),您只需引用合同程序集(通过通常的添加引用 对话)。通过这样做,将只有一个MyNameSpaceDTO.MyObject,因为第二个永远不会创建并且不需要。这种方法称为合约共享。

请看一下那个例子:

编辑:

请注意一些更改:最重要的是您通常不希望共享包含您的服务实现逻辑的程序集。所以我从合同组件中提取了该部分并将其放入单独的实施组件中。通过这样做,您只需共享接口和类型,而不是实现逻辑。这一变化也反映在上面的屏幕截图中。

您可以使用以下类设置该小型解决方案:

合约 - IService1.cs:

[ServiceContract]
public interface IService1
{
    [OperationContract]
    string GetData(int value);
}

实施 - Service1.cs:

public class Service1 : IService1
{
    public string GetData(int value)
    {
        return string.Format("You entered: {0}", value);
    }
}

主机 - Program.cs:

class Program
{
    static void Main(string[] args)
    {
        var baseAddress = new Uri("http://localhost:8732/Design_Time_Addresses/Service1/");

        using (var host = new ServiceHost(typeof(Service1), baseAddress))
        {
            // Enable metadata publishing.
            var smb = new ServiceMetadataBehavior();
            smb.HttpGetEnabled = true;
            smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
            host.Description.Behaviors.Add(smb);

            // Open the ServiceHost to start listening for messages. Since no endpoints are
            // explicitly configured, the runtime will create one endpoint per base address
            // for each service contract implemented by the service.
            host.Open();

            Console.WriteLine("The service is ready at {0}", baseAddress);
            Console.WriteLine("Press <Enter> to stop the service.");
            Console.ReadLine();

            host.Close();
        }
    }
}

客户 - Program.cs:

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press <Enter> to proceed.");
        Console.ReadLine();

        var binding = new BasicHttpBinding();
        var endpoint = new EndpointAddress("http://localhost:8732/Design_Time_Addresses/Service1/");
        var channelFactory = new ChannelFactory<IService1>(binding, endpoint);

        // Create a channel.
        IService1 wcfClient1 = channelFactory.CreateChannel();
        string s = wcfClient1.GetData(42);
        Console.WriteLine(s);
        ((IClientChannel)wcfClient1).Close();

        Console.WriteLine("Press <Enter> to quit the client.");
        Console.ReadLine();
    }
}

【讨论】:

  • 你说“请看那个例子”...哪个例子?
  • 我的意思是屏幕截图(希望)直观地解释了我写的内容。
  • 好的...明白了...对不起,如果我很密集...但是现在...没有 ServiceReference1(因为我没有运行添加服务参考)...那么如何从我的客户端调用服务代码呢?
  • 这似乎解决了如何做到这一点:stackoverflow.com/questions/19675194/…
  • 是的,你可以这样做。
猜你喜欢
  • 2020-06-18
  • 1970-01-01
  • 1970-01-01
  • 2015-12-19
  • 2021-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多