Archive

Archive for the ‘WCF’ Category

Using ASP .NET Web API with CodeFluent Entities

February 27, 2013 2 comments

This post will guide you in implementing a service layer over HTTP using ASP .NET Wet API and CodeFluent Entities.

WCF is great to expose SOAP based web services and even JSON services. However WCF does not capitalize all the possibilities that the HTTP protocol can provide.

Indeed, HTTP is a real application-level protocol, and while WCF uses HTTP only as a transport protocol (as could be TCP, UDP, named Pipes…) the ASP .NET Web API takes advantage of all the features that the HTTP protocol provides as:

  • Actions defined by verbs: GET, POST, PUT, DELETE.
  • Headers that can suggest extra information like caching, requested content, security.
  • A body that can be used for any kind of content (not only XML like for SOAP web services).
  • URIs that can be used for identify resources and actions.

For this post we will use the CodeFluent Entities demo project ‘CarRental’.

Car Rental Demo Project

Car Rental Demo Project

And we are going to add a Persistence producer (SQL Server 2012 for me), a Business Object Model (BOM) producer and a Service sub producer so we can use the WCF serialization.

Producers

Producers

We will host our services in an ASP .NET MVC 4 web site (ASP .NET Web API can also be hosted as a service), more information here.

MVC 4 Internet Application

MVC 4 Internet Application

The ASP .NET Web API provides a custom ‘Controller’ that handles the HTTP actions (GET, POST, PUT, and DELETE) as well as the content negotiation (XML, JSON, HTML…), this base controller is of type System.Web.Http.ApiController.

As the HTTP services are resource-oriented services we may want to create one Controller per Entity in our model. We will lead this post using only the Entity ‘CarGroup’ of our model. We can create some instances of type CarGroup to have some data to test.

So we first need to create a controller that extends from ‘ApiController’. We will call it ‘CarGroupController’.

CarGroupController

CarGroupController

We can see in the code of our new Controller that some methods have been created. These methods will be associated with the HTTP actions (verbs) GET, POST, PUT and DELETE.

CarGroupController Acitons

CarGroupController Acitons

Besides, adding an Api Controller made a route configuration specific to ASP .NET Web API (App_Start->WebApiConfig.cs), so the routes for our resources will be {base url}/api/{controller}/{id}. For example, we will have http://localhost:21020/api/cargroup.

ASP .NET Web API uses a ‘Convention over Configuration’ approach so the prefix of each method matches a specific HTTP action.

We are now going to implement the Actions.

To get all the instances of type CarGroup :

// GET api/cargroup
public IEnumerable<CarGroup> Get()
{
    return CarGroupCollection.LoadAll();
}

To get one CarGroup by Id:

// GET api/cargroup/5
public CarGroup Get(int id)
{
    CarGroup carGroup = CarGroup.Load(id);
    if (carGroup == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    return carGroup;
}

To create a new CarGroup :

// POST api/cargroup
public HttpResponseMessage Post([FromBody]CarGroup carGroup)
{
    if (carGroup == null || !carGroup.Save())
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
    return Request.CreateResponse(HttpStatusCode.OK, carGroup);
}

To update a CarGroup :

// PUT api/cargroup
public HttpResponseMessage Put([FromBody]CarGroup carGroup)
{
    if (carGroup == null || !carGroup.Save())
    {
        return Request.CreateResponse(HttpStatusCode.BadRequest);
    }
    return Request.CreateResponse(HttpStatusCode.OK, carGroup);
}

And finally to delete a CarGroup :

// DELETE api/cargroup/5
public HttpResponseMessage Delete(int id)
{
    CarGroup carGroup = CarGroup.Load(id);
    if (carGroup != null && carGroup.Delete())
    {
        return Request.CreateResponse(HttpStatusCode.NoContent);
    }
    return Request.CreateResponse(HttpStatusCode.NotFound);
}

As you can see, we have easily created a Controller able to support CRUD operations. The ASP .NET Web API will manage all the aspects like content negotiation and HTTP verbs (GET, POST, PUT and DELETE).

As we have added a Service Sub Producer to our model, we can use the data contract serialization (System.Runtime.Serialization.DataContractSerializer).

Let us test our Web API Controller, we will use a simple Console Application.

For example to retrieve all our Car Groups:

string uri = "http://localhost:21020/api/cargroup";
HttpWebRequest request = HttpWebRequest.CreateHttp(uri);
request.Accept = "text/xml";//we only accept XML
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
    Console.WriteLine(response.StatusCode);
    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    {
        string result = reader.ReadToEnd();
        Console.WriteLine(result);
    }
}

And what we get (do not forget to add some instances to your model or you will not have any data):

Web API call test

Web API call test

If you want to get a specific CarGroup (id=1 for example) we only need to modify the URL (GET method):

string uri = "http://localhost:21020/api/cargroup/1";

If we want to test our other methods we only need to set the right HTTP method (verb), the right parameters (if needed) and the body data (if needed).

For example to update a CarGroup (PUT HTTP method):

CarGroup carGroup = //retrieve a CarGroup instance
carGroup.DailyRate++;//update the instance

string uri = "http://localhost:21020/api/cargroup";
HttpWebRequest request = HttpWebRequest.CreateHttp(uri);
request.Accept = "text/xml"; //we only accept XML
request.Method = "PUT";
request.ContentType = "text/xml; charset=UTF-8";//we will send XML
string bodyData = "";

//----- serializing data --------------
DataContractSerializer serializer = new DataContractSerializer(typeof(CarGroup));
using (MemoryStream stream = new MemoryStream())
{
    serializer.WriteObject(stream, carGroup);
    stream.Seek(0, SeekOrigin.Begin);
    using (StreamReader reader = new StreamReader(stream))
    {
        bodyData = reader.ReadToEnd();
    }
}
//----- writing data in to the request --------------
request.ContentLength = bodyData.Length;
using (StreamWriter requestWritter = new StreamWriter(request.GetRequestStream()))
{
    requestWritter.Write(bodyData);
}

//----- reading the response
string result = "";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
    Console.WriteLine(response.StatusCode);
    using (StreamReader reader = new StreamReader(response.GetResponseStream()))
    {
        result = reader.ReadToEnd();
    }
}

//----- deserializing the response
CarGroup updatedObject = null;
using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(result)))
{
    updatedObject = (CarGroup)serializer.ReadObject(stream);
}

This works great with XML, and if we want to use JSON we only need to specify it in our request.

request.Accept = "text/json"; //we only accept JSON
request.ContentType = "text/json; charset=UTF-8";//we will send JSON

We can even send XML and ask for JSON or send JSON and ask for XML.

We need to tell ASP .NET Web API to use the WCF JSON serializer.

In the App_Start->WebApiConfig.cs file:

JsonMediaTypeFormatter jsonFormatter = (JsonMediaTypeFormatter)config.Formatters.FirstOrDefault(f => f is JsonMediaTypeFormatter);
if (jsonFormatter != null)
{
    jsonFormatter.UseDataContractJsonSerializer = true; // use WCF serializer
}

More about serialization for ASP .NET Web API here.

Well, we have manually built an Api Controller for one entity in our model. It will be great to create automatically an Api Controller for each one of our entities.

We can achieve this by making a Template, but this will be your “homeworkSmile.

You can find some information in building templates here or here.

Regards.

Pablo Fernandez Duran

CodeFluent Entities and JSON/REST

November 29, 2012 Leave a comment

In a previous post we announced that CodeFluent Entities natively support JSON/REST.

In this post we’re going to see how to take advantage of the generated JSON/REST architecture. Thanks to JSON WCF services we should be able to call server methods from the client of our choice. To illustrate that we’re going to create a back end application exposing JSON WCF services that will be consumed in a console application. As you’re going to see, all the hard work will be done by CodeFluent Entities.

Creating the solution

