My Master's Thesis Problems and solutions encountered…

14Jun/102

MS SQL Connection – Deploying WCF Services

So, I found a host for my WCF Service, which uses a IIS 7 server that can run my .svc WebService file. I could connect to my MySQL database hosted another place, but given that my new host uses MS SQL, I will be migrating to that.

This post explains how you can deploy your WCF Service and connect to the underlying database, and how to retrieve data all the way through the MVVM Design Pattern. The prerequisites for this post is that you have 1) created a project with a design pattern that somewhat resembles the MVVM covered in my previous post (see MVVM Structure), and 2) that you have created a table in a MS SQL database called 'Suppliers', and inserted three attributes called ID, name and country, respectively.

First, make sure that you have 3 projects in your solution, fx. called Model (a WCF Service Application), View (a Silverlight application), and ViewModel (a Silverlight class). You have connected the projects View and ViewModel together like it was described in step 4 of the previous post.

Step 1: Just to make sure that you have all the right information in order to deploy to your server, right-click on your Model project >> Publish, and enter all necessary data. Notice that you have to enter ftp://yourdomain.net and not just ftp.yourdomain.net.

If you have entered the correct data, the following output will be shown, and the WCF Service will have been added to the root of your server:

Step 2: Go to your Model project and chose Web.Config. Find the row that starts with < system.serviceModel>. It will look something like this:

 <system.serviceModel>
<!--Add code here -->
    <services>
      <service name="Model.Service1" behaviorConfiguration="Model.Service1Behavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="wsHttpBinding" contract="Model.IService1">
 (...)

Step 3: Right below the < system.serviceModel> and before < services> starts, you'll need to add the following code snippet:


  <serviceHostingEnvironment>
          <baseAddressPrefixFilters>
              <add prefix="http://yourDomain.net"/>
          </baseAddressPrefixFilters>
      </serviceHostingEnvironment>

Step 4: Then, a small change needs to be implemented to the endpoint binding. Shown in the code below step 2, you can see that the standard binding is wsHttpBinding. This needs to be changed to BasicHttpBinding.

After having completed step 3 and 4, you will thus end up with the code below:


<system.serviceModel>

      <serviceHostingEnvironment>
          <baseAddressPrefixFilters>
              <add prefix="http://yourDomain.net"/>
          </baseAddressPrefixFilters>
      </serviceHostingEnvironment>

    <services>
      <service name="Model.Service1" behaviorConfiguration="Model.Service1Behavior">
        <!-- Service Endpoints -->
        <endpoint address="" binding="BasicHttpBinding" contract="Model.IService1">
          <!-- 

Step 5: Repeat step 1., ie. right-click on your WebSevice >> Publish. You will then notice that two files and folder have been added to the root of your server: A Service1.svc and a Web.Config file, and a Bin folder.

Step 6: Still in your Model project, open your IService1.cs. Here you will create a class that will contain the attributes and properties for the Suppliers object that we create. Also notice the code inside the brackets [], fx. [OperationContract] and [DataMember], which make the methods and properties available to the other projects.


namespace Model
{

    [DataContract]//Makes the class available
    public class Suppliers //creates the objectet Suppliers, and defines its attributtes (properties).
    {
        int _ID;
        string _name;
        string _country;

        [DataMember]//makes the property available
        public int ID
        {
            get { return _ID; }
            set { _ID = value; }
        }
        [DataMember]
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        [DataMember]
        public string Country
        {
            get { return _country; }
            set { _country = value; }
        }

    }

Step 7: Open your Service1.svc.cs file in the Model project. In this file we will connect to the database and run our queries. When you open the file you'll notice that a lot of code has already been created for you. Below is the standard content of the Service1.svc file:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace Model
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

        public CompositeType GetDataUsingDataContract(CompositeType composite)
        {
            if (composite == null)
            {
                throw new ArgumentNullException("composite");
            }
            if (composite.BoolValue)
            {
                composite.StringValue += "Suffix";
            }
            return composite;
        }
    }
}

You just need to delete everything inside the class, and instead insert what is explained in the following steps.

Step 8: Add a reference to using System.Data.SqlClient; at the top.

Step 9: Create a SqlConnection ConnectToDB() method, that sets the connections string and returns the Sql Connection. If you have Winhost, you will find what you need to insert into your Connection String by logging in >> Site >> Site Tools >> MS SQL 2008 >> Manage. The ConnectToDB method looks something like this:


  public SqlConnection connectToDB()
        {
            string connstring = "Data Source=************;Initial Catalog=*****;User ID=******;Password=*******;Integrated Security=False;";
            SqlConnection dbConn = new SqlConnection(connstring);

            return dbConn;
        }

