Web 服务不返回序列化列表
web service not returning a serialized list
我为学习目的创建了一个简单的 Web 服务,它只实现了两种方法,一种是将对象添加到列表中,另一种是 return 列表。问题是该服务没有对象的序列化列表。 return 值是一个空数组。
我在同一个解决方案中创建了一个简单的控制台应用程序,并使用 VS 2013 中的内置向导添加了一个服务引用。这些是生成的文件:http://i.imgur.com/ql0QUZN.png 这三个 .xsd 文件很奇怪,为什么不只有一个?
解决方案本身设置为多个启动项目(服务和客户端应用程序),"Start without debugging" 模式 - 如果这很重要。
WCF 测试客户端输出如下:
新学生电话 - http://i.imgur.com/Q41lq4L.png
StudentList 调用 - http://i.imgur.com/ULQULdW.png
如果需要,我会提供更多信息,在此先感谢您。
网络服务代码:
IService.cs
namespace CollegeService
{
[ServiceContract]
public interface IService
{
[OperationContract]
List<Student> StudentList();
[OperationContract]
void NewStudent(Student s);
}
[DataContract]
public class Student
{
private string _OIB; // unique identifier
private string _name;
private string _schoolYear;
[DataMember]
public string OIB
{
get { return _OIB; }
set { _OIB = value; }
}
[DataMember]
public string Name
{
get { return _name; }
set { _name = value; }
}
[DataMember]
public string SchoolYear
{
get { return _schoolYear; }
set { _schoolYear = value; }
}
}
}
Service.svc
<%@ ServiceHost Language="C#" Debug="true" Service="CollegeService.Service" CodeBehind="Service.svc.cs" %>
Service.svc.cs
namespace CollegeService
{
public class Service : IService
{
private List<Student> _students;
public Service()
{
this._students = new List<Student>();
}
public void NewStudent(Student s)
{
this._students.Add(s);
}
public List<Student> StudentList()
{
return this._students;
}
}
}
客户代码:
Reference.cs
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34209
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CollegeServiceClient.Service {
using System.Runtime.Serialization;
using System;
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="Student", Namespace="http://schemas.datacontract.org/2004/07/CollegeService")]
[System.SerializableAttribute()]
public partial class Student : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string NameField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string OIBField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string SchoolYearField;
[global::System.ComponentModel.BrowsableAttribute(false)]
public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
get {
return this.extensionDataField;
}
set {
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Name {
get {
return this.NameField;
}
set {
if ((object.ReferenceEquals(this.NameField, value) != true)) {
this.NameField = value;
this.RaisePropertyChanged("Name");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string OIB {
get {
return this.OIBField;
}
set {
if ((object.ReferenceEquals(this.OIBField, value) != true)) {
this.OIBField = value;
this.RaisePropertyChanged("OIB");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string SchoolYear {
get {
return this.SchoolYearField;
}
set {
if ((object.ReferenceEquals(this.SchoolYearField, value) != true)) {
this.SchoolYearField = value;
this.RaisePropertyChanged("SchoolYear");
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="Service.IService")]
public interface IService {
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/StudentList", ReplyAction="http://tempuri.org/IService/StudentListResponse")]
CollegeServiceClient.Service.Student[] StudentList();
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/StudentList", ReplyAction="http://tempuri.org/IService/StudentListResponse")]
System.Threading.Tasks.Task<CollegeServiceClient.Service.Student[]> StudentListAsync();
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/NewStudent", ReplyAction="http://tempuri.org/IService/NewStudentResponse")]
void NewStudent(CollegeServiceClient.Service.Student s);
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/NewStudent", ReplyAction="http://tempuri.org/IService/NewStudentResponse")]
System.Threading.Tasks.Task NewStudentAsync(CollegeServiceClient.Service.Student s);
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public interface IServiceChannel : CollegeServiceClient.Service.IService, System.ServiceModel.IClientChannel {
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class ServiceClient : System.ServiceModel.ClientBase<CollegeServiceClient.Service.IService>, CollegeServiceClient.Service.IService {
public ServiceClient() {
}
public ServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName) {
}
public ServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public ServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public ServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress) {
}
public CollegeServiceClient.Service.Student[] StudentList() {
return base.Channel.StudentList();
}
public System.Threading.Tasks.Task<CollegeServiceClient.Service.Student[]> StudentListAsync() {
return base.Channel.StudentListAsync();
}
public void NewStudent(CollegeServiceClient.Service.Student s) {
base.Channel.NewStudent(s);
}
public System.Threading.Tasks.Task NewStudentAsync(CollegeServiceClient.Service.Student s) {
return base.Channel.NewStudentAsync(s);
}
}
}
Program.cs(入口点)
namespace CollegeServiceClient
{
public class Program
{
static void Main(string[] args)
{
ServiceClient client = new ServiceClient();
try
{
client.Open();
client.NewStudent
(new Student
{
OIB = "1234",
Name = "John Doe",
SchoolYear = "4"
}
);
Student[] students = client.StudentList();
foreach (Student s in students)
{
Console.WriteLine("Student OIB: {0} Name: {1} School year: {2}", s.OIB, s.Name, s.SchoolYear);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
client.Close();
}
}
}
}
原来问题和解释的一样here。在你的例子中,new Service
class 实例被实例化 per call,因此,你的列表是总是被重置。
要解决这个问题,只需将 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
属性添加到您的 Service
class。这应确保使用相同的 class 实例来处理您的呼叫。
我的代码是这样的:
namespace CollegeService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
public interface IService
{
[OperationContract]
List<Student> StudentList();
[OperationContract]
void NewStudent(Student s);
}
// Use a data contract as illustrated in the sample below to add composite types to service operations.
// You can add XSD files into the project. After building the project, you can directly use the data types defined there, with the namespace "CollegeService.ContractType".
[DataContract]
public class Student
{
[DataMember]
public string OIB
{
get;
set;
}
[DataMember]
public string Name
{
get;
set;
}
[DataMember]
public string SchoolYear
{
get;
set;
}
}
}
namespace CollegeService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
public class Service : IService
{
private List<Student> _students;
public Service()
{
this._students = new List<Student>();
}
public void NewStudent(Student s)
{
this._students.Add(s);
}
public List<Student> StudentList()
{
return this._students;
}
}
}
我为学习目的创建了一个简单的 Web 服务,它只实现了两种方法,一种是将对象添加到列表中,另一种是 return 列表。问题是该服务没有对象的序列化列表。 return 值是一个空数组。 我在同一个解决方案中创建了一个简单的控制台应用程序,并使用 VS 2013 中的内置向导添加了一个服务引用。这些是生成的文件:http://i.imgur.com/ql0QUZN.png 这三个 .xsd 文件很奇怪,为什么不只有一个?
解决方案本身设置为多个启动项目(服务和客户端应用程序),"Start without debugging" 模式 - 如果这很重要。
WCF 测试客户端输出如下:
新学生电话 - http://i.imgur.com/Q41lq4L.png
StudentList 调用 - http://i.imgur.com/ULQULdW.png
如果需要,我会提供更多信息,在此先感谢您。
网络服务代码:
IService.cs
namespace CollegeService
{
[ServiceContract]
public interface IService
{
[OperationContract]
List<Student> StudentList();
[OperationContract]
void NewStudent(Student s);
}
[DataContract]
public class Student
{
private string _OIB; // unique identifier
private string _name;
private string _schoolYear;
[DataMember]
public string OIB
{
get { return _OIB; }
set { _OIB = value; }
}
[DataMember]
public string Name
{
get { return _name; }
set { _name = value; }
}
[DataMember]
public string SchoolYear
{
get { return _schoolYear; }
set { _schoolYear = value; }
}
}
}
Service.svc
<%@ ServiceHost Language="C#" Debug="true" Service="CollegeService.Service" CodeBehind="Service.svc.cs" %>
Service.svc.cs
namespace CollegeService
{
public class Service : IService
{
private List<Student> _students;
public Service()
{
this._students = new List<Student>();
}
public void NewStudent(Student s)
{
this._students.Add(s);
}
public List<Student> StudentList()
{
return this._students;
}
}
}
客户代码:
Reference.cs
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.34209
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace CollegeServiceClient.Service {
using System.Runtime.Serialization;
using System;
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="Student", Namespace="http://schemas.datacontract.org/2004/07/CollegeService")]
[System.SerializableAttribute()]
public partial class Student : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
[System.NonSerializedAttribute()]
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string NameField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string OIBField;
[System.Runtime.Serialization.OptionalFieldAttribute()]
private string SchoolYearField;
[global::System.ComponentModel.BrowsableAttribute(false)]
public System.Runtime.Serialization.ExtensionDataObject ExtensionData {
get {
return this.extensionDataField;
}
set {
this.extensionDataField = value;
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string Name {
get {
return this.NameField;
}
set {
if ((object.ReferenceEquals(this.NameField, value) != true)) {
this.NameField = value;
this.RaisePropertyChanged("Name");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string OIB {
get {
return this.OIBField;
}
set {
if ((object.ReferenceEquals(this.OIBField, value) != true)) {
this.OIBField = value;
this.RaisePropertyChanged("OIB");
}
}
}
[System.Runtime.Serialization.DataMemberAttribute()]
public string SchoolYear {
get {
return this.SchoolYearField;
}
set {
if ((object.ReferenceEquals(this.SchoolYearField, value) != true)) {
this.SchoolYearField = value;
this.RaisePropertyChanged("SchoolYear");
}
}
}
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName) {
System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
if ((propertyChanged != null)) {
propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="Service.IService")]
public interface IService {
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/StudentList", ReplyAction="http://tempuri.org/IService/StudentListResponse")]
CollegeServiceClient.Service.Student[] StudentList();
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/StudentList", ReplyAction="http://tempuri.org/IService/StudentListResponse")]
System.Threading.Tasks.Task<CollegeServiceClient.Service.Student[]> StudentListAsync();
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/NewStudent", ReplyAction="http://tempuri.org/IService/NewStudentResponse")]
void NewStudent(CollegeServiceClient.Service.Student s);
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IService/NewStudent", ReplyAction="http://tempuri.org/IService/NewStudentResponse")]
System.Threading.Tasks.Task NewStudentAsync(CollegeServiceClient.Service.Student s);
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public interface IServiceChannel : CollegeServiceClient.Service.IService, System.ServiceModel.IClientChannel {
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
public partial class ServiceClient : System.ServiceModel.ClientBase<CollegeServiceClient.Service.IService>, CollegeServiceClient.Service.IService {
public ServiceClient() {
}
public ServiceClient(string endpointConfigurationName) :
base(endpointConfigurationName) {
}
public ServiceClient(string endpointConfigurationName, string remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public ServiceClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress) {
}
public ServiceClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress) {
}
public CollegeServiceClient.Service.Student[] StudentList() {
return base.Channel.StudentList();
}
public System.Threading.Tasks.Task<CollegeServiceClient.Service.Student[]> StudentListAsync() {
return base.Channel.StudentListAsync();
}
public void NewStudent(CollegeServiceClient.Service.Student s) {
base.Channel.NewStudent(s);
}
public System.Threading.Tasks.Task NewStudentAsync(CollegeServiceClient.Service.Student s) {
return base.Channel.NewStudentAsync(s);
}
}
}
Program.cs(入口点)
namespace CollegeServiceClient
{
public class Program
{
static void Main(string[] args)
{
ServiceClient client = new ServiceClient();
try
{
client.Open();
client.NewStudent
(new Student
{
OIB = "1234",
Name = "John Doe",
SchoolYear = "4"
}
);
Student[] students = client.StudentList();
foreach (Student s in students)
{
Console.WriteLine("Student OIB: {0} Name: {1} School year: {2}", s.OIB, s.Name, s.SchoolYear);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
client.Close();
}
}
}
}
原来问题和解释的一样here。在你的例子中,new Service
class 实例被实例化 per call,因此,你的列表是总是被重置。
要解决这个问题,只需将 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
属性添加到您的 Service
class。这应确保使用相同的 class 实例来处理您的呼叫。
我的代码是这样的:
namespace CollegeService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService1" in both code and config file together.
[ServiceContract]
public interface IService
{
[OperationContract]
List<Student> StudentList();
[OperationContract]
void NewStudent(Student s);
}
// Use a data contract as illustrated in the sample below to add composite types to service operations.
// You can add XSD files into the project. After building the project, you can directly use the data types defined there, with the namespace "CollegeService.ContractType".
[DataContract]
public class Student
{
[DataMember]
public string OIB
{
get;
set;
}
[DataMember]
public string Name
{
get;
set;
}
[DataMember]
public string SchoolYear
{
get;
set;
}
}
}
namespace CollegeService
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in both code and config file together.
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)]
public class Service : IService
{
private List<Student> _students;
public Service()
{
this._students = new List<Student>();
}
public void NewStudent(Student s)
{
this._students.Add(s);
}
public List<Student> StudentList()
{
return this._students;
}
}
}