Setting up WCF Services

From Halo: Reach API Wiki
Jump to: navigation, search

Bungie.net has exposed two service endpoints to consume their game data. One is based on SOAP and the other upon JSON. Both of these endpoints can be consumed by Windows Communication Foundation (WCF) available in the .NET Framework. This page will demonstrate how to use the service endpoints within Visual Studio using WCF.

Contents

[edit] Development Environment

The demonstration here will be based on Visual Studio 2010 and the .NET Framework 4. I believe the minimum requirements for this effort are Visual Studio 2008 and the .NET Framework 3.0 for SOAP, and the .NET Framework 3.5 for JSON.

This example will be based on the "ASP.NET Empty Web Application" project. It should be emphasized that a service reference can be added to many project types from Silverlight, Windows Phone, and Class Libraries, the Web Application type is convienent for this demonstration.

Empty Web Application Project in Visual Studio 2010


[edit] The SOAP Service Endpoint

The URL for the SOAP endpoint is http://www.bungie.net/api/reach/reachapisoap.svc. Visual Studio will create the necessary classes to use this endpoint for the developer through the "Add Service Reference" feature. This can be done by right-clicking on the project title, and choosing "Add Service Reference" from the options.

"Add Service Reference" Option for a Project

The "Add Service Reference" dialog will appear where you can configure how the service reference will be generated. Add the SOAP endpoint address to the "Address" text box and click on the "Go" button. This will inform Visual Studio to make a request to the .svc file and read its WSDL file. The WSDL file is used by Visual Studio to understand the signature of the service, which includes any classes necessary to call an endpoint or returned by that endpoint. You can see the methods defined by the endpoint by expanding the service and clicking on the class that will be created. The operations will populate the collection on the right.

"Add Service Reference" Dialog

The last decision you'll have to make about the reference is the namespace that you would like the reference to assume. Whatever is entered into the "Namespace" text box at the bottom of the dialog will be appended to the default namespace that is defined for the project. In this example, the default namespace is "ReachApiDemo". So if I enter "Soap" as my namespace, the generated class will have "ReachApiDemo.Soap" as the namespace.

Click "Ok" to generate the classes and WCF configuration information used to access the endpoint. Visual Studio at this point will create a class to support the access to the endpoint and hides it within an artifact within the "Service Reference" project folder. This abstracts the raw implementation of the service, but you can still access the code by viewing the Service Referece within the object browser and clicking on the class you would like to review.

Added Service Reference

[edit] WCF Configuration

Bungie.net has provided the configuration values to use the WCF based services. You can view the sample configuration file from B.net at http://www.bungie.net/fanclub/statsapi/Group/Resources/Article.aspx?cid=545261.

Here is their example modified for the SOAP example:

  1. <?xml version="1.0"?>
  2. <configuration>
  3.   <system.web>
  4.     <compilation debug="true" targetFramework="4.0" />
  5.   </system.web>
  6.   <system.serviceModel>
  7.     <behaviors>
  8.       <endpointBehaviors>
  9.         <behavior name="basicHttp">
  10.           <dataContractSerializer maxItemsInObjectGraph="6553600" />
  11.         </behavior>
  12.       </endpointBehaviors>
  13.     </behaviors>
  14.     <bindings>
  15.       <basicHttpBinding>
  16.         <binding name="basicBinding" closeTimeout="00:00:30" openTimeout="00:00:30"
  17.         receiveTimeout="00:00:30" sendTimeout="00:00:30" maxBufferSize="1500000000"
  18.         maxBufferPoolSize="1500000000" maxReceivedMessageSize="2048000000"
  19.         transferMode="Streamed">
  20.           <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
  21.           maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
  22.         </binding>
  23.       </basicHttpBinding>
  24.     </bindings>
  25.     <client>
  26.       <endpoint address="http://www.bungie.net/api/reach/reachapisoap.svc"
  27.       behaviorConfiguration="basicHttp" binding="basicHttpBinding"
  28.       bindingConfiguration="basicBinding" contract="Soap.ReachApiSoap"
  29.       name="ReachApiSoap" kind="" endpointConfiguration="">
  30.       </endpoint>
  31.     </client>
  32.     <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
  33.   </system.serviceModel>
  34. </configuration>


