.NET Blog

Tony Cavaliere

 
My Favourite Albums
  And the Grappa wins.
E-mail me Send mail

Disclaimer

Hey unlike other bloggers I stand by what I say but just in case. The opinions expressed herein are my own except on Tuesday when the second card is not turned up otherwise it ain't worth squat.

© Copyright 2012

More Free Web Site Templates

Back in an earlier post, Free Web Site Templates, I blogged about a cool site where you can download hundreds of free CSS Web Site Templates. StyleShout.com is another site where you can download free CSS templates. Currently this site has 25+ free templates to choose from and I'm sure as time progresses many more will be added to their gallery.

Guess the movie (Just watched this movie and it was great!)

Woman stands topless in front of you, "ma'am" could be taken as an insult.

Currently rated 1.5 by 4 people

  • Currently 1.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: ,
Categories: ASP.NET | HTML | CSS
Posted by CynotWhyNot on Friday, August 29, 2008 9:32 AM
Permalink | Comments (3) | Post RSSRSS comment feed

Widgets for your Blog or Web Site

You nay have noticed a few changes to my blog. Take a look to the left and you will notice a number of widgets. You can now easily add this blog to your favourites using the bookmark widget. One of my favourites is the AnswerTips widget, just double click a word on my blog and a popup window appears with the definition of the word. Another favourite is Snap Shots which augments each link on your site by adding an icon to left of the link. Whenever you hover over the icon a popup appears. This popup contains a small image of the site the link points to. I have added this widget to my home page. Check it out!

If you are interested in these widgets and many more visit 50 Great Widgets For Your Blog.

Guess the movie

Oh my God. I'm back. I'm home. All the time, it was... We finally really did it.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by CynotWhyNot on Saturday, August 23, 2008 1:33 PM
Permalink | Comments (1) | Post RSSRSS comment feed

CynotWhyNot Added to Technorati

More ways to enjoy CynotWhyNot!

Technorati Profile

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by CynotWhyNot on Monday, August 18, 2008 7:52 AM
Permalink | Comments (2) | Post RSSRSS comment feed

Calling a WCF Service from Silverlight 2.0: Part Two

In part one of this post series, I showed the working Silverlight application that calls a WCF service. If you would like to see this application then go to part one.

In this post we will show how one goes about creating this application. This post is divided into fout main sections;

  1. Creating the WCF service.
  2. Creating the Silverlight application that consumes the service.
  3. Deployment Issues
  4. Deploying the WCF service and Silverlight control.

Initial Setup

Let's start by creating a Silverlight application. Start VS2008 and then select File->New Project menu option. This will bring up the New Project dialog. This dialog is shown in Figure 1. I have decided to name this project WCF.

New Project 

Figure 1: Creating a Silverlight Application.

In my case I have chosen the to create a Silverlight application using the VB.NET language. After clicking the OK button, the Add Silverlight Application dialog appears. As shown in Figure 2, accept the defaults and click the OK button.

Add Silverlight Application

Figure 2: The Add Silverlight Application Dialog.

VS2008 should have created a solution with two projects; the first an ASP.NET application used to host the Silverlight control and a second which is the Silverlight control. Figure 3 shows the solution window with these two projects.

Initial Silverlight Solution 

Figure 3: The Initial Silverlight Solution.

We are now ready to create the WCF service.

 

WCF Service

The service we about to create will return a list of person objects. Begin by adding a new class to the web site project. To do this right click on the WCFWeb project and select the Add New Item menu option. This will result in the Add New Item dialog appearing as shown in Figure 4.

Add New Item Person Class

Figure 4: Adding the Person class

Name the class Person and select the OK button. This will cause an additional dialog to appear asking whether you want to add the code to the App_Code directory, select OK. Modify the generated Person class as per Listing 1.

Imports System.ServiceModel

Imports System.Runtime.Serialization

Imports Microsoft.VisualBasic

 

'This class needs to be serializable. The DataContract attribute is the WCF way

'of doing this.

<DataContract()> _