Start by creating a new CodeFluent Project. We’ll use the “ContactManager Sample Model” for the purpose of this article.ContactManagerModel

  • Add a new Class Library project named “ContactManager” to your solution. It will be used to host the generated files corresponding to your Business Object model and JSON WCF service’s contracts.
  • Add a new SQL Server Database project named “ContactManager.Persistence” to your solution. It will be used to host your generated SQL scripts.
  • Add a new Empty ASP.NET Website project named “ContactManager.BackEnd” to your solution and add a reference to the ContactManager project and create a “Services” folder. It will be used to host the JSON WCF Services.
  • Add a new Console Application project named “ContactManager.Client” to your solution and add a reference to the ContactManager project and to CodeFluent.Runtime.dll. We will use it to make some calls via JSON WCF to the backEnd application and display the results in the console. Also, by default, Microsoft Visual Studio 2010 sets the target framework to .NET Framework 4 Client Profile. Go to the property of your project and change its target to .NET Framework 4.
    image

Adding the producers

  • Add a Business Object Model Producer and set its Target Directory to the ContactManager project. Also add it a Service Object Model Sub Producer and configure it so JSON been enabled and no proxy been produced. This producer will generate the complete WCF-based communication layer (service, contracts) with native JSON/REST support.
  • Add a SQL Server Producer and set its target directory to the ContactManager.Persistence project.
  • Add a Template Producer and set its Target Directory to the the Services folder of your ContactManager.BackEnd project. Also set its Source Directory to “CodeFluent Entities installation folder > Modeler >Templates > ServiceModel > JsonWebServices > Services”.

Configuring the solution

Configure your solution so it first start your  ContactManager.BackEnd application and then your ContactManager.Client application.

Generating code

Now to start generating code, build your CodeFluent Entities project called ContactManager.Model.

Here is the visual studio solution you should have by now, each project containing the generated code (your database should have been created too):

ScreenShot051

Writing the client

When the WCF Service Object Model Producer is set to generate JSON web services, it automatically adds two extra operations to the Business Object model and Services:
1. JsonGet
2. JsonPost

As the name suggests, you can use those methods to read (JsonGet) or write (JsonPost) by calling any other operation available on the service.

So why not use the other operations directly instead?
Well you can (using HTTP POST method and the header Content-Type set to application/json), but what’s interesting with those JsonGet/Post methods is that they add extra JSON oriented features. One of them being able to wrap .NET exception in a nice and simple JavaScript-friendly object.

Note: JsonGet and JsonPost methods are not fully documented yet but a new version of the documentation is on its way.

Here we want to use the JsonGet method in our console application to call the default generated LoadAll method and write the result on the console:

we can break the task down to the following steps:

  • Set up the URL with all parameters
  • Send a GET WebRequest
  • Receive the Json formatted data
  • Deserialize the object(s)
  • Write the result on the console

Therefore, our console application should look something like this:

using System;
using System.Net;
using System.IO;
using CodeFluent.Runtime.Utilities;
using ContactManager;

namespace ContactManager.ConsolApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Type a key to start");
            Console.ReadKey();

            string url = "http://localhost:62738/Services/ContactManager.Customer.svc/JsonGet?method=LoadAll";
            string jsonContent = GET(url);

            //Let's display the RAW JSON content first:
            Console.WriteLine("JSON Content:");
            Console.WriteLine(jsonContent + Environment.NewLine);

            //Then each Customer:
            Console.WriteLine("From deserialized content:");
            CustomerCollection customers = JsonUtilities.Deserialize<CustomerCollection>(jsonContent);
            foreach (Customer c in customers)
            {
                Console.WriteLine(c.Trace());
            }
        }

    }
}

Notes: the URL should be changed according to your configuration (port number, and service name should be updated);

The GET method simply downloads and returns the internet string response as follow:

// Returns JSON string
private static string GET(string url)
{
    using (WebClient client = new WebClient())
    {
        try
        {
            return client.DownloadString(url);
        }
        catch (WebException ex)
        {
            WebResponse errorResponse = ex.Response;
            using (Stream responseStream = errorResponse.GetResponseStream())
            {
                StreamReader reader = new StreamReader(responseStream, new System.Text.UTF8Encoding());
                String errorText = reader.ReadToEnd();

                Console.WriteLine(errorText);
            }
            throw;
        }
    }
}

But where do we find the JSON Serializer? Well the CodeFluent Runtime (CodeFluent.Runtime.dll) comes with a very convenient class: JsonUtilities.
The JsonUtilities class is a simple yet powerful JSON Serializer allowing you to convert your .NET objects into JSON and vice versa. See that post for more information.

Running the application

Hitting Ctrl+F5 should build and launch your backend application and then your console application. Typing a key should retrieve all the customers using JSON WCF services and display them on the console as follow:

Type a key to start
JSON Content:
[{“EntityKey”:”1″,”EntityDisplayName”:”info@softfluent.com”,”RowVersion”:[0,0,0,0,0,0,7,209],”Id”:1,”EmailAddress”:”info@softfluent.com”,”Password”:null,
“FirstName”:”Thib”,”LastName”:”Nes”,”FullName”:null,”BirthdayDate”:”\/Date(-62135596800000)\/”,”LoyaltyProgramMember”:false,”LicenseNo”:null,”HasPreAccidents”:false,
“Age”:0,”AddressId”:-1,”Rentals”:[],”PaymentType”:0,”EntityState”:1}]

From deserialized content:
[Id=1,EmailAddress=info@softfluent.com,Password=,FirstName=Thib,
LastName=Nes,FullName=,BirthdayDate=1/1/0001 12:00:00 AM,LoyaltyProgramMember=False,LicenseNo=,HasPreAccidents=False,Age=0,
Address=<null>,_addressId=-1,Rentals=[Count=0],PaymentType=Cash, EntityState=Unchanged]
Press any key to continue . . .

 

What about saving data? Well, we would use the JsonPost method instead of JsonGet and use the JsonUtilities.Serialize method to serialize our content. The Main method of our console application would look like this:

static void Main(string[] args)
{
    string url = "http://localhost:62738/Services/ContactManager.Customer.svc/JsonPost?type=EntitySaveCall";
    Customer c = new Customer { FirstName = "John", LastName = "Doe", Age = 42 };
    string jsonContent = JsonUtilities.Serialize(c);
    
    POST(url, jsonContent);
}

And the POST method to send the data:

// POST a JSON string
private static void POST(string url, string jsonContent)
{
    using (WebClient client = new WebClient())
    {
        string response = string.Empty;
        //We need to specify that we are sending Json contents, or our
        //requests will be rejected by the services
        client.Headers.Add("Content-Type: json; charset=UTF-8");
        client.Encoding = System.Text.Encoding.UTF8;
        try
        {
            response = client.UploadString(url, jsonContent);
        }
        catch (WebException ex)
        {
            WebResponse errorResponse = ex.Response;
            using (Stream responseStream = errorResponse.GetResponseStream())
            {
                StreamReader reader = new StreamReader(responseStream, new System.Text.UTF8Encoding());
                String errorText = reader.ReadToEnd();

                Console.WriteLine(errorText);
            }
            throw;
        }
    }
}

This is it! This post highlighted the fact that we can directly consume JSON WCF services generated by CodeFluent Entities from the client of our choice (for instance for Windows Phone, iOS or Android to name but a few). CodeFluent Entities doing all the hard work for us by generating applications based on REST/JSON architecture in a couple of minutes.

Hope this helps!

Cheers,

Thibault NESTOR

Generating a WPF Smart Client using the Smart Client Producer

October 22, 2012 Leave a comment

Hello!

In a previous posts, we showed you the output of the WPF Smart Client Producer. In this post we’ll show you how to generate a WPF smart client. It will be a WPF application consuming WCF services thanks to a proxy and the data will be stored in a database Smile.

Creating the solution

Start by creating a new CodeFluent Project. We’ll use the “ContactManager Sample Model” for the purpose of this article.ContactManagerModel

Add a new Class Library project named “ContactManager” to your solution. It will be used to host the generated files corresponding to your Business Object model and WCF service’s contracts. Add it a folder called “ServicesConfig” that will be used to store your WCF service’s configuration files.

