Home > English > Gofer – Silverlight

Gofer – Silverlight

In our last post, we used Gofer in a Console application and got data from a SQL Server database as well as creating the database from our domain model. Today, we are going to be doing the same thing but we will be doing this with Silverlight.

First, start by create a new Silverlight 5 application.

Make sure that you do NOT enable WCF RIA Services!

Next, we are going to setup of the web project first and then move over to the Silverlight project once we are done. Let’s start with getting Gofer from NuGet. Right-click on your References folder and select Manage NuGet Packages. Next, type in “Gofer” as your search criteria. Select Gofer.Sample as your choice. This package comes with the Gofer library as well as with some helper files to make testing this easier.

Gofer.Sample has a dependency on SwitchBlade and ValueInjecter.

SwitchBlade is another package that I wrote that allows you to host Razor templates outside of ASP.NET and IIS. I will be covering SwitchBlade in a future post.

ValueInjecter is a package like AutoMapper but much more convention-based and easier.

We are also going to need to use Ninject as our DI/IOC container. We will use NuGet to install this package as well:

Finally, we will need the WCF Web API from NuGet as well:

Moving on from adding all of our packages, you will also notice that you have two new template folders for your CRUD and DDL operations. You can modify these templates to shape how you want your SQL code to look when it is used by Gofer.

You will also notice two new files:

Domain.cs – This file represents a sample domain model. It is very similar to what you would see from a Northwind with some slight modifications.

TestDriver.cs – This file is a test driver class that allows us to test Gofer. We will be using a Silverlight version of this file instead. DELETE this file from the project as we do not need it.

Next, let’s add a Global.asax file to the project and modify as shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;

using System.Web.Routing;
using Microsoft.ApplicationServer.Http;
using Ninject;
using Domain;
using Gofer;

namespace GoferSilverlight.Web
{
    public class Global : System.Web.HttpApplication
    {
        public const string NAMESPACE = "Domain";
        public Func<Type,bool> PREDICATE = x => x.Namespace == NAMESPACE;

        protected void Application_Start(object sender, EventArgs e)
        {
            RouteTable.Routes.SetDefaultHttpConfiguration(new WebApiConfiguration()
            {
                CreateInstance = (serviceType, context, request) => CreateInstance(serviceType),
                EnableTestClient = true
            });

            RouteTable.Routes.MapServiceRouteForAssemblyOf<Customers>(PREDICATE);
        }

        private object CreateInstance(Type serviceType)
        {
            object result = null;
            IKernel kernel = new StandardKernel();
            try
            {
                // The following is a sample entry for using the MapServiceRoute method:
                // RouteTable.Routes.MapServiceRoute<GoferService<Customers>>("Customer");
                // Hence the reason we need to pull the generic type from the GoferService.
                var genericType = serviceType.GetGenericArguments().FirstOrDefault();
                SchemaRules rules = GetRules(genericType);
                kernel.Bind(serviceType).ToSelf().WithConstructorArgument("rules", rules);
                result = kernel.Get(serviceType);
            }
            catch { }

            return result;
        }

        #region Rules

        private SchemaRules GetRules(Type type)
        {
            var result = new SchemaRules();
            result.AssemblyOf(type)
                .ShouldMap(PREDICATE)
                .GetSchema();

            result.PerformMigration = true;
            result.ForceNewMigration = false;

            return result;
        }

        #endregion

    };
}

UPDATE: I added a Fun<Type,bool> predicate so you could easily add your own logic for both the “RouteTable.Routes.MapServiceRouteForAssemblyOf<Customers>(PREDICATE)” and the .ShouldMap(PREDICATE) calls.

If you are curious as to what is going on here, please refer to my post Building a Generic Service using WCF Web API – Part II as it walks you through all of these steps.

One thing to point out here is that we are using the same SchemaRules class.

