Create a Class Library
Create a class library project named DataAccessLayar and add a class named Customer.cs with following public properties.In the above code snippet, you can notice that Customer class definition has an attribute named DataContract and properties have DataMember. These attributes are necessary to work with Wcf Services. If we will not keep them, WCF service will not be able to transfer the object and its properties. In order to add these attribute you may need to add reference of System.Runtime.Serialization (Right click and Add Reference … from .NET Tab) to your class library.namespace DataAccessLayer{[DataContract]public class Customer{[DataMember]public string ContactName { get; set; }[DataMember]public string CustomerID { get; set; }[DataMember]public string Address { get; set; }[DataMember]public string City { get; set; }[DataMember]public string Hiredate { get; set; }[DataMember]public string Country { get; set; }}}
Add another class called DataAccessLayer.cs in this class library that has a method called GetCustomers. This method is responsible for connecting to the database and returning the results as Generic lists. Here is the code for this.
NOTE: To avoid complications in this tutorial, I have created Customer class and DataAccessLayer class in the same class library project. In real scenario, you should separate them out.
In the above method, I have created a generic type variable that will accept Customer object, I have a stored procedure named vs_GetCustomersStartsWith that will take a string as a parameter and return all records whose name starts with parameter value.string NorthwindConnStr = ConfigurationSettings.AppSettings.Get(" NorthwindConnStr").ToString(); /// <summary>/// Get customers/// </summary>/// <returns></returns>public List<Customer> GetCustomers(string startsWith){List<Customer> list = new List<Customer>();using (SqlConnection conn = new SqlConnection(NorthwindConnStr)) {conn.Open();using (SqlCommand dCmd = new SqlCommand("vs_GetCustomersStartingWith", conn)) {SqlParameter prms = new SqlParameter("@startsWith", SqlDbType.VarChar, 5);prms.Value = startsWith + "%";dCmd.Parameters.Add(prms);dCmd.CommandType = CommandType.StoredProcedure;using (SqlDataReader reader = dCmd.ExecuteReader()){while (reader.Read()){list.Add(new Customer{CustomerID = reader["CustomerID"].ToString( ), Address = reader["Address"].ToString(), City = reader["City"].ToString(), Country = reader["Country"].ToString(),ContactName = reader["ContactName"]. ToString() });}}}conn.Close(); // lets close explicitely}return list;}
Finally I am forming the Customer object inside while (reader.Read()) loop and adding it into the generic list collection.
Get solutions of the .NET problems with video explanations, .pdf and source code in .NET How to's.
Create a WCF Service
Let’s create the WCF Service now. Right click the solution and click Add > New Proejct … Select Visual C# > Web from the Project Type and WCF Service Application from Templates, name it as WcfService. This will by default create following files:
- IService1.cs
- Service1.svc
- Service1.svc.cs
- Web.config
In the IService1 interface remove all code and add a method definition named GetCustomers. Notice that the interface declaration must have an attribute ServiceContract and its method declaration must have an attribute OperationContract otherwise this class and its member will not be exposed as services. My sample IService1 interface code looks like this.
Now let’s implement the above method in Service1.svc.cs file. If your project names are same as mine, your code for this file looks like below.using System;using System.Collections.Generic;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;using System.Collections.Generic;using DataAccessLayer;namespace WcfService{[ServiceContract]public interface IService1{[OperationContract]List<Customer> GetCustomers(string startsWith);}}
Now we need a little configuration change in web.config file. So open the config file of WcfService project and change following.using System;using System.Collections.Generic;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;using DataAccessLayer;namespace WcfService{public class Service1 : IService1{public List<Customer> GetCustomers(string startsWith){DataAccessLayer.DataAccessLayer dal = new DataAccessLayer.DataAccessLaye r(); return dal.GetCustomers(startsWith);}}}
In the system.serviceModel tag
- For endpoint – change the value of binding to basicHttpBinding.
- For identity > dns change the value to “localhost:3637” //as we are going to fix the port in the project properties later on
<!-- Service Endpoints --> <endpoint address="" binding="basicHttpBinding" contract="WcfService.IService1Now right click the project, click Properties and go to Web tab (left side) and select Specific port and enter 3637 in the textbox and save it. This is to avoid automatically generation of random ports while we are working on our sample application."> <!-- Upon deployment, the following identity element should be removed or replaced to reflect the identity under which the deployed service runs. If removed, WCF will infer an appropriate identity automatically. --> <identity> <dns value="localhost:3637"/> </identity> </endpoint> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
As Silverlight doesn’t support cross domain access by default so we need create a ClientAccessPolicy.xml file that is read when any request is sent to the server to access wcf service. In order to work for cross domain, write following code in this file
This ensures that your wcf service will be consumed by Silverlight application even if both do not fall in the same domain domain.<?xml version="1.0" encoding="utf-8"?><access-policy><cross-domain-access><policy><allow-from http-request-headers="*"><domain uri="*"/></allow-from><grant-to><resource path="/" include-subpaths="true"/></grant-to></policy></cross-domain-access></access-policy>
Save this project and build it.
Now, right click the WcfService project and go to Debug and click start new Instance. This will open up a browser with http://localhost:3637/
Consume WCF Service in Silverlight
Right click the Silverlight application and click Add Service Reference... . Write the url of the wcf service you got above in the address box, click Go button. In the Namespace box, write WcfServiceReference and click OK. This should add a reference of the wcf service and also create ServiceReferences.ClientConfig file in the root of your Silverlight application.Double click the xaml file and drag a TextBlock, TextBox, Button and DataGrid to your xaml file and ensure that they are looking similar to the below code snippet. This will ensure that your Search form is looking good.
As you can see that we have specified Button_Click event handler that will fire when user clicks button after entering keyword in the textbox. Let us see the code for this event.<Grid x:Name="LayoutRoot" Background="White"><Canvas><TextBlock Text="Search" Canvas.Left="10" Canvas.Top="12"></TextBlock><TextBox x:Name="txtSearch" Width="75" Height="22" Canvas.Left="55" Canvas.Top="10"></TextBox><Button Content=" Get Data from WCF Service " Click="Button_Click" Canvas.Top="9" Canvas.Left="140"></Button><TextBlock x:Name="lblWaiting" Canvas.Left="375" Canvas.Top="10" Text="Status: Idle"></TextBlock><data:DataGrid x:Name="dataGrid1" Canvas.Left="10" Canvas.Top="35" Width="550" Height="300" IsReadOnly="True"ItemsSource="{Binding Mode=OneWay}" AutoGenerateColumns="True" ></data:DataGrid></Canvas></Grid>
You can see that in the Button_Click event I have specified a variable named proxy and instantiating it by passing the endpointConfigurationName as parameter. endpointConfigurationName is nothing but the bindingConfiguration value of the ServiceReferences.ClientConfig file.private void Button_Click(object sender, RoutedEventArgs e){// call data web servicevar proxy = new WcfServiceReference.Service1Client("BasicHttpBinding_ IService1"); proxy.GetCustomersCompleted += new EventHandler<SilverlightApplication. WcfServiceReference.GetCustome rsCompletedEventArgs>(proxy_ GetCustomerCompleted); proxy.GetCustomersAsync(txtSearch.Text.Trim()); // call simple web servicelblWaiting.Text = "Status: Waiting ...";}//------------------------------------------------- void proxy_GetCustomerCompleted(object sender, WcfServiceReference.GetCustome rsCompletedEventArgs e) {System.Collections.ObjectModel.ObservableCollecti on<WcfServiceReference.Custome r> list = e.Result; dataGrid1.ItemsSource = list;lblWaiting.Text = "Status: Done";if (list.Count.Equals(0))lblWaiting.Text = "No records found.";elselblWaiting.Text = list.Count + " records found.";}
Later on I have specified the event handler for GetCustomersCompleted and specified the parameter for GetCustomerAsync method as the keyword (textbox value).
When the GetCustomersCompleted will finish, it will raise an event named proxy_GetCustomerCompleted. In this event, write the code like above. Build your Silverlight project and ensure that it is built successfully.
No comments:
Post a Comment