Support us .Net Basics C# SQL ASP.NET Aarvi MVC Slides C# Programs Subscribe Download

Part 6 - WCF DataContract and DataMember

Suggested Videos
Part 3 - Creating a wcf service
Part 4 - Single wcf service implementing multiple service contracts
Part 5 - How to make changes to wcf service without breaking clients



To understand DataContract and DataMember attributes in WCF, first let's understand what is meant by Serialization.

With respect to WCF, Serialization is the process of converting an object into an XML representation. The reverse process, that is reconstructing the same object from the XML is called as Deserialization. 



By default, WCF uses DataContractSerializer. 

For a complex type like Customer, Employee, Student to be serialized, the complex type can either be decorated with 
1. SerializableAttribute or
2. DataContractAttribute

With .NET 3.5 SP1 and above, we don't have to explicitly use DataContract or DataMember attributes. The Data Contract Serializer will serialize all public properties of your complex type in an alphabetical order. By default private field and properties are not serialized.

If we decorate a complex type, with [Serializable] attribute the DataContractSerializer serializes all fields. With [Serializable] attribute we don't have explicit control on what fields to include and exclude in serialized data.

If we decorate a complex type with [Datacontract] attribute, the DataContractSerializer serializes the fields marked with the [DataMember] attribute. The fields that are not marked with [DataMember] attribute are excluded from serialization. The [DataMember] attribute can be applied either on the private fields or public properties.

In WCF, the most common way of serialization is to mark the type with the DataContract attribute and mark each member that needs to be serialized with the DataMember attribute. 

If you want to have explicit control on what fields and properties get serialized then use DataContract and DataMember attributes.
1. Using DataContractAttribute, you can define an XML namespace for your data

2. Using DataMemberAttribute, you can
    a) Define Name, Order, and whether if a property or field IsRequired
    b) Also, serialize private fields and properties

Code used in the demo:
SQL Script:
Create Table tblEmployee
(
Id int,
Name nvarchar(50),
Gender nvarchar(50),
DateOfBirth datetime
)

Insert into tblEmployee values (1, 'Mark', 'Male', '10/10/1980')
Insert into tblEmployee values (2, 'Mary', 'Female', '11/10/1981')
Insert into tblEmployee values (3, 'John', 'Male', '8/10/1979')

Create procedure spGetEmployee
@Id int
as
Begin
Select Id, Name, Gender, DateOfBirth
from tblEmployee 
where Id = @Id
End

Create procedure spSaveEmployee
@Id int,
@Name nvarchar(50),
@Gender nvarchar(50),
@DateOfBirth DateTime
as
Begin
Insert into tblEmployee
values (@Id, @Name, @Gender, @DateOfBirth)
End

Employee.cs file in EmployeeService project:
using System;
using System.Runtime.Serialization;

namespace EmployeeService
{
    [DataContract(Namespace="http://pragimtech.com/Employee")]
    public class Employee
    {
        private int _id;
        private string _name;
        private string _gender;
        private DateTime _dateOfBirth;

        [DataMember(Order=1)]
        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }

        [DataMember(Order = 2)]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }

        [DataMember(Order = 3)]
        public string Gender
        {
            get { return _gender; }
            set { _gender = value; }
        }

        [DataMember(Order = 4)]
        public DateTime DateOfBirth
        {
            get { return _dateOfBirth; }
            set { _dateOfBirth = value; }
        }
    }
}

IEmployeeService.cs in EmployeeService project
using System.ServiceModel;

namespace EmployeeService
{
    [ServiceContract]
    public interface IEmployeeService
    {
        [OperationContract]
        Employee GetEmployee(int Id);

        [OperationContract]
        void SaveEmployee(Employee Employee);
    }
}

EmployeeService.cs in EmployeeService project
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;

