CloudCasts Blog

Webcasts in the Cloud
posts - 131 , comments - 71 , trackbacks - 120

My Links

News

Tag Cloud

Article Categories

Archives

Post Categories

Image Galleries

Bloggers Guides

Tutorial: Create Custom External Services in Azure AppFabric June CTP

Introduction
One of the first things I wanted to do after installing the Azure AppFabric June CTP was to create an AppFabric application that used the Bing Map SOAP services. That was when I hit my first roadblock. There is currently no option in the AppFabric Application Designer to add a reference to an external service. After asking around in the forums I learned that I should build an external service to do this. There is currently very little documentation on creating external services for Azure AppFabric, so after a couple of days experimenting I managed to get a basic external service working. As this is something that many AppFabric developers will want to do I thought I’d share what I learned in the form of a tutorial.
In this tutorial I will run through the creation of an AppFabric external service that will provide a proxy for the Bing Maps Geocode service. I have kept the implementation as simple as possible, there is a lot more you can do with external services, such as providing a configuration setting for the Bing Maps key, and customizing monitoring, but I will save this for future webcasts and tutorials. Also, bear in mind that as we are on the first CTP of these tools, things can, and will change. One of my loudest shouts to the AppFabric development team is to make it easier to consume services outside the AppFabric application, so hopefully we will see some development there.
Hopefully this tutorial will act as a starting point for creating your own external services that can be consumed by AppFabric applications. If you have any questions or comments, feel free to ping me using the comments section on my blog.
Consuming External Services
At present consuming a service outside the AppFabric application can be done in one of two ways. The quick-and-dirty way is to use the traditional “Add Service Reference” option. The proper way is to create a custom external service.
Traditional “Add Service Reference”
Whilst it is possible to use the traditional “Add Service Reference” method to consume an external service, there are a number of drawbacks to this. When consumed from an ASP.NET service the web.config is read by the application, and configuration can be used for the client endpoints, however when consumed from a stateless WCF service, configuration is not read and therefore client endpoint settings must be hardcoded. Either way the application must be re-deployed if anything changes.
Another drawback is that the external service is not recognized by the AppFabric application model, and therefore will not appear on the application diagram. There will also be no monitoring on the calls made to the external service.
Create a Custom External Service
Creating a custom external service will allow the external service to be recognized by the AppFabric application model. This means it can be used in the composition of an application, and will use the AppFabric service reference infrastructure. The external service can provide monitoring data to show usage of the service and also expose configuration settings that can be set at development time and reconfigured when the application has been deployed.
This tutorial will focus on the creation of a custom external service.
Pre-Requisites
If you are going to run through the tutorial as I have written it, you will need to install the relevant Visual Studio components and register for the relevant services. You can follow the steps using a different service if you don’t want to use the Bing Maps services.
Install Windows Azure AppFabric June CTP Developer Tools
I recommend installing the June CTP tools on a separate virtual environment to avoid possible compatibility issues with past and future releases.
You can find it here.
Install Visual Studio 2010 SDK
The Visual Studio SDK is required for creating the Visual Studio package that will contain the external service.
The Visual Studio SDK is here.
The Visual Studio Service Pack 1 SDK is here.
Create a Bing Maps Developer Account
If you want to test against the Bing Maps SOAP services you will need a developer account. It’s free to apply for, and you will receive a key to call the Bing Maps Geocode service. If you don’t want to do this you can pick another external service to consume and adjust the tutorial accordingly.
There are details on registering for an account here:
Create an AppFabric Labs Account (Optional)
If you want to test your application “In the Cloud”, and see the configuration options you will need an AppFabric account.
You can register for an account here.
Create a Bing Maps External Service
The Bing Maps Geocode service provides search functionality that takes address details as search parameters and returns a list of addresses and coordinates as a result. An external service will be created that allows the Bing Maps Geocode service to be called from an AppFabric application using the AppFabric application model. The service will be represented on the application diagram and the service endpoint will be configurable in the development and hosting environments.
Create a new MEF Component
An MEF Component will be created to contain the external service. This can then be installed in Visual Studio for the service to appear in the AppFabric designer. It is possible to do more advanced things with the Visual Studio extension, but in the interests of the tutorial I’ll keep it as simple as possible.
·         In Visual Studio, Create a new project, and select Visual Studio Package in the Visual C# / Extensibility section, name it BingMapsExternalService. (If you don’t see the Extensibility option, install the Visual Studio 2010 SDK.)

 
·         In the Select a Programming Language page, select Visual C# and Generate a new key file

 
·         Keep the default options for the next two pages.

 
·         In the Select Test Project options, clear both check boxes.
Visual Studio will create the project, and open the vsixmanifest file.
·         In the Content section of the vsixmanifest file, remove the VS Package content.

 
·         Add Content for an MEF Component and select the project name as the source.

 
·         Save and close the vsixmanifest file.
 
Add Required References
The extension project will need to hook in to the internals of the AppFabric application model, as well as serialize the metadata for the external service properties.
·         Add references to the following assemblies:
o   Microsoft.ApplicationServer.ApplicationModel
o   Microsoft.VisualStudio.ApplicationServer
o   System.ComponentModel.Composition
o   System.Fabric
o   System.Runtime.Serialization
Add the Bing Maps Service Reference
The external service will return a client proxy for the Bing Maps Geocode service. Adding a service reference to the project will create the classes for this client proxy and the data contracts for the request and response.
·         Use the Add Service Reference dialog box to add a reference to the Bin Maps Geocode Service setting the namespace to GeocodeServiceReference.
o   http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc
Note: The client configuration that is added to the app.config file will not be used in the external service.

Add Required Classes
The external service requires three classes to be implemented. Each of these will derive from a class in the AppFabric application model and provide overrides of methods and properties.
·         Add a folder named BingMaps to the project.

 
·         Add classes with the following names to the folder:
o   GeocodeServiceExport
o   GeocodeServiceExportDefinition
o   GeocodeServiceMetadata
 
Implement the Service Export Definition Class
The service export definition class provides details of the type of the service that is exported, and any configuration settings that can be set for the service. Data contract serialization is used for the configuration settings.
·         Make the GeocodeServiceExportDefinition class public and derive it from ServiceExportDefinition, adding a using for the Microsoft.ApplicationServer.ApplicationModel.Definitions namespace. (Use [Ctrl] + [.] to do this.)

 
·         Use [Ctrl] + [.] to provide the implementation of the ExportType property.

 
·         Implement the Export Type property as follows:

protected override Type ExportType
{
    get
    {
        return typeof(GeocodeServiceExport);
    }
}
 
·         Add a public property for the Uri of the service, also adding a using for the System.Runtime.Serialization namespace.

[DataMember]
[RequiredProperty]
public string Uri { get; set; }
 
Note: This property will appear in the properties pane for the external service in the AppFabric Designer. It will also allow for configuration of the service Uri in the AppFabric hosting environment.
 
·         Add a constructor to set the Uri to a default value:

public GeocodeServiceExportDefinition()
{
    Uri = "http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc";
}
 
·         Build the project and fix any errors.

 
·         The complete class should look like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ApplicationServer.ApplicationModel.Definitions;
using System.Runtime.Serialization;
 
namespace Company.BingMapsExternalService.BingMaps
{
    public class GeocodeServiceExportDefinition : ServiceExportDefinition
    {
        [DataMember]
        [RequiredProperty]
        public string Uri { get; set; }
 
        public GeocodeServiceExportDefinition()
        {
            Uri = "http://dev.virtualearth.net/webservices/v1/geocodeservice/geocodeservice.svc";
        }
 
        protected override Type ExportType
        {
            get
            {
                return typeof(GeocodeServiceExport);
            }
        }
    }
}
 
Implement the Service Export Class
The service export class will create a new client proxy for the Bing Maps Geocode service using the URI specified in the service export definition, and return it to the code in the application that calls the service. As no configuration is used for the client proxy, it must be created using code.
·         Make the GeocodeServiceExport class public and derive it from ServiceExport, adding a using for the Microsoft.ApplicationServer.ApplicationModel namespace.

 
·         Use [Ctrl] + [.] to provide the implementation of the Resolve method.

 
·         Implement the Resolve method as follows, adding usings for System.ServiceModel and Company.BingMapsExternalService.GeocodeServiceReference.

protected override object Resolve(ExportResolutionContext context)
{
    GeocodeServiceExportDefinition definition =
        (GeocodeServiceExportDefinition)GetDefinition();
 
    BasicHttpBinding binding = new BasicHttpBinding();
    EndpointAddress address = new EndpointAddress(definition.Uri);
    GeocodeServiceClient client = new GeocodeServiceClient(binding, address);
 
    return client;
}
 
·         Build the project and fix any errors.

 
·         The complete class should look like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.ApplicationServer.ApplicationModel;
using System.Diagnostics;
using System.ServiceModel;
using Company.BingMapsExternalService.GeocodeServiceReference;
 
namespace Company.BingMapsExternalService.BingMaps
{
    public class GeocodeServiceExport : ServiceExport
    {
        protected override object Resolve(ExportResolutionContext context)
        {
            GeocodeServiceExportDefinition definition =
                (GeocodeServiceExportDefinition)GetDefinition();
 
            BasicHttpBinding binding = new BasicHttpBinding();
            EndpointAddress address = new EndpointAddress(definition.Uri);
            GeocodeServiceClient client = new GeocodeServiceClient(binding, address);
 
            return client;
        }
    }
}
 
Implement the Service Metadata Class
The service metadata class provides details about the service to the AppFabric Application Designer. This includes the name and description of the service and also the list of assemblies that contain the external service.
·         Derive the GeocodeServiceMetadata class from ExternalServiceMetadata, adding a using for the Microsoft.VisualStudio.ApplicationServer.ExternalServicesMetadata namespace.

 
·         Use [Ctrl] + [.] to provide the implementation of the FriendlyName property.

 
·         Add the ExternalServiceExport attribute to the class as follows:

[ExternalServiceExport(typeof(GeocodeServiceExportDefinition))]
class GeocodeServiceMetadata : ExternalServiceMetadata
{
    public override string FriendlyName
    {
        get { throw new NotImplementedException(); }
    }
}
 
·         Implement the FriendlyName property as follows:

public override string FriendlyName
{
    get
    {
        return "Bing Maps Geocode Service";
    }
}
 
·         Override the Description property and implement it as follows:

public override string Description
{
   get
    {
        return "This will call the Bing Maps Geocode Service.";
    }
}
 
·         Override the ProxyTypeName property and implement it as follows, adding a using for Company.BingMapsExternalService.GeocodeServiceReference.

public override string ProxyTypeName
{
    get
    {
        return typeof(GeocodeServiceClient).AssemblyQualifiedName;
    }
}
 
·         Add member variables for lists of proxy and reference artifacts:

[ExternalServiceExport(typeof(GeocodeServiceExportDefinition))]
class GeocodeServiceMetadata : ExternalServiceMetadata
{
    List<string> m_ProxyArtifacts = new List<string>();
    List<string> m_ReferenceAssemblies = new List<string>();
 
 
·         Override the ProxyArtifacts property as follows:

public override List<string> ProxyArtifacts
{
    get
    {
        if (m_ProxyArtifacts.Count == 0)
        {
            m_ProxyArtifacts.Add(typeof(GeocodeServiceExportDefinition).Assembly.Location);
        }
 
        return m_ProxyArtifacts;
    }
}
 
·         Override the ReferenceAssemblies property as follows:

public override List<string> ReferenceAssemblies
{
    get
    {
        if (m_ReferenceAssemblies.Count == 0)
        {
            m_ReferenceAssemblies.Add(typeof(GeocodeServiceExportDefinition).Assembly.Location);
        }
 
        return m_ReferenceAssemblies;
    }
}
 
·         Build the project and fix any errors.

 
·         The complete class should look like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.ApplicationServer.ExternalServicesMetadata;
using Company.BingMapsExternalService.GeocodeServiceReference;
 
namespace Company.BingMapsExternalService.BingMaps
{
    [ExternalServiceExport(typeof(GeocodeServiceExportDefinition))]
    class GeocodeServiceMetadata : ExternalServiceMetadata
    {
        List<string> m_ProxyArtifacts = new List<string>();
        List<string> m_ReferenceAssemblies = new List<string>();
 
        public override string FriendlyName
        {
            get
            {
                return "Bing Maps Geocode Service";
            }
        }
 
        public override string Description
        {
            get
            {
                return "This will call the Bing Maps Geocode Service.";
            }
        }
 
        public override string ProxyTypeName
        {
            get
            {
                return typeof(GeocodeServiceClient).AssemblyQualifiedName;
            }
        }
 
        public override List<string> ProxyArtifacts
        {
            get
            {
                if (m_ProxyArtifacts.Count == 0)
                {
                    m_ProxyArtifacts.Add(typeof(GeocodeServiceExportDefinition).Assembly.Location);
                }
 
                return m_ProxyArtifacts;
            }
        }
 
        public override List<string> ReferenceAssemblies
        {
            get
            {
                if (m_ReferenceAssemblies.Count == 0)
                {
                    m_ReferenceAssemblies.Add(typeof(GeocodeServiceExportDefinition).Assembly.Location);
                }
 
                return m_ReferenceAssemblies;
            }
        }
    }
}
 
Testing a Bing Maps External Service
To test the external service a simple AppFabric application will be created with an ASP.NET service that makes a call to the Bing Maps Geocode service to search for a location. The results from the search will be displayed on the web page.
Install the Visual Studio Package
Before the external service can be used in the AppFabric designer it must be installed in Visual Studio.
·         Build the BingMapsExternalService project.

 
·         Navigate to the output folder for the extension project.
o   ..\BingMapsExternalService\BingMapsExternalService\bin\Debug

·         Double-click BingMapsExternalService.vsix and follow the instructions to install the MEF Component.

 
·         Close all instances of Visual Studio.
Create an AppFabric Application
A new application can now be created to test the external service.
·         Start Visual Studio and create a new AppFabric Application, named BingMapsExternalServiceTest.
·         Select Tools à Extension manager and notice that the BingMapsExternalService extension appears in the list of installed extensions.
Note: You can uninstall the extension with this dialog box.

·         Add an ASP.NET service named TestWeb.

 
·         Add a Bing Maps Geocode Service service named GeocodeTest.
Note: The external service name and description is listed in the New Service dialog box.

·         In the Service References section of TestWeb, add a service reference to the GeocodeTest service, and change the name the reference from Import1 to GeocodeTestImport.
Note: The Uri property of the external service is configurable in theGeocodeTest properties window.

·         Right-click App.cs and select View Diagram.
Note: The Geocode external service appears on the application diagram with a default icon.

 
·         Open ServiceReferences.g.cs.
Note: This class provides two static methods to return client proxies for the Bing Maps Geocode service.
Add Code to Call the External Service
·         Implement the BodyContent section of Default.aspx as follows:
Note: You can copy-paste the code to save time.
 

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
    CodeBehind="Default.aspx.cs" Inherits="GeocodeWeb._Default" %>
 
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>
        Welcome to Custom AppFabric Services!
    </h2>
    <table>
        <tr>
            <td>Street</td>
            <td><asp:TextBox ID="txtStreet" runat="server" /></td>
        </tr>
        <tr>
            <td>Town</td>
            <td><asp:TextBox ID="txtTown" runat="server" /></td>
        </tr>
        <tr>
            <td>Country</td>
            <td><asp:TextBox ID="txtCountry" runat="server" /></td>
        </tr>
        <tr>
            <td></td>
            <td><asp:Button ID="btnGeocode" Text="Geocode Me!" OnClick="btnGeocode_Click" runat="server" /></td>
        </tr>
    </table>
    <asp:Repeater ID="rptLocations" runat="server">
        <HeaderTemplate>
            <table>
                <tr>
                    <td><b>Address</b></td>
                    <td><b>Confidence</b></td>
                    <td><b>Coordinates</b></td>
                </tr>
        </HeaderTemplate>
        <ItemTemplate>
                <tr>
                    <td><%# DataBinder.Eval(Container.DataItem, "DisplayName")%></td>
                    <td><%# DataBinder.Eval(Container.DataItem, "Confidence")%></td>
                    <td><%# DataBinder.Eval(Container.DataItem, "Locations[0].Latitude")%>, <%# DataBinder.Eval(Container.DataItem, "Locations[0].Longitude")%></td>
                </tr>
        </ItemTemplate>
        <FooterTemplate>
            </table>
        </FooterTemplate>
    </asp:Repeater>
</asp:Content>
 
 
·         In Default.aspx.cs add a button click event for btnGeocode and implement it as follows, using your own Bing Maps key:
Note: You will need to add the relevant using declarations.

protected void btnGeocode_Click(object sender, EventArgs e)
{
    GeocodeServiceClient geoClient = ServiceReferences.CreateGeocodeTestImport();
 
    GeocodeRequest geoReq = new GeocodeRequest()
    {
        Credentials = new Credentials()
        {
            ApplicationId = "{Your Bing Maps Key}"
        },
        Address = new Address()
        {
            AddressLine = txtStreet.Text,
            Locality = txtTown.Text,
            CountryRegion = txtCountry.Text
        }
    };
 
    GeocodeResponse geoResp = geoClient.Geocode(geoReq);
 
    rptLocations.DataSource = geoResp.Results;
    rptLocations.DataBind();
}
 

Note: The ServiceReferences class can now be used to return the client proxy for the Bing Maps Geocode service.

·         Build the solution, there will be errors…

 
·         In the TestWeb project, add references to System.ServiceModel and System.Runtime.Serialization.

 
·         Build the solution, fix any remaining errors.
 
Test the Application in the AppFabric Emulator
The application can now be tested in the AppFabric Emulator.
·         Start the application without debugging.

 
·         When the web page appears, enter an address and click “Geocode Me!”

 
·         You can test the search by copy-pasting the coordinates into the search box for the Bing Maps website:
Test the Application in the AppFabric Hosting Environment
If you have an account for the AppFabric Labs portal you can test the application in the hosting environment. I’m assuming you know how to publish an application.
·         Publish, deploy and start the application in the AppFabric hosting environment.

 
·         Navigate to the GeocodeTest service and note the configuration for the service URI is available.
·         Test the application by navigating to the TestWeb endpoint.
Summary
Creating a custom external service for the AppFabric Application Designer requires a bit of work, but provides an implementation that follows the development model for AppFabric applications. The Bing Maps Geocode example used in this tutorial is one of the most basic implementations of an external service, the implementation could be improved to provide a configuration for the Bing Maps key, provide a custom icon, implement other Bing Maps services, and provide custom monitoring.
The CustomServices tutorial in the AppFabric samples provides some other examples of custom external services. The ReadMe document provides some explanation on creating custom external services.
If you have any questions or comments, feel free to ping me using the comments section on my blog.

Print | posted on Monday, July 18, 2011 8:25 AM | Filed Under [ Azure WCF/WF VS2010 AppFabic ]

Feedback

Gravatar

# re: Tutorial: Create Custom External Services in Azure AppFabric June CTP

Great post Alan, I also ran into the same need over the weekend. The creation of such external services warrants a wizard at the very least, hopefully they consider one for the future.

Have you tried adding the custom service reference to a windows workflow service? Don’t think it’d add the reference activity like it does for WCF services… Or does it?
7/18/2011 4:42 PM | Thiago Almeida
Gravatar

# re: Tutorial: Create Custom External Services in Azure AppFabric June CTP

>>The creation of such external services warrants a wizard at the very least, hopefully they consider one for the future.

That was my first bit of feedback to the team. Hopefuly there will be an easy option to consume external services in the future.

>>Have you tried adding the custom service reference to a windows workflow service? Don’t think it’d add the reference activity like it does for WCF services… Or does it?

No it does not. Its the same thing when you add a reference to a Service Bus Queue, or Azure Storage artifact. If you want to call these services from a workflow you can create your own ServiceReferences class with the static metods to get the proxy, and then create a code activity to call the service. Again, I hope the functionality to create activities is improved going forward.

Regards,

Alan
7/18/2011 8:31 PM | Alan Smith
Post A Comment
Title:
Name:
Email:
Comment:
Verification:
 
 

Powered by: