我的第一个WCF服务器 - 使用“字符串”,但不能使用自定义界面?

时间:2011-09-11 17:45:20

标签: c# wcf

我已经实现了我的第一个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());
        }
    }
}

2 个答案:

答案 0 :(得分:2)

如果使用界面,则必须做两件事:

  1. 实现需要可序列化(使用DataContract - Attribute)
  2. 如果使用界面(这里是IConsoleDataImpl),你必须告诉服务known types
  3. 让您的生活更轻松,并使用DataContract及其成员使用DataMember属性修饰实现,并使用实现而不是接口。

    你可以找到很多关于这个here

    的信息

    (并且不要以“我”开始实现名称)

    这是一个没有已知类型的东西的返工,我想这会帮助你 第一步 - 不需要深入研究(Interfaces + KnownTypes)。

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

答案 1 :(得分:1)

那里有几个问题。首先,您的界面应标记为[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复制到客户端时才会有效。

希望有道理......