namespace EmployeeService
{
    public class EmployeeService : IEmployeeService
    {
        public Employee GetEmployee(int Id)
        {
            Employee employee = new Employee();
            string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
            using (SqlConnection con = new SqlConnection(cs))
            {
                SqlCommand cmd = new SqlCommand("spGetEmployee", con);
                cmd.CommandType = CommandType.StoredProcedure;
                SqlParameter parameterId = new SqlParameter();
                parameterId.ParameterName = "@Id";
                parameterId.Value = Id;
                cmd.Parameters.Add(parameterId);
                con.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                {
                    employee.Id = Convert.ToInt32(reader["Id"]);
                    employee.Name = reader["Name"].ToString();
                    employee.Gender = reader["Gender"].ToString();
                    employee.DateOfBirth = Convert.ToDateTime(reader["DateOfBirth"]);
                }
            }
            return employee;
        }

        public void SaveEmployee(Employee employee)
        {
            string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
            using (SqlConnection con = new SqlConnection(cs))
            {
                SqlCommand cmd = new SqlCommand("spSaveEmployee", con);
                cmd.CommandType = CommandType.StoredProcedure;
                SqlParameter parameterId = new SqlParameter
                {
                    ParameterName = "@Id",
                    Value = employee.Id
                };
                cmd.Parameters.Add(parameterId);

                SqlParameter parameterName = new SqlParameter
                {
                    ParameterName = "@Name",
                    Value = employee.Name
                };
                cmd.Parameters.Add(parameterName);

                SqlParameter parameterName = new SqlParameter
                {
                    ParameterName = "@Gender",
                    Value = employee.Gender
                };
                cmd.Parameters.Add(parameterGender);

                SqlParameter parameterName = new SqlParameter
                {
                    ParameterName = "@DateOfBirth",
                    Value = employee.DateOfBirth
                };
                cmd.Parameters.Add(parameterDateOfBirth);

                con.Open();
                cmd.ExecuteNonQuery();
            }
        }
    }
}

App.config in EmployeeServiceHost project
<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add name="DBCS"
         connectionString="data source=.;Integrated Security=SSPI;database=Sample"
         providerName="System.Data.SqlClient" />
  </connectionStrings>
  <system.serviceModel>
    <services>
      <service name="EmployeeService.EmployeeService" behaviorConfiguration="mexBehaviour">
        <endpoint address="EmployeeService" binding="basicHttpBinding" contract="EmployeeService.IEmployeeService">
        </endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8080/"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="mexBehaviour">
          <serviceMetadata httpGetEnabled="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Program.cs in EmployeeServiceHost project
using System;
using System.ServiceModel;

namespace EmployeeServiceHost
{
    class Program
    {
        public static void Main()
        {
            using (ServiceHost host = new ServiceHost(typeof(EmployeeService.EmployeeService)))
            {
                host.Open();
                Console.WriteLine("Host started @ " + DateTime.Now.ToString());
                Console.ReadLine();
            }
        }
    }
}

WebForm1.aspx in Client project
<table style="font-family:Arial; border:1px solid black;">
    <tr>
        <td>
            <b>ID</b>
        </td>
        <td>
            <asp:TextBox ID="txtID" runat="server">
            </asp:TextBox>
        </td>
    </tr>
    <tr>
        <td>
            <b>Name</b>
        </td>
        <td>
            <asp:TextBox ID="txtName" runat="server">
            </asp:TextBox>
        </td>
    </tr>
    <tr>
        <td>
            <b>Gender</b>
        </td>
        <td>
            <asp:TextBox ID="txtGender" runat="server">
            </asp:TextBox>
        </td>
    </tr>
    <tr>
        <td>
            <b>Date Of Birth</b>
        </td>
        <td>
            <asp:TextBox ID="txtDateOfBirth" runat="server">
            </asp:TextBox>
        </td>
    </tr>
    <tr>
        <td>
            <asp:Button ID="btnGetEmployee" runat="server" 
                                 Text="Get Employee" 
                                 onclick="btnGetEmployee_Click" />                                    
        </td>
        <td>
            <asp:Button ID="btnSave" runat="server" 
                        Text="Save Employee" 
                        onclick="btnSave_Click" />
        </td>
    </tr>
    <tr>
        <td colspan="2">
            <asp:Label ID="lblMessage" runat="server" 
                        ForeColor="Green" Font-Bold="true">
            </asp:Label>
        </td>
    </tr>