Add a new Class Library project named “ContactManager.Proxy” to your solution. It will be used to host the generated files corresponding to the proxy.

Add a new SQL Server Database project named “ContactManager.Persistence” to your solution. It will be used to host your generated SQL scripts.

Add a new WPF application project named “ContactManager.SmartClient” to your solution. It will be used to host the generated files of your WPF application. Remove the MainWindow.xaml file since we are going to generate our own. Also, by default, Microsoft Visual Studio 2010 sets the target framework to .NET Framework 4 Client Profile. Go to the property of your project and change the target to .NET Framework 4 in order to use the standard libraries.

image

Adding the producers

The Business Object Model Producer

To generate your Business Objects model, add the Business Object Model Producer to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Business Layer Producers node and select it:

image

In the Target Directory field, select your Class Library project called ContactManager.

image

Click OK.

The SQL Server Producer

To generate your persistence scripts, add the SQL Server Producer (or the one that suits your configuration) to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Persistence Layer Producers node and select it:

image

In the Connection String field enter your connection string used to connect to your SQL Server. Also in the Target Directory field, select your SQL Server Database project called ContactManager.Persistence. Finally in the Target Version field, select your SQL Server version.

The Service Object Model Producer

To generate your WCF service and your proxy, add the Service Object Model Producer to your CodeFluent Entities project by clicking “Add new SubProducer” on your  “Business Object Model” producer in Visual Studio’s Solution Explorer, expand the Business Layer Producers node and select it:

image

In the Target Directory field, select your Class Library project called ContactManager.Proxy and click OK.

The Template Producer

Note: The Template producer is not mandatory. However, it is really handy if you want to be able to quickly run and test your WCF service using the CodeFluent Entities Hoster.

Lets now generate the configuration files of your WCF service. Add the Template Producer to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Utility Producers node and select it:

ScreenShot032

In the Source Directory field select the “Server” folder located at “CodeFluent Entities installation folder > Modeler >Templates > ServiceModel”. And in the Target Directory field, select the folder called ServicesConfig located in your Class Library project called ContactManager, then click OK.

The WPF Smart Client Producer

Then, to generate your WPF smart client, add the WPF Smart Client Producer to your CodeFluent Entities project by clicking “Add new producer” on the “Producers” folder in Visual Studio’s Solution Explorer, expand the Application Producers node and select it:

image

In the Target Directory field, select your WPF application project called ContactManager.SmartClient and click OK.

Generating code

Now to start generating code, build your CodeFluent Entities project called ContactManager.Model.

Here is the visual studio solution you should have by now, each project containing the generated code (your database should have been created too):

image

Building and running the application

At this stage, your application has been generated and is almost ready to be built and run. Since your WPF application uses the Proxy you need to add your Class Library project called ContactManager.Proxy as a reference to your WPF application project called ContactManager.SmartClient project.

Now you can build your solution, then run your WCF service as you usually do or thanks to the CodeFluent Entities Hoster using your generated service configuration files. Finally start your WPF application.

Tip: If you use the CodeFluent Entities Hoster, a quick and easy way to ensure the executable is automatically copied to the output directory is to add a reference to it. This is absolutely not required to compile your Business Object model (your Class Library called ContactManager), it’s just a shortcut to have the executable in the output directory without having to create post-build events.

And tadaaa! You’ve created your 100% functional WPF smart client without a single line of code!

SmartClient (1)

SmartClient (2)

Enjoy!

Thibault Nestor

CodeFluent Service Host

October 11, 2012 1 comment

CodeFluent Entities is shipped with a very handy tool called the CodeFluent Service Host.

CodeFluent Service Host is a command line tool that enables you to easily host Windows services as well as Windows Communication Foundation (WCF) services. It takes care of all the plumbing: service registration, start, stop, multi threading, log and so on… It supports CodeFluent Generated services as well as other manually coded services.