Public Class Person

 

    'First name of the person. You must opt in to make a property serializable,

    'hence the DataMember attribute.

    Private _First As String

    <DataMember()> _

    Public Property First() As String

        Get

            Return _First

        End Get

        Set(ByVal value As String)

            _First = value

        End Set

    End Property

 

    'Last name of the person. You must opt in to make a property serializable,

    'hence the DataMember attribute.

    Private _Last As String

    <DataMember()> _

    Public Property Last() As String

        Get

            Return _Last

        End Get

        Set(ByVal value As String)

            _Last = value

        End Set

    End Property

 

    'Simple constructor.

    Public Sub New(ByVal first As String, ByVal last As String)

        Me.First = first

        Me.Last = last

    End Sub

 

End Class

Listing 1: Person Class

The Person class is rather simple containing just two properties and one constructor. The class is decorated with the <DataContract()> attribute which indicates it is serializable. The <DataMember()> attributes that decorate the two properties indicates that the members are part of the contract and are serializable. Unlike the <Serializable()> attribute, where by default properties are automatically serialized, with the <DataContract()> attribute you must explicitly chose which properties are included during serialization.

Next add a WCF Service template to the web project. Right click on the web project and select the Add New Item menu option. This will bring up the Add New Item dialog as shown in Figure 5. Call the service PersonService.

Add New Item - WCF Service

Figure 5: Add the WCF Service

After selecting the Add button, three new files are added to the web project; IPersonService.vb, PersonService.vb and PersonService.svc. In addition, the web.config file is modified with the addition of the <system.serviceModel> section.

Let's investigate each file.

As previously mentioned the web.config is modified whenever a WCF service is added to the project. Specifically, the section <system.serviceModel> is added. It is here that the configuration of the newly added WCF service exists. Two changes are required in order to get the service to properly working. Firstly, the binding wsHttpBinding needs to be changed to basicHttpBinding as Silverlight currently only supports the basicHttpBinding. The second change, although not strictly required, is to hard code the port for the dns. I like to do this to ensure that the application will always work regardless of which port the development web server decides to chose. An alternative approach would be to create a web application which automatically configures an IIS virtual directory. In order to hard code a port number select the web site project and go to the Properties window. Next set Use dynamic ports to False and then chose some port number. I like to use a port number of 666. Now you can update the web.config and hard code the dns value to localhost:666. Figure 6 shows the property window with the hard code port number and Listing 2 shows the <system.serviceModel> section with the binding and port number changes.

Property Window Port Number

Figure 6: The Web Site Project Properties Window with the hard coded port number

 

 

    <system.serviceModel>

        <behaviors>

            <serviceBehaviors>

                <behavior name="PersonServiceBehavior">

                    <serviceMetadata httpGetEnabled="true" />

                    <serviceDebug includeExceptionDetailInFaults="false" />

                </behavior>

            </serviceBehaviors>

        </behaviors>

        <services>

            <service behaviorConfiguration="PersonServiceBehavior" name="PersonService">

                <endpoint address="" binding="basicHttpBinding" contract="IPersonService">

                    <identity>

                        <dns value="localhost:666" />

                    </identity>

                </endpoint>

                <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />

            </service>

        </services>

    </system.serviceModel>

Listing 2: web.config

The change to the IPersonService.vb interface is small as all we need to do is change the generated function name to something more meaningful. Listing 3 shows the necessary changes to IPersonService.vb.

 

Imports System.ServiceModel

 

<ServiceContract()> _

Public Interface IPersonService

 

    <OperationContract()> _

    Function GetPeople() As List(Of Person)

 

End Interface

Listing 3: IPersonService.vb

Note the only change to the templated interface is the function name and that it returns a list of person objects. The interface is decorated with the <ServiceContract()> attribute indicating the interface defines a service contract in a WCF application. The <OperationContract()> attribute indicates that the GetPeople function defines an operation that is part of a service contract. The bottom line is that a client (Silverlight in our case) can call the function GetPeople across process boundaries.

The PersonService class needs to implement the IPersonService interface. Listing 4 contains the modifications to the class.

 

Imports System.ServiceModel

 

'Implementation of IPersonService.

<ServiceBehavior(IncludeExceptionDetailInFaults:=True)> _