SchemaRules – This tells the Gofer engine what conventions to use for its data access. There is a ton that you can override with this class and we will take a look at that in a later post but this is the bare minimum that you need to get going. Also, you will see two properties that tell the engine whether or not to perform a migration as well as force the migration, meaning that it will drop the database and recreate it if necessary.

There is one last change that you need to put in place before we can test our service. We will need to modify the Web.config. The following is a sample Web.config that you can pattern against for yourself:

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit

http://go.microsoft.com/fwlink/?LinkId=169433

  -->
<configuration>
  <appSettings>
    <add key="DB_NAME" value="Example" />

    <add key="DDL_ConnectionString" value="Provider=SQLOLEDB;Server=(local);Database=master;Integrated Security=SSPI;" />
    <add key="DDL_DatabaseType" value="4" />

    <add key="ConnectionString" value="Data Source=(local);Initial Catalog=Example;Integrated Security=SSPI;" />
    <add key="DatabaseType" value="3" />

    <add key="TemplatePath" value="C:\Users\Matt\Documents\visual studio 2010\Projects\GoferSilverlight\GoferSilverlight.Web\CRUD_Templates" />
    <add key="DDL_TemplatePath" value="C:\Users\Matt\Documents\visual studio 2010\Projects\GoferSilverlight\GoferSilverlight.Web\DDL_Templates" />
  </appSettings>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  </system.serviceModel>
</configuration>

If we run the application, you will see a blank screen but we can still test our service:

I am using the database that I tested with the previous post. Therefore, I knew I had at least one record in the Customers table. Based on the results of the service, I can see that I am getting back a good JSON response.

Ok, our service is ready, now let’s shift gears and see what we must do to test this on the Silverlight side.

We want to share our domain for both the client and server. Right-click your Silverlight project and select “Add | Existing Item…”. Navigate to the web project and select the Domain.cs file and click the down arrow to “Add As Link”. This will give us the domain model definition in our Silverlight project.

Next, let’s add our Gofer.Silverlight package from NuGet. Right-click on the References folder and select Manage NuGet Packages. Next, type in “Gofer” as your search criteria. Select Gofer.Silverlight as your choice.

Gofer.Silverlight has a dependency on Async CTP and HTTP Contrib which are provided as part of the install.

Async CTP is a library that helps make asynchronous programming easier.

Http Contrib is a library that helps make calling the WCF Web API easier from clients such as Silverlight.

You will also notice that a “readme.txt” file added to the project. If you open the file, you will see the you need to add the following code snippet to the constructor of your App.xaml.cs file:

HttpWebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);
HttpWebRequest.RegisterPrefix("https://", WebRequestCreator.ClientHttp);

I wrote a blog post here when I ran into some strange issues trying to test my services for PUT and DELETE behaviors.

Okay, let’s add the following TestDriver.cs class to the Silverlight project:

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 Gofer.DataAccess;
using Domain;

namespace GoferSilverlight
{
    public class TestDriver
    {
        public void Run()
        {
            var repo = new SilverlightRepository("Customers");
            var cust = new Customers()
            {
                CompanyName = "Bubba's Repair",
                ContactName = "Billy Bob",
                ContactTitle = "Owner",
                Address = "100 Pecan Street",
                City = "Columbia",
                PostalCode = "29661",
                Country = "USA",
                Phone = "(803) 836-1212",
                Fax = "(803) 836-1213"
            };
            repo.Create<Customers>(cust,
                (item) =>
                {
                    if (item == null)
                    {
                        // Handle data here....
                    }
                },
                (error) =>
                {
                    if (error == null)
                    {
                        // Handle error here....
                    }
                }
            );            
        }
    };
}

As you can see, this is very similar to what we used in the Console application but all calls are asynchronous and I also wanted to have a unique callback for success and errors. If the database did not exist, you could run this just like the Console code and a new database would be created as long as you had the PerformMigration property set to “true” in your Global.asax.cs file.