Another sweet thing about it is that you can either use it in Console mode as well as in Windows Service mode. As a developer I found the Console mode very convenient since it allows me to quickly test my own services without having to install/uninstall them after each modification. Besides, you can print your traces and exceptions directly on the console! It also embeds a special out-of-the-box WCF exception handler that is capable of displaying WCF server errors without using any other external tool like the Service Trace Viewer.

The CodeFluent.Runtime.ServiceHost.exe can be found in your CodeFluent Entities installation directory. In order to work it needs only the following:

  • The hosted assembly containing the service(s) and its referenced assemblies
  • A standard .NET configuration file indicating the host which service to host.
    Note that if you use the Service Object Model Producer (provided out-of-the-box by CodeFluent Entities) to generate your services, it will automatically create the configuration file needed by CodeFluent Service Host. Thus to start your service in Console mode you’ll just have to run CodeFluent.Runtime.ServiceHost.exe.
    Here is an example of how to use CodeFluent Service Host in Windows Service Mode:

First we need to install the service. Here is the content of the InstallService.bat that will do it for us (This batch file can also be generated by the Service Object Model Producer):

CodeFluent.Runtime.ServiceHost.exe /i /name:MyServiceName 
/displayName:MyServiceDisplayName 
/description:"This service is a WCF services host"

Running the batch file will install your service. Then you’ll be able to manage your service as any other windows services thanks to the Windows Administration Services console:

CodeFluent Service Hoster - Windows Service

More info in the documentation can be found here.

Note in the latest builds, CodeFluent Service Host is available in 4 editions:

  • CodeFluent.ServiceHost.exe 32-bit (CLR2)
  • CodeFluent.ServiceHost4.exe 32-bit (CLR4)
  • CodeFluent.ServiceHost.exe 64-bit (CLR2)
  • CodeFluent.ServiceHost4.exe 64-bit (CLR4)

Of course, if you use a .config file, it will have to follow the .exe name, sor for the CLR4 versions, the config file will have to be named CodeFluent.ServiceHost4.exe.config.

Cheers,

Thibault Nestor

Adding Attributes On Generated WCF Contracts

August 2, 2011 Leave a comment

We saw on previous posts (i.e. The Smart Client Object Model) that CodeFluent Entities fully supports WCF, and by that I don’t mean that the generated classes are just serializable (which they are by the way), but instead I mean that CodeFluent Entities can generate the entire communication layer (services, contracts, proxies and configuration) so you can spend your time somewhere else.

A question that we often get is:

Great it generates all my contracts, but what if I’d like to have some custom attribute on a specific operation in one of my contracts? How can I do that?

To a simple question, a simple answer!

Using CodeFluent Entities it’s possible to add attributes on generated elements via the cf:attribute node. Likewise you can specify attribute parameters using the cf:argument node.

For instance, say I’d like to add the following WebInvoke attribute on a LoadAll method:

[OperationContract]
[WebInvoke(UriTemplate = "LoadAll", Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
CustomerCollection LoadAll();

Here’s how to do it in XML in my model:

<cf:method name=”LoadAll” body=”load”>
<cf:attribute name=”System.ServiceModel.Web.WebInvoke” class=”_serviceModel:serviceInterface”>
<cf:argument name=”UriTemplate” expression=”&quot;{2:Name}&quot;” />
<cf:argument name=”Method” expression=”&quot;Post&quot;” />
<cf:argument name=”BodyStyle” expression=”System.ServiceModel.Web.WebMessageBodyStyle.Wrapped” />
<cf:argument name=”ResponseFormat” expression=”System.ServiceModel.Web.WebMessageFormat.Json” />
</cf:attribute>
</cf:method>

Note 1: _serviceModel:serviceInterface is a filter which indicates the producer to place this attribute on each method of the service interface. Other possible filters are:_serviceModel:service (points to the service class), _serviceModel:serviceInterface (points to the interface), _serviceModel:serviceInterfaceProxy (points to the proxy interface).

Note 2: Escape quotes using ‘&quot;’ to define static strings.

Note 3: The expression attribute of the argument element understands 3 aliases: {0} being the default namespace, {1} being the parent node (attribute), {2} being the parent of the parent (method in this case).

Generate WPF Smart-Clients using CodeFluent Entities (video)

June 29, 2011 4 comments

CodeFluent Entities ships a WPF Smart-Client Producer (beta) which allows developers to generate a WPF application using WCF to communicate with the server.

The following video shows the producer’s output, and the application you see running in it is a 100% generated (database, object model, WCF services, WCF proxy, as well as WPF screens).

WPF Smart-Client Producer

This demo is actually part of the webinar so if you want to know more on what is shown, I invite you to take a look at our last webinar: http://blog.codefluententities.com/2011/06/16/codefluent-entities-webinar-june-15th-2011/

The Smart Client Object Model: Silverlight Support


We introduced the Smart Client Object Model in a previous post and we mentioned the fact that it could be used in both standard .NET apps as well as Silverlight apps. This is true thanks to Silverlight’s CoreCLR.

Starting from Silverlight 2, Silverlight ships a scaled version of the original .NET CLR named the CoreCLR. It basically is a stripped down version of the standard CLR, only containing what is needed to develop rich .NET internet applications. In a nutshell, the CoreCLR contains:

  • Most of the same Base Class Libraries as the ones provided in the standard CLR,
  • JIT,
  • Garbage Collector,
  • Security Model,
  • Exception Handling,
  • Loader & Binder,
  • Debugging APIs

Nevertheless, as you understood, not all .NET classes are available so to ensure that the generated Smart Client Object Model can be used by any Smart-Client including Silverlight ones you’ll need to reference the CodeFluent Silverlight Runtime (corresponding to your Silverlight version)which adds support for missing features required by the object model.

Furthermore, the runtime also adds a key feature which is the Silverlight Automatic Asynchronous Proxy (aka SLAAP). As you may know, the Silverlight programming model requires that all server calls cannot be issued from the UI thread and need to be asynchronous. As a consequence developers need to implement the IAsyncResult interface for all their server calls. Therefore, without using CodeFluent Entities, making a server call in Silverlight looks like something like this:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    MySampleService.CustomerCollectionClient client = new MySampleService.CustomerCollectionClient();
    client.LoadAllCompleted += new EventHandler(client_LoadAllCompleted);
    client.LoadAllAsync();
}

void client_LoadAllCompleted(object sender, MySampleService.LoadAllCompletedEventArgs e)
{
    listBox1.ItemsSource = e.Result;
}

Well using CodeFluent Entities and its generated Smart Client Object Model you don’t have to bother using the IAsyncResult interface anymore with those LoadAllAsync and LoadAllCompleted members, but simply call the LoadAll method as you would have done in a standard .NET application. However, since Silverlight requires that server calls should not be issued on the UI thread you need to run it on a background thread such as this:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    ThreadPool.QueueUserWorkItem(GetCustomers);
}

private void GetCustomers(object state)
{
    CustomerCollection customers = CustomerCollection.LoadAll();
    Dispatcher.BeginInvoke(() => listBox1.ItemsSource = customers);
}

Better, but still this implies that developers have to do the QueueUserWorkItem and BeginInvoke themselves. To remedy this, the runtimes actually include two handy extensions RunAsync and UpdateUI which actually take care of all this. This way loading business data using the Smart Client Object Model in Silverlight gets down to do the following:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    this.RunAsync(() =>
    {
        // 1. business code
        CustomerCollection customers = CustomerCollection.LoadAll();

        this.UpdateUI(() =>
        {
            // 2. UI update code
            listBox1.ItemsSource = customers;
        });
    });
}

To sum-up, key points using the Smart Client Object Model in Silverlight are:

  • It’s the same object model for all smart clients,
  • this is possible mostly thanks to the runtimes which provide the missing features in the targeted CoreCLR (2, 3, 4),
  • furthermore the runtimes provide the Silverlight Automatic Asynchronous Proxy feature so you don’t have to bother with IAsyncResult anymore.
Follow

Get every new post delivered to your Inbox.

Join 51 other followers