Welcome to Verizon M2M client application development!
This tutorial teaches you how to build your first M2M client application using C# in Microsoft Visual Studio. The application will log in to create an API session, use the session token to activate a device and retrieve information about the device, and then log out to terminate the session. You’ll learn some fundamentals of working with SOAP in C#, and how to send requests to our web services and receive synchronous responses. (Some M2M API methods also send asynchronous responses, and there is a separate tutorial covering how to receive those responses.)
The Verizon Wireless Network Services API uses SOAP messages in XML format to communicate with your client application. SOAP is a communication protocol that is based on XML, so it can be used on any platform and with any programming language, including C#.
Learn about SOAP and web services:
If this is your first time working with SOAP or XML, don't worry -- you'll only be working with local C# classes and objects. There are standard C# libraries that convert XML messages to C# objects and vice-versa, and the Wireless Network Services SDK includes some common methods and client proxies for all Wireless Network Services web services. You don't need to know how to read XML, and you certainly don't need to be a SOAP expert.
This tutorial will walk you through the steps required to use those C# tools, load the M2M web service descriptions into your project, and use the M2M classes and methods to accomplish some common tasks, including:
There is a separate tutorial that covers creating a listening service for asynchronous callback messages from the ThingSpace Platform, and registering to receive those messages.
You're probably ready to jump right in and get started, but there are some preparatory steps that you have to take before you can write an application to communicate with the ThingSpace Platform web services.
You will not be able to create a functional M2M API client until you can check off all of these items.
Before you start this tutorial, you should have downloaded and installed:
Verizon M2M Wireless Network Services SDK, unzipped to a location on your hard drive
NOTE:This tutorial requires the SDK for release 4.4.1 (October 2014) or newer. If you have an older version of the SDK, go to m2mdeveloper.verizon.com to request the latest version.
One of these versions of Visual Studio, or newer:
This tutorial shows Visual Studio 2012 screenshots, but the commands are similar in other recent versions.
Your client application will interact with web services on the ThingSpace Platform. Your application needs to know what those services are, where to connect with them, and what data can be sent and received.
The ThingSpace Platform web services are described in WSDL files, which are XML documents that conform to the Web Service Description Language. Each web service has its own WSDL file that specifies the location of the service and the operations (methods) that are available in the service. There are also some XSD schema documents that define the details of interacting with the service. The WSDL and schema files for all Verizon Wireless Network Services are included in the Verizon Wireless Network Services SDK.
To work with SOAP web services in your C# application, the WSDLs and schema documents have to be converted to C# classes and methods, and then added to your project. You can do this yourself by adding them as service references, but the SDK contains a ClientProxy project that already contains the C# classes created from the WSDL and XSD files, so that conversion is already done for you.
This tutorial uses a new project and solution to keep things clear. You can also do these steps in an existing project.
Back in Visual Studio, right-click the solution (not your project) and from the Add menu, select Existing Project.
In Visual Studio 2012 and 2013, select Assemblies > Framework. Check the checkboxes for these classes and then click OK:
System.Web
In Visual Studio 2010, click the .Net tab, then select these classes and click OK:
In Visual Studio 2012 and 2013, select Solution > Projects, then check the checkbox for CommonLib and ClientProxy. Click OK.
In Visual Studio 2010, click the Projects tab and select CommonLib and ClientProxy, and click OK.
The ClientProxy class library includes an app.config file that contains system.ServiceModel settings that are required to make connections to the M2M endpoints. You must copy the system.ServiceModel from that file and paste it into the app.config file in your project.
Process Flow
When making calls to Wireless Network Services APIs, your application will follow this flow:
Some requests take some time to process, such as activating a device or changing a service plan. For those requests, the ThingSpace Platform sends 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. Working with M2M callback messages is covered in Create a C# Callback Listener in Visual Studio.
As part of ThingSpace Platform security, your application must include a valid session token in the header of all requests. To receive one, the application must log in, providing a valid username and password. The SOAP response will include a session token.
NOTE:Your application can use a token as many times as needed, but a session expires after 20 minutes of inactivity. If the ThingSpace Platform returns an error saying that the token is expired, your application will need to log in again to obtain a new token.
To log in to the ThingSpace Platform:
Right-click on your project and select Add > Class to create a new class. In this example we named the class "Wns" for "Wireless Network Services."
Add the following using statements before the namespace declaration, to work with SOAP web services.
using CommonLib; using System.ServiceModel; using System.ServiceModel.Description; using System.Configuration;
using ClientProxy.SessionService;
namespace M2MTutorial { class Wns { private string sessionToken; private SessionServiceClient sessionService;
private void Login(string username, string password) { // Create a login request object that will make the API call. // The LogInRequest class is autogenerated from the wsdl file. LogInRequest request = new LogInRequest(); // Set the username and password for the request. request.Username = username; request.Password = password; // Create a SessionServiceClient object. The SessionServiceClient // class is autogenerated from the wsdl file. sessionService = new SessionServiceClient(); // Add a behavior to the sessionService endpoint that will add // the session token to the header of all SessionService requests. // The sessionToken value is added inside the try block. // This is a little more complex for the sessionService client than // for the other services. // AddSessionTokenToHeaderBehavior() comes from the CommonLib library. sessionService.Endpoint.Behaviors.Add(new AddSessionTokenToHeaderBehavior("")); //VS2013 version //sessionService.Endpoint.EndpointBehaviors.Add(new AddSessionTokenToHeaderBehavior("")); try { // Pass the request object to the LogIn() method to // send the request and get the response. LogInResponse response = sessionService.LogIn(request); // The token is a string that you get from the response. sessionToken = response.SessionToken; Console.WriteLine("Log in successful. Session token is " + sessionToken); // Set the session token for the AddSessionToTokenBehavior in the endpoint. var requestHeader = sessionService.Endpoint.Behaviors.First(b => b is AddSessionTokenToHeaderBehavior); ((AddSessionTokenToHeaderBehavior)requestHeader).SessionToken = response.SessionToken; } // The service will return SOAP faults as fault exceptions, // such as for an invalid password catch (FaultException ex) { Console.WriteLine("FaultException:" + ex.Message); } // The service can throw a timeout exception (for instance, if the // SessionServiceClient endpoint address is not correct). catch (System.TimeoutException ex) { Console.WriteLine("TimeoutException:" + ex.Message); } }
Finally, create the main() method to call Login(). Replace "username" and "password" with the UWS username and password for your account.
static void Main(string[] args) { Wns session = new Wns(); session.Login("username", "password"); }
NOTE:If you created a new project for this tutorial, you will need to delete the program.cs file, or at least delete its main() method, since a project can't have two main() methods.
As a security measure, your application should log out of the ThingSpace Platform when finished making requests. Logging out will invalidate the current session token, ensuring that it can't be used for any further requests.
The LogOut request must contain the session token in the header as well as in the body element. The token is added to the request header automatically because Logout() uses the Session Service client that was created by Login(). The ThingSpace Platform verifies the token, invalidates the session, and then returns the same token in the response.
Add a logout method that uses the SessionServiceClient object that was created at login.
private void Logout() { // Add a behavior that adds the session token to all requests. sessionService.Endpoint.Behaviors.Add(new AddSessionTokenToHeaderBehavior(sessionToken)); // VS2013 version // sessionService.Endpoint.EndpointBehaviors.Add(new AddSessionTokenToHeaderBehavior(sessionToken)); LogOutRequest request = new LogOutRequest(); request.SessionToken = sessionToken; try { // Send the request using the SessionServiceClient object // created at login. LogOutResponse response = sessionService.LogOut(request); Console.WriteLine("Session " + response.SessionToken + " terminated."); } catch (FaultException ex) { Console.WriteLine("FaultException:" + ex.Message); } catch (System.TimeoutException ex) { Console.WriteLine("TimeoutException:" + ex.Message); } }
Call the new method from main().
static void Main(string[] args) { Wns session = new Wns(); session.Login("username", "password"); session.Logout(); }
Activating service for a device prepares a device for use on the Verizon network, including adding the device to the account (if it's not added already) and assigning a phone number (MDN/MSISDN). Once activated, a device can send and receive data on the network.
Activating a device is an asynchronous operation that uses CarrierService callbacks to notify you when the activation is complete. Activation usually only takes a few minutes, but can take up to 24 hours to complete. There is a separate tutorial that covers creating a listening service for M2M callback messages and registering to receive those messages.
You must provide a valid service plan code when activating a device so that the service can be billed correctly. This tutorial includes code for getting a list of service plans in the account, and then simply uses the first service plan code that is returned in the response. You will probably want something a little more sophisticated in your production application.
Service plans belong to accounts, and device activation is part of the carrier service, so you need to add using statements for the AccountService and CarrierService classes in ClientProxy.
using ClientProxy.AccountService; using ClientProxy.CarrierService;
Create a method to get the code for the first service plan in the account.
private string GetServicePlanCode(String account) { // Create an AccountServiceClient object. AccountServiceClient accountService = new AccountServiceClient(); // Add a behavior that adds the session token to all requests. accountService.Endpoint.Behaviors.Add(new AddSessionTokenToHeaderBehavior(sessionToken)); // VS2013 version // accountService.Endpoint.EndpointBehaviors.Add(new AddSessionTokenToHeaderBehavior(sessionToken)); // Create a request object and set your account name as an attribute. GetServicePlanListRequest request = new GetServicePlanListRequest(); request.Account = account; try { // Send the request. GetServicePlanListResponse response = accountService.GetServicePlanList(request); // Store the first service plan object. ServicePlan servicePlan = response.ServicePlans[0]; // For tutorial, display success message. Console.WriteLine("Using service plan " + servicePlan.Name + " with code " + servicePlan.Code); // Return the service plan code. return servicePlan.Code; } catch (FaultException ex) { Console.WriteLine("FaultException:" + ex.Message); return "00000"; } catch (System.TimeoutException ex) { Console.WriteLine("TimeoutException:" + ex.Message); return "00000"; } }
To activate a device, you must include identifiers for the device, such as the ICCID (for the SIM card) or the IMEI, ESN, or MEID of the device itself. To activate a 4G device, you must use both the IMEI and the ICCID, in that order. This tutorial uses the two identifiers for a 4G device.
private void ActivateDevice(string account, string svcPlanCode) { // Create a CarrierServiceClient object. CarrierServiceClient carrierService = new CarrierServiceClient(); // Add the session token from login to the header. carrierService.Endpoint.Behaviors.Add(new AddSessionTokenToHeaderBehavior(sessionToken)); // VS2013 version // carrierService.Endpoint.EndpointBehaviors.Add(new AddSessionTokenToHeaderBehavior(sessionToken)); // Create the two Device Identifier objects required for a 4G device. // You must use the fully qualified name for the DeviceIdentifier class because // DeviceService and CarrierService both have DeviceIdentifier classes ClientProxy.CarrierService.DeviceIdentifier deviceId1 = new ClientProxy.CarrierService.DeviceIdentifier(); deviceId1.Kind = "imei"; deviceId1.Identifier = "990003420535574"; ClientProxy.CarrierService.DeviceIdentifier deviceId2 = new ClientProxy.CarrierService.DeviceIdentifier(); deviceId2.Kind = "iccid"; deviceId2.Identifier = "89148000000800784258"; // Put the Device Identifier objects into a list of identifiers. var deviceIds = new List{ deviceId1, deviceId2 }; // Create a DeviceIdentifierCollection object to hold the list of device identifiers. ClientProxy.CarrierService.DeviceIdentifierCollection deviceIdCollection = new ClientProxy.CarrierService.DeviceIdentifierCollection(); deviceIdCollection.DeviceIdentifiers = deviceIds; // Create a list of DeviceIdentifierCollection objects to pass to ChangeDeviceState. // This is the list of all devices to be changed (only one in this case). var deviceList = new List { deviceIdCollection };
You use the ChangeDeviceStateRequest in the CarrierService to make any device state changes. The request has an ActivateDeviceRequest object as a property. (It also has properties for suspending, deactivating, and restoring devices.) The ActivateDeviceRequest object contains properties for the service plan code and the MDN Zip code, which is the Zip code where you expect the device to be used the most. Add the following code under the code you just added. The Zip code is set to 98115.
// Create request to change the device state. ChangeDeviceStateRequest cdsRequest = new ChangeDeviceStateRequest(); cdsRequest.Activate = new ActivateDeviceRequest(); cdsRequest.AccountName = account; cdsRequest.DeviceList = deviceList; //list of devices cdsRequest.Activate.ServicePlan = svcPlanCode; cdsRequest.Activate.MdnZipCode = "98115";
Send the request, and save the returned Request ID to match up with the callback message.
try { // Make the request to activate. ChangeDeviceStateResponse cdsResponse = carrierService.ChangeDeviceState(cdsRequest); // Store the returned request ID for later use. string requestId = cdsResponse.RequestId; // For tutorial, display request ID. Console.WriteLine("Activate request acknowledged with request ID " + requestId); } catch (FaultException ex) { Console.WriteLine("FaultException:" + ex.Message); } catch (System.TimeoutException ex) { Console.WriteLine("TimeOutException:" + ex.Message); } }
Finally, call the new methods from main(). Pass in the name of your account to both of the new methods.
static void Main(string[] args) { Wns session = new Wns(); session.Login("username", "password"); String servicePlanCode = session.GetServicePlanCode("account"); session.ActivateDevice("account", servicePlanCode); session.Logout(); }
After your application has received the callback message indicating that the device activation is complete, you may want to pull all of the information about the device and add it to your local database of devices. For example, your application can parse the returned information to find the phone number that was assigned to the device. The following code requests the information for a device and checks the state and MDN/MSISDN value.
NOTE:Because activation can take some time, do not create your application to make an activation request and then immediately check the device information. The device state will not change until after the asynchronous callback has been sent. Best practice is to wait until after receiving the callback before checking the device information.
Add a using statement for the DeviceService class that is part of ClientProxy.
using ClientProxy.DeviceService;
Add a method to request the device information.
private void GetDvcInformation() { // Create a DeviceServiceClient object. DeviceServiceClient deviceService = new DeviceServiceClient(); // Add a behavior that adds the session token to all DeviceService requests. deviceService.Endpoint.Behaviors.Add(new AddSessionTokenToHeaderBehavior(sessionToken)); // VS2013 version // deviceService.Endpoint.EndpointBehaviors.Add(new AddSessionTokenToHeaderBehavior(sessionToken)); // Create a device information request. GetDeviceInformationRequest gdiRequest = new GetDeviceInformationRequest(); // Use the IMEI of the device you activated as the device ID. // Note that 4G devices only need two identifiers when activating, // so one is enough here. ClientProxy.DeviceService.DeviceIdentifier deviceId = new ClientProxy.DeviceService.DeviceIdentifier(); deviceId.Kind = "imei"; deviceId.Identifier = "990003420535573"; gdiRequest.Device = deviceId; try { GetDeviceInformationResponse gdiResponse = deviceService.GetDeviceInformation(gdiRequest); } catch (FaultException ex) { Console.WriteLine("FaultException:" + ex.Message); } catch (System.TimeoutException ex) { Console.WriteLine("TimeOutException:" + ex.Message); } }
Inside the try statement, add code to find the device state and assigned MDN/MSISDN.
try { GetDeviceInformationResponse gdiResponse = deviceService.GetDeviceInformation(gdiRequest); // The device state is contained in the CarrierInformation String dvcState = gdiResponse.Device.CarrierInformation[0].State; Console.WriteLine("Device state is " + dvcState); // If the device is active, get the MDN/MSISDN assigned by the network. if (dvcState.Equals("active")) { foreach (ClientProxy.DeviceService.DeviceIdentifier dvcId in gdiResponse.Device.DeviceIdentifiers) { if (((dvcId.Kind.Equals("mdn")) | (dvcId.Kind.Equals("msisdn")))) { // You probably want to record the phone number, // but here we'll just display it. Console.WriteLine(dvcId.Kind + " is " + dvcId.Identifier); } } }
Call the new method from main().
static void Main(string[] args) { Wns session = new Wns(); session.Login("username", "password"); String servicePlanCode = session.GetServicePlanCode("account"); session.ActivateDevice("account", servicePlanCode); session.GetDvcInformation(); session.Logout(); }