Create a C-Sharp Callback Listener in Visual Studio

Overview

For Wireless Network Services API service requests that require significant processing time, such as provisioning service for a device or changing a service plan, the ThingSpace Platform replies first with a synchronous response that acknowledges the request and allows your application to continue processing. Later, the platform sends an asynchronous callback message, reporting the results of the request.

The synchronous response contains a unique Request ID. The callback message contains the same Request ID so that you can associate the callback contents with the original API request.

ThingSpace Platform callback services provide your application with real-time updates about service changes. They also create less load on your systems because your application does not have to poll for updates, which means better performance.

To receive callback messages, you must create and deploy one or more web services that can validate and process SOAP messages that conform to the M2M CallbackData schema. You must register the URLs of your web services with the ThingSpace Platform so that it knows where to send the callback messages.

Routing, Firewall, and Security Considerations

Your company must host your callback listening web services at an IP address or URL that can be reached by the ThingSpace Platform callback servers. (This means that you probably cannot use your own computer to test callbacks, unless you have an externally visible IP address that leads to your computer.)

For security reasons, your IT department will probably put the hosting servers behind your company firewall. The firewall must be configured to allow HTTP requests from the Verizon M2M servers to reach the servers hosting your listening service. Contact your Verizon Wireless business sales representative or sales engineer for the IP addresses used by the Verizon M2M callback services.

Requests from the M2M callback services will use TLS 1.1 or 1.2 protocols to secure the messages. Other protocols are not supported.

Create a Simple Callback Listener Service

This tutorial walks you through the steps to create a simple callback listening service that validates incoming requests and returns a callback response that contains the request ID. The end result is very similar to the CallbackService.ReferenceImplementation project that is included in the Wireless Network Services SDK.

Convert the WSDL and XSD to C# Classes

Use the command-line tools in Visual Studio to convert the callback WSDL and XSD to C# classes.

  1. Go to the Start menu and navigate to Microsoft Visual Studio > Visual Studio Tools > Developer Command Prompt. (Some versions of Visual Studio have "Visual Studio Command Prompt.")
  2. Change directory to the "callback wsdls" folder in the Wireless Network Services SDK.
  3. Type this command to convert the CallbackService_WNS_Gen2.wsdl file to ICallbackService.cs file that defines the CallbackService interface and classes. Be sure to set the last parameter to the namespace that you want to use.

    > wsdl.exe CallbackService_WNS_Gen2.wsdl /o:ICallbackService.cs /serverInterface /namespace:com.yourcompany.m2mlistener

  4. Type this command to convert the CallbackData_WNS_Gen2.xsd file to CallbackData_WNS_Gen2.cs file that defines callback data objects. Set the last parameter to the namespace that you want to use. Do not use the same namespace that you used for the WSDL file.

    > xsd.exe CallbackData_WNS_Gen2.xsd /classes /n:com.yourcompany.m2mlistener.data

Create a Project and Add the Interface and Classes

You can create your listening service as a project in a new solution or add it as a new project in an existing solution.

  1. In Visual Studio, go to File > New > Project.
  2. Select Web under Visual C#. Change the .NET Framework selector to ".NET Framework 3.5." Select "ASP.NET Web Service Application."
  3. Type a name for your project and click OK.
  4. Right-click your project and select Add > Existing Item. Navigate to the ICallbackService.cs file, and then click Add.
  5. Right-click your project and select Add > Existing Item again. Navigate to the CallbackData_WNS_Gen2.cs file, and then click Add.

Implement the Callback interface

The Callback method must accept a CallbackRequest object, which is an HTTP request SOAP message from the ThingSpace Platform, and return a CallbackResponse object, which is a short SOAP message containing the RequestID.

