Posts

....
Technical Blog for .NET Developers ©

Tuesday, August 28, 2012

WCF Services

When we have to develop a process to be accessed across multiple applications and plattforms, the choice is programming a web service

WCF enables you to encapsulate processes, and expose just the methods and data neccessary to share

In this example we will design a WCF service to filter the access to a database, we will expose two methods and a class

The first step is begin a new WCF Application project

This is the interface of our service, a service dedicated to retrieve and insert data in a chemical elements table, with every Contract defined, plus one for providing information about possible exceptions to the client side

     
namespace Chemistry
{
    [ServiceContract]
    public interface IChemicalService
    {
        [OperationContract]
        [FaultContract(typeof(AccessFault))]
        Element[] GetElements();

        [OperationContract]
        [FaultContract(typeof(AccessFault))]
        string InsertElement(Element element);
    }

    [DataContract]
    public class Element
    {
        [DataMember]
        public string AtomicSymbol { get; set; }

        [DataMember]
        public string Name { get; set; }

        [DataMember]
        public string LatinName { get; set; }
    }

    [DataContract]
    public class AccessFault
    {
        [DataMember]
        public string ExceptionType { get; set; }

        [DataMember]
        public string StackTrace { get; set; }
    }
}


The code file of our service implements this interface, so we implement these methods in it

This is the code for retrieve data, the method GetElements()

     
    public Element[] GetElements()
    {
        try
        {
            SqlCommand retrieveCommand = new SqlCommand()
            {
                Connection = OpenConnection(),
                CommandType = CommandType.StoredProcedure,
                CommandText = "P_SELECT_ELEMENTS",
                CommandTimeout = 20
            };

            SqlDataReader reader = 
                retrieveCommand.ExecuteReader(CommandBehavior.CloseConnection);

            Element[] Elements = new Element[0];

            int index = 0;
            while (reader.Read())
            {
                Array.Resize<Element>(ref Elements, Elements.Length + 1);
                Element element = new Element()
                {
                    AtomicSymbol = reader[0].ToString(),
                    Name = reader[1].ToString(),
                    LatinName = reader[2].ToString()
                };
                Elements[index++] = element;
            }

            return Elements;
        }
        catch (Exception ex)
        {
            AccessFault fault = new AccessFault() 
                { ExceptionType = ex.GetType().ToString(), 
                  StackTrace = ex.StackTrace };
            throw new FaultException<AccessFault>
                (fault, new FaultReason(ex.Message));
        }
    }
    


And this is the method for inserting data

     
    public string InsertElement(Element element)
    {            
        try
        {
            SqlCommand insertCommand = new SqlCommand()
            {
                Connection = OpenConnection(),
                CommandType = CommandType.StoredProcedure,
                CommandText = "P_INSERT_ELEMENT",
                CommandTimeout = 20,
            };

            insertCommand.Parameters.AddRange(new SqlParameter[] {
                new SqlParameter("@asymbol", element.AtomicSymbol),
                new SqlParameter("@name", element.Name),
                new SqlParameter("@latinname", element.LatinName)});

            insertCommand.ExecuteNonQuery();
            insertCommand.Connection.Close();

            return element.AtomicSymbol;
        }
        catch (Exception ex)
        {
            AccessFault fault = new AccessFault() 
                { ExceptionType = ex.GetType().ToString(), 
                  StackTrace = ex.StackTrace };
            throw new FaultException<AccessFault>
                (fault, new FaultReason(ex.Message));
        }
    }
    


Now we will test the io of the service with WCF Test Client tool. Execute the service from Visual Studio and add the Url to WCF Test Client



The next step is deploying the service for its usage from different points. For this we run inetmgr, and add a new web site. Make sure your IIS is configured to allow ASP.NET v4.0 applications. You can set up this configuration with the next prompt command



After this we publish the service



Now we browse our service from IIS HostedChemicalService web site



While configuring the web site and the parameters for the service publication, we can choose any port, minding it's not busy by other application, in our case the deployment Url is

http://localhost:9789/ChemicalService.svc

The final step is calling the service layer for interacting with the database. With this purpose we create a client application, called ChemicalClient, and we add the Service Reference to the project



The code is as follows

     
    private void btnGetElements_Click(object sender, EventArgs e)
    {
        try
        {
            ChemicalServiceClient client = new ChemicalServiceClient();
            Element[] elements = client.GetElements();

            dgvElements.DataSource = elements.ToList();
            lblResult.Text = elements.Length.ToString() + " were found";
        }
        catch (FaultException<AccessFault> ex)
        {
            lblResult.Text = ex.Message + 
                ex.Detail.ExceptionType + ex.Detail.StackTrace;
        }
    }

    private void btnInsertElement_Click(object sender, EventArgs e)
    {
        try
        {
            ChemicalServiceClient client = new ChemicalServiceClient();
            Element elemToInsert = new Element()
            {
                AtomicSymbol = txtAtomicSymbol.Text,
                Name = txtName.Text,
                LatinName = txtLatinName.Text
            };

            string elemKey = client.InsertElement(elemToInsert);
            lblResult.Text = elemKey + " was added correctly";                
        }
        catch (FaultException<AccessFault> ex)
        {
            lblResult.Text = ex.Message + 
                ex.Detail.ExceptionType + ex.Detail.StackTrace;
        }
    }
    


With a correct execution, we get the next result




<METHOD SOFTWARE © 2012>