Step 8: Now we will add the method that will query the database and return a List of data that ultimately will be inserted into the Silverlight application. Notice that we create a method called getSupplierList() of type List< Suppliers>, where Suppliers is the name of the class created in step 6.

    public List<Suppliers> getSupplierList()
        {

            List<Suppliers> SupplierList = new List<Suppliers>(); //list that will containt all data retrieved from the database. 

            SqlConnection dbConn = connectToDB();//Method above
            string _selectQuery = string.Format("SELECT * FROM suppliers");//Query
            try
            {
                dbConn.Open();
                //Creates the comand object and sets the query of the command.
                SqlCommand cmd = new SqlCommand(_selectQuery, dbConn); //Executes
                SqlDataReader rdr = cmd.ExecuteReader(); //loop, read data

                while (rdr.Read())//for hver række der bliver hentet ind, gør vi følgende
                {

                    Suppliers Sup = new Suppliers();

                    Sup.ID = (int)rdr[0];
                    Sup.Name = (string)rdr[1];
                    Sup.Country = (string)rdr[2];

                    SupplierList.Add(Sup); //row is added

                }

            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
            return SupplierList;
        }
    }

Step 9: Open IService1.cs again. Before the public class Suppliers that you created earlier, add the OperationContract shown below, that exposes your getSupplierList() method and makes it accessable to the ViewModel.

[ServiceContract]
    public interface IService1
    {

        [OperationContract]
        List<Suppliers> getSupplierList(); //Name of method in Service1

    }

Step 10: Repeat step 1 (publish).

Now, we need to connect the ViewModel to the Model.

Step 11: On your ViewModel, right-click on References, and chose Add new Webservice. Here you will want to find the webService you have uploaded to the server. In the address field, enter http://yourDomain.com/Service1.svc, like shown below. Name your WebService (I have named mine QMWebService) and click 'OK'.

Now, you have connected the ViewModel to the Model.

If your service is not hosted locally and your Silverlight is, then you will get a warning about CrossDomain policy. To enable your service to receive calls from your locally hosted application, follow step 12:

Step 12: Create a new .xml file that contains the following code (source).


<?xml version="1.0" encoding="utf-8"?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="SOAPAction">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

Copy the file to the root of your server.

Step 13: This step is necessary in order for the View to reflect the changes made to it when the property in the ViewModel is set (updated). You will have to add a class to your ViewModel, and just copy-paste the code from below. It is taken from the MVVM demo application by Josh Smith, and can be also be found here. Name the class ViewModelBase.cs.

Name the class ViewModelBase, as all classes in the ViewModel are inherited from it.


using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Diagnostics;

namespace SilverLightViewModel
{
    /// <summary>
    /// Base class for all ViewModel classes in the application.
    /// It provides support for property change notifications
    /// and has a DisplayName property.  This class is abstract.
    /// </summary>
    public abstract class ViewModelBase : INotifyPropertyChanged, IDisposable
    {
        #region Constructor

        protected ViewModelBase()
        {
        }

        #endregion // Constructor

        #region DisplayName

        /// <summary>
        /// Returns the user-friendly name of this object.
        /// Child classes can set this property to a new value,
        /// or override it to determine the value on-demand.
        /// </summary>
        public virtual string DisplayName { get; protected set; }

        #endregion // DisplayName

        #region Debugging Aides

        /// <summary>
        /// Warns the developer if this object does not have
        /// a public property with the specified name. This
        /// method does not exist in a Release build.
        /// </summary>
        //[Conditional("DEBUG")]
        //[DebuggerStepThrough]
        //public void VerifyPropertyName(string propertyName)
        //{
        //    // Verify that the property name matches a real,
        //    // public, instance property on this object.
        //    if (TypeDescriptor.GetProperties(this)[propertyName] == null)
        //    {
        //        string msg = "Invalid property name: " + propertyName;

        //        if (this.ThrowOnInvalidPropertyName)
        //            throw new Exception(msg);
        //        else
        //            Debug.Fail(msg);
        //    }
        //}

        /// <summary>
        /// Returns whether an exception is thrown, or if a Debug.Fail() is used
        /// when an invalid property name is passed to the VerifyPropertyName method.
        /// The default value is false, but subclasses used by unit tests might
        /// override this property's getter to return true.
        /// </summary>
        protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

        #endregion // Debugging Aides

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Raised when a property on this object has a new value.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises this object's PropertyChanged event.
        /// </summary>
        /// <param name="propertyName">The property that has a new value.</param>
        protected virtual void OnPropertyChanged(string propertyName)
        {
            //this.VerifyPropertyName(propertyName);

            PropertyChangedEventHandler handler = this.PropertyChanged;
            if (handler != null)
            {
                var e = new PropertyChangedEventArgs(propertyName);
                handler(this, e);
            }
        }

        #endregion // INotifyPropertyChanged Members

        #region IDisposable Members

        /// <summary>
        /// Invoked when this object is being removed from the application
        /// and will be subject to garbage collection.
        /// </summary>
        public void Dispose()
        {
            this.OnDispose();
        }

        /// <summary>
        /// Child classes can override this method to perform
        /// clean-up logic, such as removing event handlers.
        /// </summary>
        protected virtual void OnDispose()
        {
        }

#if DEBUG
        /// <summary>
        /// Useful for ensuring that ViewModel objects are properly garbage collected.
        /// </summary>
        ~ViewModelBase()
        {
            string msg = string.Format("{0} ({1}) ({2}) Finalized", this.GetType().Name, this.DisplayName, this.GetHashCode());
            System.Diagnostics.Debug.WriteLine(msg);
        }
#endif