[edit] The JSON Service Endpoint

The URL for the JSON endpoint is http://www.bungie.net/api/reach/reachapijson.svc. The steps to use the JSON service is the same for the SOAP endpoint so follow the same directions, but substitute the URL for the JSON endpoint for the SOAP endpoint.

[edit] Adjusting the WCF JSON Implementation

Unlike SOAP, JSON does not define the uri for the operation within the WSDL. This needs to be added after the fact when you added the JSON service reference. Specifically, you need to modify the OperationContracts to inform WCF how to communicate with the JSON REST-ful services.

A new attribute, "WebInvokeAttribute", has to be added to each method in the Reach API JSON client class. This attribute will inform WCF that it is working with a REST-ful service. You have to provide the BodyStyle, Method, RequestFormat, ResponseFormat, and UriTemplate attributes in the constructor. For example, on the GetGameMetadata operation,

  1. [WebInvokeAttribute(BodyStyle = WebMessageBodyStyle.WrappedRequest,
  2.  Method = "GET",
  3.  RequestFormat = WebMessageFormat.Json,
  4.  ResponseFormat = WebMessageFormat.Json,
  5.  UriTemplate = "game/metadata/{identifier}")]

So what's going on here...

It seems that the Request has multiple elements at the root, which is an error as there can only be one root element. The solution is to wrap the collection of request elements, hence the "WrappedRequest".

The RequestFormat and ResponseFormat remind WCF that we're working with JSON.

The UriTemplate is how we manipulate the URL to match the one provided by B.net. The default WCF behavior is to use querystrings which will not work as Bungie.net uses slashes. You can find the endpoints on B.net at http://www.bungie.net/fanclub/statsapi/Group/Resources/Article.aspx?cid=545064.

FYI, Every time you update your service reference, you'll have to redo this procedure.


[edit] Using the Services

Consuming the data from the services is very straight forward. For this example, I'll use a webpage to call out to the service, return the meta data used for games, and present the Weapons of Halo Reach.

[edit] ASP.NET Page and Code Behind

I've highlighted the important lines of code that are used to consume the service.

  1. <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Soap.aspx.cs" Inherits="ReachApiDemo._Soap" %>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  3. <html xmlns="http://www.w3.org/1999/xhtml">
  4.     <head runat="server">
  5.         <title></title>
  6.     </head>
  7.     <body>
  8.         <form id="form1" runat="server">
  9.             <div>
  10.                 <asp:DataList runat="server" ID="ctlDataList">
  11.                     <HeaderTemplate>
  12.                         <tr>
  13.                             <th>Key</th>
  14.                             <th>ID</th>
  15.                             <th>Name</th>
  16.                             <th>Description</th>
  17.                         </tr>
  18.                     </HeaderTemplate>
  19.                     <ItemTemplate>
  20.                         <tr>
  21.                             <td><%# Eval("Key") %></td>
  22.                             <td><%# Eval("Value.ID") %></td>
  23.                             <td><%# Eval("Value.Name") %></td>
  24.                             <td><%# Eval("Value.Description") %></td>
  25.                         </tr>
  26.                     </ItemTemplate>
  27.                 </asp:DataList>
  28.             </div>
  29.         </form>
  30.     </body>
  31. </html>


  1. using System;
  2. using ReachApiDemo.Soap;
  3.  
  4. namespace ReachApiDemo
  5. {
  6.     public partial class _Soap : System.Web.UI.Page
  7.     {
  8.         protected void Page_Load(object sender, EventArgs e)
  9.         {
  10.             ReachApiSoapClient client = new ReachApiSoapClient();
  11.  
  12.             MetaDataResponse metaData = client.GetGameMetadata(ApiKey.value);
  13.  
  14.             if (metaData.status == 0)
  15.             {
  16.                 if (metaData.Data != null)
  17.                 {
  18.                     ctlDataList.DataSource = metaData.Data.AllWeaponsById;
  19.                     ctlDataList.DataBind();
  20.                 }
  21.             }
  22.         }
  23.     }
  24. }
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox