1

I have a simple web service created for learning purposes, it has only two methods implemented, one adds objects into a list and another returns the list. The problem is that the service does not the serialized list of objects. The return value is an empty array. I created a simple console app within the same solution and added a service reference to it using that built-in wizard in VS 2013. These are the generated files: http://i.imgur.com/ql0QUZN.png Those three .xsd files are weird, why not just one?

The solution itself is set to multiple start-up projects (both the service and the client app), "Start without debugging" mode - if that matters.

Here's what WCF Test Client outputs:

NewStudent call - http://i.imgur.com/Q41lq4L.png

StudentList call - http://i.imgur.com/ULQULdW.png

I will provide more info if needed, thank you in advance.

WEB SERVICE CODE:

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;
        }
    }
}

CLIENT CODE:

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 (entry point)

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();
            }
        }
    }
}
Venom
  • 1,107
  • 4
  • 21
  • 46
  • Add `[DataContract]` on top of `Student`. Also think that your `[DataMember]` attributes should go over the variables themselves rather than their accessor methods. – npinti May 26 '15 at 13:30
  • It's there already, I just deleted it by mistake whily pasting the code here. – Venom May 26 '15 at 13:32
  • Then please update your to reflect what you have. Also, I think you will need to move your `DataMember` attributes over the variables, not over their accessors. – npinti May 26 '15 at 13:34
  • I'll try putting it on top of both first, then just the variables. – Venom May 26 '15 at 13:34
  • I tried your solution but now I cannot access those fields since they are private. The client code wont compile. – Venom May 26 '15 at 13:37
  • The client would still access the fields through their getters. – npinti May 26 '15 at 13:43
  • Here are the compile errors that I receive after modifying the web service, starting it and updating the client's service reference - http://i.imgur.com/j4ZSSVv.png – Venom May 26 '15 at 13:46
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/78810/discussion-between-npinti-and-venom). – npinti May 26 '15 at 13:53

1 Answers1

1

Turns out the problem is the same as the one explained here. In your case, a new instance of the Service class was being instantiated per call, thus, your list was always being reset.

To go round this problem, simply add the [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Single)] attribute to your Service class. This should ensure that the same class instance is used to handle your calls.

This is how my code looks:

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;
        }
    }
}
Community
  • 1
  • 1
npinti
  • 51,780
  • 5
  • 72
  • 96
  • It works now, thank you. But what about the get and set syntax I used? Can that somehow work? Mine works too (just checked it), without adding DataMember to data members, just the accessors. – Venom May 26 '15 at 14:53
  • @Venom: Yes it does work. The only reason I changed it is because it is shorter to write. – npinti May 26 '15 at 14:56
  • @Venom: I've added some very minor notes in the chat. – npinti May 26 '15 at 15:16