        #endregion // IDisposable Members
    }
}

Step 14: The next step is to go to your MainPage_ViewModel, that will contain the necessary properties and eventhandlers. The aim with this class is to register changes, call the WebService, and retrieve the data that will be inserted into the .xaml Grid, that will be created in the next step.

MainPage_ViewModel:


using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SilverLightViewModel;//new
using System.Collections.ObjectModel;//new
using ViewModel.QMServiceReference; //new

namespace ViewModel
{
    public class MainPage_ViewModel : ViewModelBase
    {
        private ObservableCollection<Suppliers> _suppliers; //Collection registres changes. Updates run.
        //list of all supplies

        public MainPage_ViewModel()
        {

            QMServiceReference.Service1Client WebService = new Service1Client();
            WebService.getSupplierListCompleted += new EventHandler<getSupplierListCompletedEventArgs>(WebService_getSupplierListCompleted);//Eventhandler is trigged when the webservice call has been run, and data han been retrieved
            WebService.getSupplierListAsync(); //calls webservice. 

        }

        void WebService_getSupplierListCompleted(object sender, getSupplierListCompletedEventArgs e)
        {

            //Is called when the webservice returnes a list 

            Suppliers = e.Result;
        }

        # region Properties

        public ObservableCollection<Suppliers> Suppliers
        {
            get { return _suppliers; } //instance of Suppliers
            set
            {
                _suppliers = value;
                OnPropertyChanged("Suppliers");
            }//property name
        }

        # endregion

    }
}

Step 15 (last step!): Create a Grid in your MainPage.xaml, like the one shown below. Notice that the name of the binding attribute is not named after the name you have created in your database, but rather in what you declared them in your Model, in the Suppliers class (see step 6).

MainPage.xaml:

 <data:DataGrid x:Name="SupplerGrid" MinHeight="100" IsReadOnly="True" AutoGenerateColumns="False" ItemsSource="{Binding Suppliers}">
                <data:DataGrid.Columns>
                    <data:DataGridTextColumn x:Name="ID" Header="ID" Binding="{Binding ID}" />
                    <data:DataGridTextColumn x:Name="ID2" Header="Name" Binding="{Binding Name}" />
                    <data:DataGridTextColumn x:Name="testData" Header="Value" Binding="{Binding Country}" />
                </data:DataGrid.Columns>
            </data:DataGrid>

And no... this time I won't end the post by stating "And that's it!", because this task is horrible, frustrating and endlessly time-consuming. But it works. I hope this post will help somebody get through the process costing only a limited amount of blood, sweat and tears.

Enjoy!

13Jun/100

MVVM Structure

This post explains how to set up a project according to the MVVM Design Pattern (Model-View-ViewModel). What needs to be done is to create three projects called Model (WCF Service Application), View (Silverlight application), and ViewModel (Silverlight class):

Step 1: Add a new project named Model: Right-click on your Solution >> Add new project >> Visual C# >> WCF >> WCF Service Application. The project will contain the method that connects to the database and returns a list. OBS: Remember to change to .Net Framework 3.5 instead of .NET Framework 4.0.

Model

Step 2: Add a new project named View. Right-click on your Solution >> Add new project >> Visual C# >> Silverlight >> Silverlight Application. This project will contain all the .xaml files.

Uncheck the "Host the Silverlight application in a new or existing Web site in the solution".

Step 3: Add a new project named ViewModel. Right-click on your Solution >> Add new project >> Visual C# >> Silverlight >> Silverlight Class Library. A class will be auto-generated, and name it MainPage_ViewModel.cs as it will contain all code-behind for your MainPage.xaml.

So, the structure of the application has been created, and next we need to link the View and ViewModel together, by creating a reference:

Step 4: Select your View and right-click on References: Click Add reference >> Projects >> Chose ViewModel from the list.

Step 5: Go to MainPage.xaml.cs, and add using ViewModel; at the top. Also, add the code snippet seen in line 8, that will create a new instance of the MainPage_ViewModel() class.


using ViewModel; 

namespace View
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            this.DataContext = new MainPage_ViewModel();
        }
    }
}

And that's it! (Well, almost: to actually use this structure and gather data from a database thorugh a WCF and bind the Model and the ModelView together, you'll need to follow the steps of my next post).

13Jun/100

Changes…

So, a while ago I figured out that I needed to make some pretty drastic changes to my project before being able to code the rest of the functionality needed for my application. The problem originated from beginners mentality I suppose, because the very structure of my project was the main problem.

Also, for various reasons I have chosen to use a MS SQL database instead of the MySQL, so I will not be using the ODBC connection that I described in an earlier post.

So, I had to make two changes: I had to structure my project according to the MVVM Design Pattern (Model-View-ViewModel), and I had to set up and connect to a MS SQL database.

Deciding to change the structure of my project was necessary, but pretty frustrating, as I basically have to build up a whole new project and start again from scratch. Of course, most of the functionality from my old project can be reused, and I have fortunately documented and blogged about most of it, so the rebuilding will not take as much time as it did the first time I went through it all.

Wish me luck!

Filed under: Misc. No Comments