The final step to get this to work is to add the following code to the constructor of your MainPage.xaml.cs file:

TestDriver td = new TestDriver();
td.Run();

If you add a couple breakpoints as shown below, you should be ready to run the application:

When the debugger hits your breakpoint, you should see something similar to the following:

That’s it! This may seem like a lot of moving pieces to get this working but once you get in the groove, you will see that this is so much easier than dealing with proxies and hidden code generated files from Visual Studio. I personally really like this approach and I look forward to getting your response as well.

In the next couple of posts, I will be digging deeper into to Gofer as a whole to show you everything that you can do.

About these ads
  1. Chui Tey
    January 4, 2012 at 12:02 pm | #1

    which assembly does the following referenced in Global.asax reside in?
    using Microsoft.ApplicationServer.Http;

    • January 4, 2012 at 1:08 pm | #2

      Hi Chui,

      Did you add a reference to the WebApi.All package? That should have resolved your issues.

  2. Chui Tey
    January 4, 2012 at 12:31 pm | #3

    In my case Nuget never added the references to the necessary DLLs. Here’s what I required:

    System.Net
    System.ServiceModel

    GoferSilverlight\packages\HttpClient.0.6.0\lib\40\System.Net.Http.dll
    GoferSilverlight\packages\HttpClient.0.6.0\lib\40\Microsoft.Net.Http.Formatting.dll
    GoferSilverlight\packages\WebApi.0.6.0\lib\40-Full\Microsoft.ApplicationServer.Http.dll
    GoferSilverlight\packages\WebApi.Enhancements.0.6.0\lib\40-Full\Microsoft.ApplicationServer.HttpEnhancements.dll
    GoferSilverlight\packages\JsonValue.0.6.0\lib\40\Microsoft.Json.dll
    GoferSilverlight\packages\HttpClient.0.6.0\lib\40\Microsoft.Net.Http.Formatting.dll

    • January 4, 2012 at 1:12 pm | #4

      I just created a new Silverlight project and on the web project I added the WebApi.All NuGet package and it brought everything I needed. Please be sure that you brought in the correct package.

      Thanks,

      Matt

  3. Chui Tey
    January 4, 2012 at 9:12 pm | #5

    I’ve repeated the experiment a few times using “Tools” > “Library Package Manager” > “Manage NuGet Packages for Solution…”. but to no avail.

    In the end, I used the NuGet powershell, and this successfully added the references to the necessary DLLs in my solution.

    PM> install-package WebApi.All
    # download msgs here
    Successfully installed ‘WebApi.All 0.6.0′.
    Successfully added ‘JsonValue 0.6.0′ to WebApplication1.
    Successfully added ‘HttpClient 0.6.0′ to WebApplication1.
    Successfully added ‘WebApi 0.6.0′ to WebApplication1.
    Successfully added ‘WebApi.Enhancements 0.6.0′ to WebApplication1.
    Successfully added ‘WebApi.OData 0.6.0′ to WebApplication1.
    Successfully added ‘WebApi.All 0.6.0′ to WebApplication1.

  4. March 5, 2012 at 12:54 pm | #7

    Matt, I tried working through the entire tutorial again because I might have a small project that could use this, but it appears that WebApi.All is no longer in NuGet.

    There appears to be a few symbols changed or gone – SetDefaultHttpConfiguration, WebApiConfiguration. (Replaced with GlobalConfiguration.Configuration http://wcf.codeplex.com/discussions/318774)

    • March 5, 2012 at 2:42 pm | #8

      Hi Chui Tey,

      I am in the process of porting the WCF Web API to the new ASP.NET Web API. This has a Go Live license with it from Microsoft and you can run this in production. I am hoping to have this ported as quickly as possible and I will be doing some blog posts to announce the difference.

      Thanks,

      Matt

  5. March 5, 2012 at 9:12 pm | #9

    Great, thanks.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 193 other followers

%d bloggers like this: