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

Part 7 - KnownType attribute in WCF

Suggested Videos
Part 4 - Single wcf service implementing multiple service contracts
Part 5 - How to make changes to wcf service without breaking clients
Part 6 - WCF DataContract and DataMember



If we have classes related by inheritance, the wcf service generally accepts and returns the base type. If you expect the service to accept and return inherited types, then use KnownType attribute.

There are other ways of associating known types, which we will discuss in next video session.



Code used in the demo:
SQL:
Alter table tblEmployee Add 
EmployeeType int, AnnualSalary intHourlyPay int, HoursWorked int

Alter procedure spGetEmployee  
@Id int  
as  
Begin  
 Select Id, Name, Gender, DateOfBirth, 
EmployeeType, AnnualSalary, HourlyPay, 
HoursWorked  
 from tblEmployee where Id = @Id  
End

Alter procedure spSaveEmployee  
@Id int,  
@Name nvarchar(50),  
@Gender nvarchar(50),  
@DateOfBirth DateTime,
@EmployeeType int,
@AnnualSalary int = null,
@HourlyPay int = null,
@HoursWorked int = null
as  
Begin  
 Insert into tblEmployee  
 values (@Id, @Name, @Gender, @DateOfBirth, 
@EmployeeType, @AnnualSalary, @HourlyPay, 
@HoursWorked)  
End

FullTimeEmployee.cs
namespace EmployeeService
{
    public class FullTimeEmployee : Employee
    {
        public int AnnualSalary { get; set; }
    }
}

PartTimeEmployee.cs
namespace EmployeeService
{
    public class PartTimeEmployee : Employee
    {
        public int HourlyPay { get; set; }
        public int HoursWorked { get; set; }
    }
}

Employee.cs
using System;
using System.Runtime.Serialization;

namespace EmployeeService
{
    [KnownType(typeof(FullTimeEmployee))]
    [KnownType(typeof(PartTimeEmployee))]
    [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; }
        }

        [DataMember(Order = 5)]
        public EmployeeType Type { get; set; }
    }

    public enum EmployeeType
    {
        FullTimeEmployee = 1,
        PartTimeEmployee = 2
    }
}

EmployeeService.cs
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 = null;
            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())
                {
                    if ((EmployeeType)reader["EmployeeType"] == EmployeeType.FullTimeEmployee)
                    {
                        employee = new FullTimeEmployee
                        {
                            Id = Convert.ToInt32(reader["Id"]),
                            Name = reader["Name"].ToString(),
                            Gender = reader["Gender"].ToString(),
                            DateOfBirth = Convert.ToDateTime(reader["DateOfBirth"]),
                            Type = EmployeeType.FullTimeEmployee,
                            AnnualSalary = Convert.ToInt32(reader["AnnualSalary"])
                        };
                    }
                    else
                    {
                        employee = new PartTimeEmployee
                        {
                            Id = Convert.ToInt32(reader["Id"]),
                            Name = reader["Name"].ToString(),
                            Gender = reader["Gender"].ToString(),
                            DateOfBirth = Convert.ToDateTime(reader["DateOfBirth"]),
                            Type = EmployeeType.PartTimeEmployee,
                            HourlyPay = Convert.ToInt32(reader["HourlyPay"]),
                            HoursWorked = Convert.ToInt32(reader["HoursWorked"]),
                        };
                    }
                }
            }
            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 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);

                SqlParameter parameterEmployeeType = new SqlParameter
                {
                    ParameterName = "@EmployeeType",
                    Value = employee.Type
                };
                cmd.Parameters.Add(parameterEmployeeType);

                if (employee.GetType() == typeof(FullTimeEmployee))
                {
                    SqlParameter parameterAnnualSalary = new SqlParameter
                    {
                        ParameterName = "@AnnualSalary",
                        Value = ((FullTimeEmployee)employee).AnnualSalary
                    };
                    cmd.Parameters.Add(parameterAnnualSalary);
                }
                else
                {
                    SqlParameter parameterHourlyPay = new SqlParameter
                    {
                        ParameterName = "@HourlyPay",
                        Value = ((PartTimeEmployee)employee).HourlyPay,
                    };
                    cmd.Parameters.Add(parameterHourlyPay);

                    SqlParameter parameterHoursWorked = new SqlParameter
                    {
                        ParameterName = "@HoursWorked",
                        Value = ((PartTimeEmployee)employee).HoursWorked
                    };
                    cmd.Parameters.Add(parameterHoursWorked);
                }

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

WebForm1.aspx
<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>
            <b>Employee Type</b>
        </td>
        <td>
            <asp:DropDownList ID="ddlEmployeeType" runat="server" 
                OnSelectedIndexChanged="ddlEmployeeType_SelectedIndexChanged"
                AutoPostBack="True">
                <asp:ListItem Text="Select Employee Type" Value="-1">
                </asp:ListItem>
                <asp:ListItem Text="Full Time Employee" Value="1">
                </asp:ListItem>
                <asp:ListItem Text="Part Time Employee" Value="2">
                </asp:ListItem>
            </asp:DropDownList>
        </td>
    </tr>
    <tr id="trAnnualSalary" runat="server" visible="false">
        <td>
            <b>Annual Salary</b>
        </td>
        <td>
            <asp:TextBox ID="txtAnnualSalary" runat="server">
            </asp:TextBox>
        </td>
    </tr>
    <tr id="trHourlPay" runat="server" visible="false">
        <td>
            <b>Hourly Pay</b>
        </td>
        <td>
            <asp:TextBox ID="txtHourlyPay" runat="server">
            </asp:TextBox>
        </td>
    </tr>
    <tr id="trHoursWorked" runat="server" visible="false">
        <td>
            <b>Hours worked</b>
        </td>
        <td>
            <asp:TextBox ID="txtHoursWorked" 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
protected void btnGetEmployee_Click(object sender, EventArgs e)
{
    EmployeeService.EmployeeServiceClient client = 
        new EmployeeService.EmployeeServiceClient();
    EmployeeService.Employee employee = 
        client.GetEmployee(Convert.ToInt32(txtID.Text));

    if (employee.Type == EmployeeService.EmployeeType.FullTimeEmployee)
    {
        txtAnnualSalary.Text = 
            ((EmployeeService.FullTimeEmployee)employee).AnnualSalary.ToString();
        trAnnualSalary.Visible = true;
        trHourlPay.Visible = false;
        trHoursWorked.Visible = false;
    }
    else
    {
        txtHourlyPay.Text = 
            ((EmployeeService.PartTimeEmployee)employee).HourlyPay.ToString();
        txtHoursWorked.Text = 
            ((EmployeeService.PartTimeEmployee)employee).HoursWorked.ToString();
        trAnnualSalary.Visible = false;
        trHourlPay.Visible = true;
        trHoursWorked.Visible = true;
    }
    ddlEmployeeType.SelectedValue = ((int)employee.Type).ToString();

            
            
    txtName.Text = employee.Name;
    txtGender.Text = employee.Gender;
    txtDateOfBirth.Text = employee.DateOfBirth.ToShortDateString();
    lblMessage.Text = "Employee retrieved";
}

protected void btnSave_Click(object sender, EventArgs e)
{
    EmployeeService.EmployeeServiceClient client = new 
        EmployeeService.EmployeeServiceClient();
    EmployeeService.Employee employee = null;

    if (((EmployeeService.EmployeeType)Convert.ToInt32(ddlEmployeeType.SelectedValue)) 
        == EmployeeService.EmployeeType.FullTimeEmployee)
    {
        employee = new EmployeeService.FullTimeEmployee
        {
            Id = Convert.ToInt32(txtID.Text),
            Name = txtName.Text,
            Gender = txtGender.Text,
            DateOfBirth = Convert.ToDateTime(txtDateOfBirth.Text),
            Type = EmployeeService.EmployeeType.FullTimeEmployee,
            AnnualSalary = Convert.ToInt32(txtAnnualSalary.Text),
        };
        client.SaveEmployee(employee);
        lblMessage.Text = "Employee saved";
    }
    else if (((EmployeeService.EmployeeType)Convert.ToInt32(ddlEmployeeType.SelectedValue)) 
        == EmployeeService.EmployeeType.PartTimeEmployee)
    {
        employee = new EmployeeService.PartTimeEmployee
        {
            Id = Convert.ToInt32(txtID.Text),
            Name = txtName.Text,
            Gender = txtGender.Text,
            DateOfBirth = Convert.ToDateTime(txtDateOfBirth.Text),
            Type = EmployeeService.EmployeeType.PartTimeEmployee,
            HourlyPay = Convert.ToInt32(txtHourlyPay.Text),
            HoursWorked = Convert.ToInt32(txtHoursWorked.Text),
        };
        client.SaveEmployee(employee);
        lblMessage.Text = "Employee saved";
    }
    else
    {
        lblMessage.Text = "Please select Employee Type";
    }
}

protected void ddlEmployeeType_SelectedIndexChanged
    (object sender, EventArgs e)
{
    if (ddlEmployeeType.SelectedValue == "-1")
    {
        trAnnualSalary.Visible = false;
        trHourlPay.Visible = false;
        trHoursWorked.Visible = false;
    }
    else if (ddlEmployeeType.SelectedValue == "1")
    {
        trAnnualSalary.Visible = true;
        trHourlPay.Visible = false;
        trHoursWorked.Visible = false;
    }
    else
    {
        trAnnualSalary.Visible = false;
        trHourlPay.Visible = true;
        trHoursWorked.Visible = true;
    }
}

wcf tutorial

15 comments:

  1. Hello Sir,

    These all videos are very helpful for me. All WCF concepts were so hard to understand but now its easy for me. my basic concepts are clear now. Thank you very much.

    ReplyDelete
  2. Hello Sir,

    Is it possible to host multiple services using one host project with same biding and baseaddress?

    ReplyDelete
  3. I've noticed, or I'm assuming, that in your if statement:
    if (employee.Type == EmployeeService.EmployeeType.FullTimeEmployee) ,
    you are using the Enumeration defined in the same name space as your employee class. It was not marked with [DataMember] and you didn't use [Serialize], so how did it get passed to the client so that it's usable in your if statement?

    ReplyDelete
    Replies
    1. [DataMember(Order = 5)]
      public EmployeeType Type { get; set; }
      it is declared once check it out...

      Delete
  4. Thx for this tutorial! Well explained.

    ReplyDelete
  5. Hello Venkat Sir,

    Can you please make the videos for Restful service using WCF.

    Thanks,
    Suraj Kumar

    ReplyDelete
  6. Dear sir
    I have an exception,
    Enum value '0' is invalid for type 'EmployeeService_Web_WCF.EmployeeService.EmployeeType' and cannot be serialized. Ensure that the necessary enum values are present and are marked with EnumMemberAttribute attribute if the type has DataContractAttribute attribute.
    I have employee class like this
    namespace EmployeeService
    {
    [KnownType(typeof(FullTimeEmployee))]
    [KnownType(typeof(PartTimeEmployee))]
    [DataContract(Namespace = "http://pragimtech.com/Employee")]
    public class Employee
    {
    private int _id;
    private string _name;
    private string _gender;
    private DateTime _dateOfBirth;

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

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

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

    [DataMember(Order=1)]
    public int ID
    {
    get { return _id; }
    set { _id = value; }
    }
    [DataMember(Order=5)]
    public EmployeeType Type { get; set; }
    }


    public enum EmployeeType
    {

    FullTimeEmployee = 1,

    PartTimeEmployee = 2
    }
    }

    ReplyDelete
    Replies
    1. Please check the values in the listitems of the ddlEmployeeType control. One of those 3 list items may be containing Value="0", or even if you don't mention explicit values, it will start from 0; and we don't have that value mentioned in our enum type. Hope it helps!

      Delete
  7. Hi,

    Anyone can help me to understand the logic here:

    EmployeeService.cs

    ((EmployeeType)reader["EmployeeType"] == EmployeeType.FullTimeEmployee)

    Question 1:

    what will get return in this line: EmployeeType.FullTimeEmployee

    Question 2:

    I hope -- reader["EmployeeType"] -- will return integer value. why we are converting into "EmployeeType" as like (EmployeeType)reader["EmployeeType"].

    ReplyDelete
    Replies
    1. Answer for Question 1:
      ------------------------------

      EmployeeType.FullTimeEmployee will return "FullTimeEmployee" data type is "EmployeeType"


      Answer for Question 2:
      -----------------------------

      reader["EmployeeType"] will return "1" datatype is anonymous - int object. We have to typecast that anonymous - int object to EmployeeType, to compare both values.

      Delete
  8. just an FYI...

    if (employee.GetType() == typeof(FullTimeEmployee))

    is same as

    if (employee is FullTimeEmployee)

    The latter maybe easy to read for some developers

    ReplyDelete
  9. Dear Sir,

    I have followed your steps exactly as it is in your video and blog but few things are not working in my system but perfectly working in your system as shown in your video. Please help me in understanding the following:

    In your code, you did not mention [DataContract] attribute to the following class but still it is working fine but hot happening in my system.

    FullTimeEmployee.cs
    namespace EmployeeService
    {
    public class FullTimeEmployee : Employee
    {
    public int AnnualSalary { get; set; }
    }
    }

    PartTimeEmployee.cs
    namespace EmployeeService
    {
    public class PartTimeEmployee : Employee
    {
    public int HourlyPay { get; set; }
    public int HoursWorked { get; set; }
    }
    }


    My code:

    FullTimeEmployee.cs
    namespace EmployeeService
    {
    [DataContract(Namespace = "http://rahul.com/2018/03/20/Employee")]
    public class FullTimeEmployee : Employee
    {
    [DataMember]
    public int AnnualSalary { get; set; }
    }
    }

    PartTimeEmployee.cs
    namespace EmployeeService
    {
    [DataContract(Namespace = "http://rahul.com/2018/03/20/Employee")]
    public class PartTimeEmployee : Employee
    {
    [DataMember]
    public int HourlyPay { get; set; }
    [DataMember]
    public int HoursWorked { get; set; }
    }
    }

    ReplyDelete
  10. This comment has been removed by the author.

    ReplyDelete
  11. i got error kindly support
    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 SDK documentation and inspect the server trace logs.

    ReplyDelete
  12. In 2 classes FullTimeEmployee.cs and PartTimeEMployee.cs add [DataContract].

    ReplyDelete

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