我创建了一个非常简单的服务器和客户端控制台应用程序,演示了我遇到的问题,我试图将可序列化对象的实例传递给客户端,但它在服务器上失败。
我错过了什么?我并不担心现在使用DataContracts进行面向服务 - 我只是想了解为什么现在的代码不会将EJob带到客户端(但它会调用'来自服务器的消息'消息)< / p>
非常感谢。
修改
即使我使用DataContract属性(如下所示)装饰EJob类,它仍然无效 - 我在客户端收到的对象将LastName设置为null ?????
[DataContract]
public class EJob
{
[DataMember]
public string LastName = "Smith";
}
服务器
namespace testServer
{
[ServiceContract()]
public interface IRemoteClient
{
[OperationContract]
void SayHi(string msg);
[OperationContract]
void ProcessJob(EJob job);
}
[Serializable()]
public class EJob
{
public string LastName = "Smith";
}
class Program
{
static void Main(string[] args)
{
MngrServer.SendJob();
}
}
public class MngrServer
{
public static void SendJob()
{
try
{
// send this off to the correct exe
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, true);
string address = string.Format("net.tcp://localhost:33888/BatchMananger/client");
EndpointAddress epa = new EndpointAddress(address);
// create the proxy pointing to the correct exe
IRemoteClient clientProxy = ChannelFactory<IRemoteClient>.CreateChannel(binding, epa);
clientProxy.SayHi("Hello from server"); <-- THIS WORKS FINE
EJob job = new EJob { LastName = "Janssen" };
clientProxy.ProcessJob(job); <-- THIS RAISES AN EXCEPTION see below...
}
catch (Exception ex)
{
string msg = ex.Message;
//The formatter threw an exception while trying to deserialize the message: There was an error while
//trying to deserialize parameter http://tempuri.org/:job. The InnerException message was ''EndElement' 'job'
//from namespace 'http://tempuri.org/' is not expected. Expecting element 'LastName'.'.
}
}
}
}
客户端
namespace testClient
{
[ServiceContract()]
public interface IRemoteClient
{
[OperationContract]
void SayHi(string msg);
[OperationContract]
void ProcessJob(EJob job);
}
[Serializable()]
public class EJob
{
public string LastName = "Smith";
}
class Program
{
static void Main(string[] args)
{
MngrClient.Prepare();
Console.ReadLine();
}
}
/// <summary>
/// STATIC / INSTANCE
/// </summary>
public class MngrClient : IRemoteClient
{
public void SayHi(string msg)
{
Console.WriteLine(msg);
}
public void ProcessJob(EJob job)
{
Console.WriteLine(job.LastName);
}
public static void Prepare()
{
// allow this class to be used! - so instances are created and info directly passed on to its static members.
ServiceHost sh = new ServiceHost(typeof(MngrClient));
// create the net binding
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, true);
// define the tcpaddress
string address = string.Format("net.tcp://localhost:33888/BatchMananger/client");
// add a service point so my server can reach me
sh.AddServiceEndpoint(typeof(IRemoteClient), binding, address);
// now open the service for business
sh.Open();
}
}
}
答案 0 :(得分:2)
您的EJob datacontract位于服务器与客户端的不同命名空间中。您需要在同一名称空间中声明这两个类,或使用属性在客户端上设置名称空间以匹配服务器上的名称空间
(Datacontract属性有一个你可以传递的命名空间值,或者你可以使用一个单独的命名空间属性来告诉WCF使用备用命名空间用于合同,不记得我的头顶了)
修改强> 刚验证 - 它是您想要的DataContractAttribute的Namespace属性,因此在您的客户端声明中:
[DataContract(Namespace="EJobNamespaceAsItIsDeclaredOnTheServer")]
public class EJob ...
现在,将所有DataContracts放在客户端和服务器都引用的单独程序集(称为契约程序集)中是很常见的。您只需要该程序集中的合同类定义,不需要其他任何内容。
答案 1 :(得分:0)
你以某种方式让它有点倒退......
根据IRemoteClient
的服务合同,您应该在服务器端有一个实现该接口的实现类:
public class ServiceImplementation : IRemoteClient
{
public void SayHi(string msg)
{
.....
}
public void ProcessJob(EJob job)
{
.....
}
}
另外:服务方法应该返回某些东西给调用者!没有返回类型,你有点创建一个服务的黑洞 - 你可以调用它的方法,但没有任何东西被返回....另外:服务实现类应 < em> NOT 自己托管!将其作为一个单独的类
您应该在托管此服务的服务器端拥有主机类:
public class HostForYourService
{
public HostForYourService()
{
// send this off to the correct exe
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, true);
string address = string.Format("net.tcp://localhost:33888/BatchMananger/client");
EndpointAddress epa = new EndpointAddress(address);
ServiceHost sh = new ServiceHost(typeof(ServiceImplementation));
// define the tcpaddress
sh.AddServiceEndpoint(typeof(IRemoteClient), binding, address);
// now open the service for business
sh.Open();
}
然后您的客户端应为此服务构建客户端代理并将其命名为
public class YourServiceClient
{
public void CallService()
{
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None, true);
string address = string.Format("net.tcp://servername:33888/BatchMananger/client");
EndpointAddress epa = new EndpointAddress(address);
// create the proxy pointing to the correct exe
IRemoteClient clientProxy = ChannelFactory<IRemoteClient>.CreateChannel(binding, epa);
clientProxy.SayHi("Hello from server"); <-- THIS WORKS FINE
EJob job = new EJob { LastName = "Janssen" };
clientProxy.ProcessJob(job);
}
}
但同样:通常,您的服务方法应返回客户端可以操作的内容 - 毕竟,您通常不希望在服务器上执行Console.WriteLine
- 你想要计算某些东西,查找某些东西等,并将响应返回给客户,然后依次可以将结果输出到控制台或其他东西......