AppExchange Service

Getting Started

Contents

Consuming With .Net. 1

Consuming With Java (JAX-WS). 3

Consuming With JavaScript (JSONP). 5

 

Consuming With .Net

In order to consume the AppExchange Service with .Net you must first generate artifacts from WSDL. First create a project in Visual Studio 2010 or 2012. Then, from the Solution Explorer right click on the project root and select Add Service Reference. In the dialog box
enter WSDL URL. In the Namespace input type the name you want (AppExchange, for instance) and Click Go button.

Once your source file has been generated (likely named AppExchange) make sure you have correct web service binding settings in app.config.

<system.serviceModel>

        <bindings>

            <basicHttpBinding >               

                <binding name="AppExchangePortBinding">

                    <security mode="TransportCredentialOnly" >

                        <transport  clientCredentialType="Basic" proxyCredentialType="Basic" realm="RMSWS Authentication" />

                    </security>

                </binding>               

            </basicHttpBinding>

        </bindings>

        <client>           

            <endpoint address="http://rmsws.yieldstar.com:80/rmsws/AppExchange"

                binding="basicHttpBinding" bindingConfiguration="AppExchangePortBinding"

                contract="AppExchange.AppExchange" name="AppExchangePort" />

        </client>

    </system.serviceModel>

 

Now you may call the web service. All examples below are in C# but the methodology can be applied to Visual Basic .Net, J#, etc. First, you need to have credentials.

AppExchangeClient service = new AppExchangeClient();

service.ClientCredentials.UserName.UserName = "myusername";

service.ClientCredentials.UserName.Password = "mypassword";

 

Then, create a request object to specify which property, client, and other information to obtain information for. Here is what the a request for rent summary may look like:

rentSummaryRequest request = new rentSummaryRequest();

request.clientName = "myclientname";

request.externalPropertyId = "mypropertyid";

 

Now simply pass that to the operation and receive the response:

rentSummaryResponse response = service.getRentSummary(request);

Putting it all together, it is very easy to have a console application display the summary:

    class Program

    {

        static void Main(string[] args)

        {

          

            AppExchangeClient service = new AppExchangeClient("AppExchangePort");

 

 

            service.ClientCredentials.UserName.UserName = "myusername";

            service.ClientCredentials.UserName.Password = "mypassword";

 

            rentSummaryRequest rentSummaryRequest = new rentSummaryRequest();

            rentSummaryRequest.clientName = "myclientname";

            rentSummaryRequest.externalPropertyId = "mypropertyid";

 

            rentSummaryResponse rentSumaryResponse = service.getRentSummary(rentSummaryRequest);

            Console.WriteLine("Effective Date: {0}", rentSumaryResponse.effectiveDate);

            Console.WriteLine("------------------------");

            foreach (rentSummaryFloorPlanUnitType fput in rentSumaryResponse.floorPlanUnitType)

            {

                Console.WriteLine("Floor Plan: {0} {1} sqft",

                    fput.floorPlanDescription, fput.avgSqFt);

                Console.WriteLine("Bed/Bath: {0}/{1}", fput.bedRooms,

                    fput.bathRooms);

                Console.WriteLine("Market Rent: {0}-{1}",

                    fput.minMarketRent, fput.maxMarketRent);

                Console.WriteLine("Concession: {0}-{1}",

                    fput.minConcession, fput.maxConcession);

                Console.WriteLine("Final Rent: {0}-{1}",

                    fput.minFinalRent, fput.maxFinalRent);

                Console.WriteLine("------------------------");

            }

 

            Console.ReadLine();                       

        }

    }

 Make sure to catch SoapExceptions in a production environment. All faults thrown by the AppExchange Service extend baseFault. This has a code value (not to be confused with SoapException‘s code) that should be obtained when needing support.

Consuming With Java (JAX-WS)

JAX-WS has become a Java standard. The most commonly used reference implementation of it can be obtained here. Unless you use an IDE which automatically generates artifacts, you must first generate them manually with wsimport like so:

wsimportXnocompile -s <source directory> -p <preferred package> <wsdl url>

More information on wsimport can be found here (and here for the ant task). Now that you have generated the code, you may access the web service. First, you should statically store an instance of the proxy provider:

private static final AppExchange_Service PROVIDER =

        new AppExchange_Service();

Now when ready to use the service, instantiate it and provide your credentials:

AppExchange service = PROVIDER.getAppExchangePort();

((BindingProvider)service).getRequestContext().put(

        BindingProvider.USERNAME_PROPERTY, "myusername");

((BindingProvider)service).getRequestContext().put(

        BindingProvider.PASSWORD_PROPERTY, "mypassword");

For this example, we are obtaining the rent summary. First, build the request with the client name and property ID:

RentSummaryRequest request = new RentSummaryRequest();

request.setClientName("myclientname");

request.setExternalPropertyId("mypropertyid");

Now, call the operation:

RentSummaryResponse response;

try {

    response = service.getRentSummary(request);

} catch (InternalErrorFaultException e) {

    throw new RuntimeException(e);

} catch (OperationFaultException e) {

    throw new RuntimeException(e);

} catch (AuthenticationFaultException e) {

    throw new RuntimeException(e);

}

Putting it all together, it is very easy to output to a console:

public class Main {

 

      // proxy provider

      private static final AppExchange_Service PROVIDER =

            new AppExchange_Service();

 

      public static void main(String[] args) throws IOException {

            // obtain proxy and provide credentials

            AppExchange service = PROVIDER.getAppExchangePort();

            ((BindingProvider) service).getRequestContext().put(

                        BindingProvider.USERNAME_PROPERTY, "myusername");

            ((BindingProvider) service).getRequestContext().put(

                        BindingProvider.PASSWORD_PROPERTY, "mypassword");

 

            // build request

            RentSummaryRequest request = new RentSummaryRequest();

            request.setClientName("myclientname");

            request.setExternalPropertyId("mypropertyid");

 

            // execute operation

            RentSummaryResponse response;

            try {

                  response = service.getRentSummary(request);

            } catch (InternalErrorFaultException e) {

                  throw new RuntimeException(e);

            } catch (OperationFaultException e) {

                  throw new RuntimeException(e);

            } catch (AuthenticationFaultException e) {

                  throw new RuntimeException(e);

            }

 

            // output information

            System.out.println("Effective Date: " +

                        response.getEffectiveDate());

            System.out.println("------------------------");

            for (RentSummaryFloorPlanUnitType fput : response.getFloorPlanUnitType()) {

                  System.out.println("Floor Plan: "

                              + fput.getFloorPlanDescription() + " "

                              + fput.getAvgSqFt() + " sqft");

                  System.out.println("Bed/Bath: " + fput.getBedRooms() +

                              '/' + fput.getBathRooms());

                  System.out.println("Market Rent: " +

                              fput.getMinMarketRent() + '-' +

                              fput.getMaxMarketRent());

                  System.out.println("Concession: " +

                              fput.getMinConcession() + '-' +

                              fput.getMaxConcession());

                  System.out.println("Final Rent: " +

                              fput.getMinFinalRent() + '-' +

                              fput.getMaxFinalRent());

                  System.out.println("------------------------");

            }

            new BufferedReader(new InputStreamReader(System.in)).readLine();

      }

}

Of course, the exception handling above is not acceptable for a production environment. When requesting support on exceptions that are unclear, make sure you obtain the “code” inside the “faultInfo” of the thrown exception.

Consuming With JavaScript (JSONP)

In order to consume with JavaScript, your YieldStar provider needs to provide you with an API token. This token is tied to a set of hosts you will be calling this from. Once you have the token, you can use JSONP to access AppExchange directly from your webpage. JSONP basically is an RPC mechanism in which a dynamic script tag is embedded in the page in order to obtain data from another domain that’s not your own. Web browsers’ AJAX implementations respect the same origin policy which basically means you cannot perform an untrusted AJAX operation outside the domain you are at.

Although all the major JavaScript libraries have some support for JSONP (i.e. jQuery, Dojo, Prototype, YUI, etc), this example will show how to use it natively. You will also need a JSON stringifier to turn your input JavaScript objects to strings. All major JavaScript libraries have this. This example uses the most accepted one at json.org. If you use this one, make sure you minify before using in a production environment.

All parameters and objects are the exact same as they would be in SOAP. All dates are stored in the basic format of ISO-8601 (that is YYYY-MM-DD). Any collections are simple JSON arrays and primitive types are preserved such as integers, decimals, and booleans. In order to call AppExchange in JavaScript, you must first construct a request object. In this example we will be using the getRentSummary operation. So the request object requires a clientName and an externalPropertyId. We can do this like so:

var params = {'clientName' : clientName, 'externalPropertyId' : externalPropertyId};

 

Now that we have the parameters (the request object), we can construct the script tag like so:

 

var script = document.createElement('script');

script.setAttribute('type', 'text/javascript');

script.setAttribute('src',

        'https://APP_EXCHANGE_SERVER/AppExchange?json' +

        '&token=' + escape(apiToken) +

        '&operation=getRentSummary' +

        '&callback=getRentSummaryCallback' +

        '&param=' + escape(JSON.stringify(params)));

 

There are a few things happening here. First, we ask the DOM document to create a script element. Then we set the type to type/javascript just as though we were hand-typing it in a web page. Finally we set the source URL. This URL is the same as it is for SOAP calls except it has an empty json parameter. You also must provide the api token you were given by your YieldStar representative as the token parameter. The escape function encodes the token to a URL friendly format. The operation parameter is the actual AppExchange operation you want to call. In this case we are calling getRentSummary. The callback parameter is the name of the JavaScript function to callback to with the response. The param parameter is the request object for the operation. Since this is a JavaScript object, we must convert it to a string. This is what JSON.stringify does. Even once it’s converted to a string, it must be encoded to be placed in a URL. This is what escape does. Now that the script element is built, it must be attached to the document like so:

 

document.body.appendChild(script);

Performing the element addition above will automatically execute the script and call the callback. In order to obtain the response, we must have a callback. This is simply a function like so:

 

function getRentSummaryCallback(rentSummary) {

 

The variable will be populated with the output of the rent summary operation. If the callback parameter was not populated, an alert dialog box will be presented to the browser user saying so. For any other errors, the response object will contain a boolean property error set to true. The error will also have a type and a message. Therefore, you can check for an error at the top of your callback like so:

 

if (rentSummary.error) {

    alert('Error: type: "' + rentSummary.type + '" message: "' + rentSummary.message + '"');

}

 

In most situations you would do something else on error besides an alert box. Here are the error types:

·         param – Invalid JSON in the param request object in the URL

·         authentication – Invalid token, calling host, or privileges to call the specified operation

·         operation – Validation failure on request object

·         internal – All other errors such as internal errors and unknown operations

 

If the response does not have an error, it is safe to assume it has a proper response. You may then iterate the response as you see fit. Putting all of the above together, we can have a button on a webpage that retrieves the rent summary for a property and displays it in a table.

 

<html>

    <head>

        <title>JavaScript Sample</title>

        <script type="text/javascript" src="json2.js"></script>

        <script type="text/javascript">

            function getRentSummary(apiToken, clientName, externalPropertyId) {

                var params = {'clientName' : clientName,

                        'externalPropertyId' : externalPropertyId};

                var script = document.createElement('script');

                script.setAttribute('src',

                        'https://APP_EXCHANGE_SERVER/AppExchange?json' +

                        '&token=' + escape(apiToken) +

                        '&operation=getRentSummary' +

                        '&callback=getRentSummaryCallback' +

                        '&param=' + escape(JSON.stringify(params)));

                script.setAttribute('type', 'text/javascript');

                document.body.appendChild(script);

            }

 

            function getRentSummaryCallback(rentSummary) {

                if (rentSummary.error) {

                    alert('Error: type: "' + rentSummary.type +

                            '" message: "' + rentSummary.message + '"');

                } else {

                    var table = document.getElementById('tblResponse');

                    for (i in rentSummary.floorPlanUnitType) {

                        var fput = rentSummary.floorPlanUnitType[i];

                        var row = table.insertRow(-1);

                        row.insertCell(0).innerHTML = fput.floorPlanDescription +

                            ' ' + fput.avgSqFt + ' sqft';

                        row.insertCell(1).innerHTML = fput.bedRooms +

                            '/' + fput.bathRooms;

                        row.insertCell(2).innerHTML = fput.minMarketRent +

                            '-' + fput.maxMarketRent;

                        row.insertCell(3).innerHTML = fput.minConcession +

                            '-' + fput.maxConcession;

                        row.insertCell(4).innerHTML = fput.minFinalRent +

                            '-' + fput.maxFinalRent;

                    }

                    table.style.display = '';

                    document.getElementById('btnGetRentSummary').disabled = true;

                }

            }

        </script>

    </head>

    <body>

        <button id="btnGetRentSummary" type="button"

                onclick="getRentSummary('myapitoken', 'myclientname', 'mypropertyid');">

            Get RentSummary

        </button>

        <table id="tblResponse" style="display: none" border="1">

            <tr>

                <th>Floor Plan</th>

                <th>Bed/Bath</th>

                <th>Market Rent</th>

                <th>Concession</th>

                <th>Final Rent</th>

            </tr>

        </table>

    </body>

</html>