Public Class PersonService

    Implements IPersonService

 

    'Return an in memory list of people.

    Public Function GetPeople() As List(Of Person) Implements IPersonService.GetPeople

        Dim people As New List(Of Person)

        people.Add(New Person("John", "Smith"))

        people.Add(New Person("Jane", "Summers"))

        Return people

    End Function

 

End Class

Listing 4: PersonService.vb

The implementation of the GetPeople function is rather simple. Firstly, we create a reference to a List of Person objects. Next two person objects are added to the list collection and finally this list of persons is returned.

The PersonService.svc represents the end point to the service. Provided we run the service within the development environment, this file does not require any modifications. Later, in the this post we will discuss deployment issues and we will see that modifications to this file and additional code is required when hosting the service on a web server that uses multiple host headers (i.e., more than one address). More on that later.

Right click on the PersonService.svc and select the  View in Browser menu option. If all is well you should see the default service web page appearing (see Figure 7).

Browse to PersionService

Figure 7: Navigating to the PersonService.svc service.

That's it we have created a WCF service. Now let's move on to consuming this service from within a Silverlight application.

 

Consuming the WCF Service from within Silverlight

We will start by adding a reference to the service. Right click on the Silverlight project and select the Add Service Reference menu item. This will bring up the Add Service Reference dialog. Select the Discover button. This will cause the IDE to search the solution for all services, displaying them in the list box. Since there is only one service in the solution the Services list box will only contain a single service, namely, PersonService.svc. Change the namespace to PersonProxy. After doing this the dialog should appear similar to Figure 8.

Add Service Reference

Figure 8: Adding a Service Reference to the Silverlight Project

Select OK. This will add the PersonProxy reference to the project and in addition will add the ServiceReferences.ClientConfig configuration file. This configuration file requires modification as it does not contain the fully qualified name of the service. It is missing the namespace, WCF (the name of the project). I'm not sure if this is a Beta 2 bug and perhaps it will be fixed for RTM. After this change the ServiceReferences.ClientConfig file should appear the same as in Listing 5.

<configuration>

    <system.serviceModel>

        <bindings>

            <basicHttpBinding>

                <binding name="BasicHttpBinding_IPersonService"

                    maxBufferSize="65536"

                    maxReceivedMessageSize="65536">

                    <security mode="None" />

                </binding>

            </basicHttpBinding>

        </bindings>

        <client>

            <endpoint address="http://localhost:666/WCFWeb/PersonService.svc"

                binding="basicHttpBinding"

                bindingConfiguration="BasicHttpBinding_IPersonService"

                contract="WCF.PersonProxy.IPersonService"

                name="BasicHttpBinding_IPersonService" />

        </client>

    </system.serviceModel>

</configuration>

Listing 5: ServiceReferences.ClientConfig

This configuration file is included as content into the Silverlight XAP deployment file. If you need to change the end point, as you would need to do so if you are changing the location of the WCF service, then you can rename the XAP extension to ZIP, unzip the contents, modify the endpoint, re-zip the file and rename the extension back to XAP.

Before we can write any code to call the service, we need to add some UI to the Page.xaml file. I have chosen to display the data in a DataGrid. To initiate the call to the sercice I have added a button control. Finally, in case there were any errors generated during the call to the service, I have included a TextBlock. Let's proceed with the UI.

Listing 6 contains the complete XAML for the UI. The default generated Grid has been replaced with a StackPanel. Within the StackPanel are the Button, DataGrid and TextBlock controls. It is best not to paste the code from this listing into your copy of Page.xaml as the DataGrid requires an addition reference which is automatically included when you drag and drop the control.

<UserControl

   xmlns:my="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" 

   x:Class="WCF.Page"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

   Width="500" Height="250">

 

    <StackPanel x:Name="LayoutRoot" Background="Bisque">

        <Button Content="Call WCF Service" FontSize="24" Width="220" Height="50"

               Margin="15" Click="btnWCF_Click" />

        <my:DataGrid x:Name="grdPeople" AutoGenerateColumns="False"

                    FontSize="24" Width="500" RowHeight="50" 

                    Visibility="Collapsed">

            <my:DataGrid.Columns>

                <my:DataGridTextColumn Header="First Name" FontSize="24" Width="230"

                   DisplayMemberBinding="{Binding First}" />

                <my:DataGridTextColumn Header="Last Name" FontSize="24" Width="237"

                   DisplayMemberBinding="{Binding Last}" />

            </my:DataGrid.Columns>

        </my:DataGrid>

        <TextBlock x:Name="txtError" TextWrapping="Wrap" Width="500" Height="350"

                  ScrollViewer.VerticalScrollBarVisibility="Auto" />

    </StackPanel>

 

</UserControl>

Listing 6: Page.xaml

A couple of notes on the DataGrid. The AutoGenerateColumns is set to false so that we can control which items are data bound. We are declaratively binding the first and last name using the DisplayMemberBinding attribute. Later in the code behind we will call the service and set the ItemSource of the DataGrid.

That's it for the UI now let's concentrate on the code behind.

The code behind for Page.xaml is responsible for calling the WCF service and then setting the ItemSource of the DataGrid to the list of person objects. Listing 7 contains the complete code listing for page.xaml.vb.

Partial Public Class Page

    Inherits UserControl

 

    Public Sub New()

        InitializeComponent()

    End Sub

 

    Private Sub btnWCF_Click( _

        ByVal sender As System.Object, _

        ByVal e As System.Windows.RoutedEventArgs)

 

        Dim proxy As New PersonProxy.PersonServiceClient()

        AddHandler proxy.GetPeopleCompleted, AddressOf onGetPeopleCompleted

        proxy.GetPeopleAsync()

 

        grdPeople.Visibility = Windows.Visibility.Collapsed

        grdPeople.ItemsSource = Nothing

 

    End Sub

 

    Public Sub onGetPeopleCompleted( _

        ByVal sender As Object, _

        ByVal e As PersonProxy.GetPeopleCompletedEventArgs)

 

        If e.Error Is Nothing Then

            grdPeople.Visibility = Windows.Visibility.Visible

            grdPeople.ItemsSource = e.Result

        Else

            txtError.Text = e.Error.ToString

        End If

 

    End Sub

 

End Class

Listing 7: Page.xaml.vb

The code consists of two methods. The btnWCF_Click method is wired to the button click event. This is where we instantiate the PersonProxy. Next an event handler for the GetPeopleCompleted event is added specifying the method to be called when the event is fired. We then initiate the call to the service by invoking GetPeopleAsync. Silverlight will only allow asynchronous calls to services.

The method onGetPeopleCompleted is responsible for binding the data to the DataGrid. As a precaution, we first check to see if an error has occurred and if so the error is displayed in a TextBlock. I have found that exceptions that happen during the call to the WCF service are by default hidden, i.e., they appear as (404) Not Found exception. This is a security feature as you don't necessarily want the consumers of the service to have knowledge of your code. Further investigation is  required to know how to best handle these kinds of exceptions.

If no error is generated during the call to the WCF service then the returned data (e.Result) is is bound to the DataGrid via the ItemSource property.

That's it we are done. Let's try running the application. Right click the WCFTestPage.aspx file in the web site project and select View in Browser menu option. This should bring up the browser and hopefully the Silverlight control will appear. Click the Call WCF Service button and after a short period of time a DataGrid should appear, containing a list of people. Figure 9 shows the DataGrid with the list of people.

I also have a working copy of this Silverlight control embedded in my previous post.

WCF Test Page

Figure 9: Running the Silverlight Test Page. 

 

Deployment Issues

I wanted to share with you some challenges I came across when I deployed this WCF service to my ISP. Hopefully this will save you some time.

The first problem I came across was using Silverlight for cross-domain communication, that is, Silverlight by default can only call services that are hosted on the same domain. This prevents cross-site request forgery and prevents a Silverlight control from making unauthorized calls to a third party service. In order for a Silverlight control to access a service in another domain the service must grant access. This can be done by installing one of two files on the web server. I will discuss only one of these files, the ClientAccessPolicy.xml. The contents of this file is shown in Listing 8.

<?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 include-subpaths="true" path="/" />

      </grant-to>

    </policy>

  </cross-domain-access>

</access-policy>

Listing 8: ClientAccessPolicy.xml

To add this file to the web site project, right click the project and select the Add New Item menu option. From the Add New Item dialog box select the XML file template and name it ClientAccessPolicy.xml. Finally, cut and paste the contents of the XML in listing 8 into this XML file.

As indicated by the <domain uri="*" /> node, this file allows requests from any domain. For further details on allowing cross-domain access visit MSDN Site. This file must be deployed to the root of the domain where the service is installed.

The second problem was a little more difficult to resolve. After I installed the the ClientAccessPolicy.xml file to the web server I received the following error:

This collection already contains an address with scheme http: There can be at most one address per scheme in the collection.

After a bit of searching I found a few posts that explained this multiple bindings issue. Out of the box .NET does not support multiple bindings per site and since I am hosting this service on my ISP the likelihood that it has multiple bindings is great. Thankfully there is a way around this that involves creating your own custom service host factory. This factory is responsible for choosing the appropriate base address. Listing 9 shown this custom service host factory.

 

Imports Microsoft.VisualBasic

Imports System.ServiceModel.Activation

Imports System.ServiceModel

 

Public Class CustomHostFactory

    Inherits ServiceHostFactory

 

    Protected Overrides Function CreateServiceHost( _

        ByVal serviceType As System.Type, _

        ByVal baseAddresses() As System.Uri) _

        As System.ServiceModel.ServiceHost

 

        Return New ServiceHost(serviceType, baseAddresses(0))

 

    End Function

 

End Class

Listing 9: Custom Service Host Factory

To add this code right click the App_Code folder in the web site project and select the Add New Item menu option. Then from the Add New Item dialog select the Class template and name it CustomService.vb. Finally cut and paste the code from Listing 9 into CustomService.vb.

The code is rather simple. The class CustomHostFactory inherits from ServiceHostFactory and overrides the CreateServiceHost function. The implementation creates an instance of a ServiceHost class and chooses the first base address from the collection of addresses.

Next the PersonService.svc file must be changed so that the service is created using this custom service host factory. Listing 10 shows this modified PersonService.svc file. For further information please visit the following blog post.

 

<%@ ServiceHost Language="VB" Debug="true" Factory="CustomHostFactory"

Service="PersonService" CodeBehind="~/App_Code/PersonService.vb" %>

Listing 10: Adding Custom Service Host Factory to PersonService.svc

 

Deploying the WCF Service and Silverlight Application to a Web Server

WCF Service:

Copy the following files to the virtual directory where the service is to be hosted:

  • App_Code/CustomService.vb
  • App_Code/IPersonService.vb
  • App_Code/Person.vb
  • App_Code/PersonService
  • PersonService.svc
  • web.config (modify the DNS value and set it to the domain where the service is to hosted)

Silverlight Application:

Add the Silverlight control to whatever page you desire. If you need to change the location of the WCF Service then you can rename the XAP extension to ZIP, unzip the contents, modify the endpoint in the ServicesReferences.ClientConfig file, re-zip the file and rename the extension back to XAP. 

Guess the movie

See that clock on the wall? In five minutes you are not going to believe what I've told you.

Currently rated 4.0 by 5 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: Silverlight | WCF
Posted by CynotWhyNot on Friday, August 15, 2008 6:29 AM
Permalink | Comments (173) | Post RSSRSS comment feed

Calling a WCF Service from Silverlight 2.0: Part One

In the next two posts I will describe how to create a WCF service and then how to consume it from within a Silverlight 2.0 application. But before we begin with the code let's take a look at the final application. Below is a SilverLight control that calls a WCF service. The WCF service returns a list of person objects. For the purpose of this demo the Person object is rather simple and contains only two properties; the first and last name. Clicking the button will call the WCF service, asynchronously, returning a list of person objects. This list of Person objects is then bound to a Silverlight DataGrid control. Go ahead, try it.

 

 

Stay tuned for the next post where I will detail how to create the WCF service and how to consume the service from within a Silverlight application.

Guess the movie

Know this. This creature is the bringer of death. He will never eat, he will never sleep, and he will never stop.

Currently rated 1.0 by 2 people

  • Currently 1/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: Silverlight
Posted by CynotWhyNot on Tuesday, August 12, 2008 10:45 PM
Permalink | Comments (30) | Post RSSRSS comment feed