我的第一个WCF服务器-工作与"字符串"但不适用于自定义界面

本文关键字:quot 字符串 不适用 适用于 自定义界面 第一个 WCF 工作 我的 服务器 | 更新日期: 2023-09-27 18:08:29

我实现了我的第一个WCF应用程序。我需要一个方法IConsoleData GetData();客户端收到CommunicationException "There was an error reading from the pipe: The channel was closed. (109, 0x6d)."

当我将IConsoleData GetData();替换为string GetData();时,应用程序变得可用。

我应该如何修复代码使用IConsoleData GetData() ?

服务器:

//public interface IConsoleData
//{
//    double GetCurrentIndicator();
//}
//public class IConsoleDataImpl : IConsoleData
//{
//    public double GetCurrentIndicator()
//    {
//        return 22;
//    }
//}
[ServiceContract]
public interface IMBClientConsole
{
    [OperationContract]
    //IConsoleData GetData();
    string GetData();
}
public class MBClientConsole : IMBClientConsole
{
    //public IConsoleData GetData()
    //{
    //    return new IConsoleDataImpl();
    //}
    public string GetData()
    {
        //return new IConsoleDataImpl();
        return "hello";
    }
}
class Log
{
    private ServiceHost _host;
    public void initialize()
    {
        _host = new ServiceHost(typeof (MBClientConsole),
                                new Uri[]
                                    {
                                        new Uri("net.pipe://localhost")
                                    });
            _host.AddServiceEndpoint(typeof(IMBClientConsole),
              new NetNamedPipeBinding(),
              "PipeReverse");
            _host.Open();
            System.Threading.Thread.Sleep(1000000);
            // TODO: host.Close();
    }
}
客户:

//public interface IConsoleData
//{
//    double GetCurrentIndicator();
//}
[ServiceContract]
public interface IMBClientConsole
{
    [OperationContract]
    //IConsoleData GetData();
    string GetData();
}
class Program
{
    static void Main(string[] args)
    {
        ChannelFactory<IMBClientConsole> pipeFactory =
            new ChannelFactory<IMBClientConsole>(
                new NetNamedPipeBinding(),
                new EndpointAddress(
                    "net.pipe://localhost/PipeReverse"));
        IMBClientConsole pipeProxy =
          pipeFactory.CreateChannel();
        while (true)
        {
            string str = Console.ReadLine();
            Console.WriteLine("pipe: " +
              //pipeProxy.GetData().GetCurrentIndicator());
              pipeProxy.GetData());
        }
    }
}

我的第一个WCF服务器-工作与"字符串"但不适用于自定义界面

如果你使用一个接口,你必须做两件事:

  1. 实现需要是可序列化的(使用DataContract - Attribute)
  2. 你必须告诉服务的已知类型如果你使用接口(这里是IConsoleDataImpl)

让你的生活更轻松,用DataContract装饰实现,用DataMember属性装饰它的成员,使用实现而不是接口。

你可以在这里找到很多关于这个的信息

(实现名称不要以"I"开头)

这是一个没有已知类型的东西的返工,我想这将有助于你的第一步-还没有必要深入挖掘(接口+ KnownTypes)。

[DataContract]
public class ConsoleData
{
    [DataMember]
    public double CurrentIndicator
    {
        get { return 22; }
        set { /* whatever */ }
    }
}
[ServiceContract]
public interface IMBClientConsole
{
    [OperationContract]
    ConsoleData GetData();
}

这里有几个问题。首先,你的接口应该被标记为[DataContract]

[DataContract]
public interface IConsoleData
{
    double GetCurrentIndicator();
}

现在,当WCF通过网络发送IConsoleData时,它将在类中序列化数据,发送它,并在客户端上反序列化它。您的实现的问题在于它不包含任何可以序列化的内容。

public class IConsoleDataImpl : IConsoleData
{
    public double GetCurrentIndicator()
    {
        return 22;
    }
}

如果要使用上面的svcutil.exe构建客户端,它将创建IConsoleDataImpl类,但GetCurrentIndicator方法不会做任何事情。这里的重要区别是:WCF将传输DATA,而不是IMPLEMENTATION。

可能想要的更像是:

[DataContract]
public interface IConsoleData
{
    [DataMember]
    double CurrentIndicator { get; set; }
}
public class ConsoleDataImpl : IConsoleData
{
    public double CurrentIndicator { get; set; }
}

[ServiceContract]
[KnownType(typeof(ConsoleDataImpl))]
public interface IMBClientConsole
{
    [OperationContract]
    IConsoleData GetData();
}
public class MBClientConsole : IMBClientConsole
{
    public IConsoleData GetData()
    {
        return new IConsoleDataImpl() { CurrentIndicator = 22 };
    }
}

虽然在这一点上,IConsoleData接口不是真的需要,我只是删除它。

但基本上要记住的是,一般来说,你希望你的WCF服务包含方法,你的数据契约包含属性(或字段)。如果您从WSDL生成客户端,则DataContract中方法内部的实现将不在客户端中,只有当您将带有DataContracts的共享dll复制到客户端时才会起作用。