</table>

WebForm1.aspx.cs in Client project
protected void btnSave_Click(object sender, EventArgs e)
{
    EmployeeService.Employee employee = new EmployeeService.Employee();
    employee.Id = Convert.ToInt32(txtID.Text);
    employee.Name = txtName.Text;
    employee.Gender = txtGender.Text;
    employee.DateOfBirth = Convert.ToDateTime(txtDateOfBirth.Text);

    EmployeeService.EmployeeServiceClient client = new
        EmployeeService.EmployeeServiceClient();
    client.SaveEmployee(employee);

    lblMessage.Text = "Employee saved";
}

protected void btnGetEmployee_Click(object sender, EventArgs e)
{
    EmployeeService.EmployeeServiceClient client = new
        EmployeeService.EmployeeServiceClient();
            
    EmployeeService.Employee employee =             
        client.GetEmployee(Convert.ToInt32(txtID.Text));

    txtName.Text = employee.Name;
    txtGender.Text = employee.Gender;
    txtDateOfBirth.Text = employee.DateOfBirth.ToShortDateString();

    lblMessage.Text = "Employee retrieved";
}

wcf tutorial

25 comments:

  1. Hi Venkat,
    Your Videos are very helpful, Thanks a lot for those!
    Can you please post a video on how a protocol is to be chosen in developing a WCF service. Which are all the factors to be considered while deciding on Binding in WCF?

    ReplyDelete
  2. Excpetion is oCCURING "System.ServiceModel.FaultException: The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.
    "

    on the below line

    Line 146:
    Line 147: public EmployeeWebClient.EmployeeService.Employee GetEmployee(int id) {
    Line 148: return base.Channel.GetEmployee(id);
    Line 149: }
    Line 150:

    Please help

    ReplyDelete
  3. Adding
    in the config file.. helps me in debugging the issue, now its resolved ..

    Thanks

    ReplyDelete
    Replies
    1. Hi Manish,
      what should we add into the config file in order to avoid this exception as i'm getting the same exception

      Delete
    2. Hiii Manish,
      Can u please tell me what should be done to over come that error...! the same error... tried a lot... exhausted...! thanks in advance...

      Delete
    3. Change connectionString="Data Source=.;Initial Catalog=DB_Name;Integrated Security=True"

      Delete

  4. Hello,i have a problem with host.When i start the host it starts and looks it is working but when i try to add service reference to the client then i can't find host listening on localhost:8080.Same from browser(s),host is running but i can't get to service from browser address http://localhost:8080.I checked all the code in host startup,app.config...everything is fine.It was a same problem with one of the previous tutorials and i found i was adding reference to System.ServiceModel at wrong place(project) but now it is not a case.I have reference to System.ServiceModel in host console proj. and in the WCF proj.I also have using statement for System.ServiceModel.
    No solution found on the net,tried netsh http add urlacl url=http://:8080 user=...
    but nothing works.
    VS is running in admin mode.
    Code was copied from the site.
    Any ideas what to do ?Lost over 10 hours to try to follow this video but stuck here...
    Thanks in advance

    ReplyDelete
    Replies
    1. Check the connection string in app.config file....

      connectionString="data source=.;.......... change it to (remove .)
      connectionString="data source= your sql path;.......

      Delete
  5. Thanks very kindly for your videos. They are very very helpful and informative. Can you post one where you use Entity Framework with WCF and consumed by a winform application to display data on a Datagridview.
    Thanks
    Bonny

    ReplyDelete
  6. how i can debug a wcf services from client or servicehosting application

    ReplyDelete
  7. i am getting sql exception please help me to solve it

    string cs = "Data Source=(localdb)\v11.0;Initial Catalog=WCFdb;Integrated Security=SSPI";


    A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: Named Pipes Provider, error: 40 - Could not open a connection to SQL Server)

    ReplyDelete
  8. Hi Venkat
    thanks for the tutorials

    I am getting the following error while consuming the service .
    "An existing connection was forcibly closed by the remote host"

    Please help me
    Thanks

    ReplyDelete
  9. Hi..
    How can I use parameterized constructor?
    do i need to write DataMember??
    or what shhould I do?

    ReplyDelete
  10. Hi,

    i'm getting an error as "the name at ConfigurationManager is does not exist in the current context" even i added using System.Configuration i'm getting this error

    can any one help in this.

    Thank u in advance

    ReplyDelete
    Replies
    1. In the Project references, Add System,Configuration Assembly,
      only then ConfigurationManager will work

      Delete
  11. Hi,In consile application result is not displaed and in client application service is not detected

    ReplyDelete
  12. Hey, I am facing some problem with host.When I start the host it starts and looks it is working but when I try to add service reference to the client then I can't find host listening on localhost:8080.Same from browser(s),host is running but I can't get to service from browser address http://localhost:8080.I checked the entire code in host startup,app.config...everything is fine.I have reference to System.ServiceModel in host console proj. and in the WCF proj.I also have using statement for System.ServiceModel.
    No solution found on the net,tried netsh http add urlacl url=http://:8080 user=...
    but nothing works.
    Visual Studio Ultimate 2013 is running as Admininstrator.
    Please help me ..

    Please Reply

    ReplyDelete
  13. not able to load webservice after updating code for this tutorial.
    The server was unable to process the request due to an internal error

    ReplyDelete
  14. I am very grateful for you useful video, may you help me please the problem is
    in the server side the error that this appears is at line
    SqlDataReader reader = cmd.ExecuteReader();
    and at the client side at line
    mployeeService.Employee employee = client.GetEmployee(Convert.ToInt32(txtID.Text));

    ReplyDelete
  15. In the Employee Clientadded the Service reference(EmployeeService), i am getting error in Referece.cs class as """"The type name 'EmployeeService' does not exist in the type 'EmployeeServiceClient.EmployeeService.EmployeeServiceClient'""""

    Please help me, i am not able to resolve this issue...

    ReplyDelete
  16. Please suggest how do I return XMLDocument?

    ReplyDelete
  17. I love your videos, your voice and your teaching style. You have really made a difference in my career/interviews over the years. I'm looking forward to learning more about WCF.

    ReplyDelete
  18. Save Employee should have following code:
    string cs = ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString;
    using (SqlConnection con = new SqlConnection(cs))
    {
    SqlCommand cmd = new SqlCommand("spSaveEmployee", con);
    cmd.CommandType = CommandType.StoredProcedure;
    SqlParameter parameterId = new SqlParameter
    {
    ParameterName = "@Id",
    Value = employee.Id
    };
    cmd.Parameters.Add(parameterId);

    SqlParameter parameterName = new SqlParameter
    {
    ParameterName = "@Name",
    Value = employee.Name
    };
    cmd.Parameters.Add(parameterName);

    SqlParameter parameterGender = new SqlParameter
    {
    ParameterName = "@Gender",
    Value = employee.Gender
    };
    cmd.Parameters.Add(parameterGender);

    SqlParameter parameterDateOfBirth = new SqlParameter
    {
    ParameterName = "@DateOfBirth",
    Value = employee.DateOfBirth
    };
    cmd.Parameters.Add(parameterDateOfBirth);

    con.Open();
    cmd.ExecuteNonQuery();
    }

    ReplyDelete
  19. If you are getting an error saying "System.ServiceModel.FaultException: The server was unable to process the request due to an internal error.", it is because you maybe referring to a database that does not exist. The author has the database name as "Sample", so if you don't have it, you will run into errors. Just pass the correct database name. My database name is master2, so I pass it this way.

    > connectionString="data source=.;Integrated Security=SSPI;database=master2".

    ReplyDelete
  20. Getting below error :
    Service 'EmployeeService.EmployeeService' has zero application (non-infrastructure) endpoints. This might be because no configuration file was found for your application, or because no service element matching the service name could be found in the configuration file, or because no endpoints were defined in the service element.

    ReplyDelete

It would be great if you can help share these free resources