NOTE: This sample code uses log4net to track callback processing. All of the logging lines are optional. Leave them out if you don't have log4net installed, or replace them with statements for a different logging system, such as System.Diagnostics.

  1. Add the following using statements at the top of your code. Be sure to use the same namespace names that you used when converting the WSDL and XSD files.

    using System.Xml.Serialization;
    using log4net;
    using com.yourcompany.m2mlistener;
    using com.yourcompany.m2mlistener.data;
    
  2. Create a class that is based on WebService and implements the ICallbackService interface:

      public class Listener : WebService, ICallbackService
    
  3. Enable logging to track callback processing:

        private static readonly ILog Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
    
  4. Begin the Callback method by validating that the request contains data:

        // Implement the Callback interface for all callbacks except SMS
        public CallbackResponse Callback(CallbackRequest request)
        {
          if (request == null)
          {
            throw new NullReferenceException("Null request.");
          } 
          else
          {
            Logger.Info("Request Id: " + request.RequestId);
          }
          if (request.Data == null) throw new NullReferenceException("Null data.");
          Logger.Info(request.Data.OuterXml);
    
  5. Deserialize the XML string and verify that it is of type CallbackData. Throw an exception if it is not.

          Logger.Info("De-serializing...");
          var reader = new StringReader(request.Data.OuterXml);
          var serializer = new XmlSerializer(typeof(CallbackData));
          var someObject = serializer.Deserialize(reader);
          if (someObject.GetType() != typeof(CallbackData))
          {
            throw new ApplicationException(
              string.Format("Expecting de-serialized object to be of type CallbackData, but got {0} instead.", someObject.GetType())
            );
          }
    
  6. Cast the deserialized data as CallbackData and then check for a SOAP fault.

          else
          {
            Logger.Info("De-serialized successfully.");
    
            CallbackData cbData = (CallbackData)someObject;
    
            if (cbData.Fault != null)
            {
              Logger.Info("Fault error: " + cbData.Fault.faultcode + "\n" + cbData.Fault.faultstring);
            }
    
  7. Process valid callbacks that don't have SOAP faults. This tutorial only looks for CarrierService callbacks from device activations, but you can also read the MDN, MIN, and IP address that were assigned when the device was activated. The sample code assumes that an "activateRequestId" has been read from a database to match with the ID in the callback, and that another method exists for adding device phone numbers to a database of active devices.

            else
            {
              // Check if the request ID matches the one for device that you activated
              if (request.RequestId == activateRequestId)
              {
                if (cbData.CarrierService != null &&
                  cbData.CarrierService.ChangeDeviceState != null &&
                  cbData.CarrierService.ChangeDeviceState.Activate != null &&
                  cbData.CarrierService.ChangeDeviceState.Activate.DeviceIdentifierCollection != null)
                  {
                    // Loop through device identifiers
                    foreach (com.yourcompany.m2mlistener.data.DeviceIdentifier deviceId 
                    in cbData.CarrierService.ChangeDeviceState.Activate.DeviceIdentifierCollection)
                    {
                      // Call a method you've created that stores 
                      // the identifiers somewhere
                      AddToActivatedDevices(deviceId.Kind, deviceId.Identifier);
                    }
                  }
                }
              }
    
  8. The method ends by returning the original Request ID in a SOAP response, as an acknowledgement to the ThingSpace Platform that the request was received. Your application must acknowledge callback messages within 15 seconds. Unacknowledged callback messages will be resent 3 times at 5 minute intervals, and then marked as failed.

            }
    
            return new CallbackResponse { RequestId = request.RequestId };
          }
    
  9. The ICallbackService interface also declares an SmsCallback method, so you will have to provide a placeholder method to avoid compile errors.

          public SmsCallbackResponse SmsCallback(SmsCallbackRequest SmsCallbackRequest)
          {
            Logger.InfoFormat("Received SMS Message: {0} from device [", SmsCallbackRequest.SmsMessage);
            if (SmsCallbackRequest.Device != null)
              foreach (var device in SmsCallbackRequest.Device)
              {
                Logger.InfoFormat("\"{0} {1}\"", device.Kind, device.Identifier);
              }
            Logger.Info("]");
    
            return new SmsCallbackResponse();
          }
    
        }
    
      }
    

Register to Receive Callback Messages

After you have built your callback listener web service and have it running on a server, you need to register the URL of the web service with the ThingSpace Platform so that it knows where to send the callback messages. You only need to do this once for each type of callback message (see the note below); the ThingSpace Platform will store the setting and always send callback messages for your account to that URL. The UWS Explorer tool (included in the Tools and Examples folder in the SDK) is an easy way to register your URL, or you can use a SOAP client like SoapUI, as described here. However, if you choose to do it programmatically, the steps are described below.

NOTE: The ThingSpace Platform can send [[WNS2:Callback Registration Service|several different types of callback messages]], each relating to a different type of information. This tutorial only describes CarrierService callback messages for device activations. You do not need to subscribe to all callback messages -- only to those that are applicable to your needs.

  1. In your Visual Studio project that contains the M2M client Login and Logout methods, right-click on Service References and select Add Service Reference.
  2. In the Address box, type the path to the CallbackRegistrationService.wsdl file from the Wireless Network Services SDK. Type "CallbackRegistrationServiceProxy" in the Namespace field. Click OK.

  3. Add a using statement for the callback service. Replace with the namespace of your project.

    using .CallbackRegistrationServiceProxy;
    
  4. Add a method to register a URL as a callback listener for a specific service. This example uses the CarrierService because it sends responses for device activations.

          private void RegisterCallback(string service, string callbackUrl)
          {
    
             // Create a new CallbackRegistrationService object
             CallbackRegistrationServiceClient callbackRegService =
                new CallbackRegistrationServiceClient("BasicHttpBinding_ICallbackRegistrationService");
    
             // Add a behavior to add a session token to requests. 
             // The sessionToken is the token from logging in.
             callbackRegService.Endpoint.Behaviors.Add(new AddSessionTokenToHeaderBehavior(sessionToken));
    
             // Create a request for registering the callback and set the account name,
             // service name, and URL for your service that will listen for the callback.
             RegisterCallbackRequest request = new RegisterCallbackRequest();
             request.AccountName = "MyAccount";
             request.ServiceName = service;
             request.Url = callbackUrl;
    
             try
             {
                // Send the request.
                RegisterCallbackResponse response = callbackRegService.RegisterCallback(request);
    
                Console.WriteLine("Callback listener registered for " + response.ServiceName);
    
             }
             catch (FaultException ex)
             {
                  Console.WriteLine("FaultException:" + ex.Message);
             }
             catch (System.TimeoutException ex)
             {
                Console.WriteLine("TimeOutException:" + ex.Message);
             }
          }
    
  5. Call the new method from main() and pass in a service name and URL.

            static void Main(string[] args)
            {
                Wns session = new Wns();
                session.Login("username", "password");
                session.RegisterCallback("CarrierService", "http://206.128.130.132:9005/m2mListener");
                session.Logout();
            }
    

    NOTE: Allowed port numbers for new callback registrations are 80, 443, 9001-9006 and 50551-50559.