internal async Task<Token> GenerateTokenAsync()
    {
      string tokenUrl = string.Format(@"https://www.arcgis.com/sharing/oauth2/token?client_id={0}&grant_type=client_credentials&client_secret={1}&f=pjson",
        "client_id",
        "client_secret");

      try
      {
        HttpWebRequest webRequest = (HttpWebRequest)System.Net.WebRequest.Create(tokenUrl);
        webRequest.Timeout = 0xea60;
        System.Net.WebResponse response = await webRequest.GetResponseAsync();
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Token));
        _token = (Token)serializer.ReadObject(response.GetResponseStream());
        return _token;
      }
      catch
      {
        return null;
      }
    }
    //Use the ArcGIS REST API to create a profile line based on the input geometry
    public async Task<Polyline> GetProfileLine(Geometry geometry)
    {
      try
      {
        string requestUrlBase = @"http://elevation.arcgis.com/arcgis/rest/services/Tools/Elevation/GPServer/Profile/";

        //Create the token to use
        TokenService elevationServices = new TokenService();
        _token = await elevationServices.GenerateTokenAsync();

        #region Submit a profile task to be executed asynchronously. A unique job ID will be assigned for the transaction.
        string oidField = "OID";
        string lengthField = "Shape_Length";
        string InputLineFeatures = CreateInputLineFeaturesJson(geometry, oidField, lengthField);
        string additonalParams = "&ProfileIDField=" + oidField + "&DEMResolution=FINEST&MaximumSampleDistance=10&MaximumSampleDistanceUnits=Kilometers&returnZ=true&returnM=true&env%3AoutSR=102100&env%3AprocessSR=102100&f=json";
        string profileServiceUrl = string.Format("{0}submitJob?token={1}&InputLineFeatures={2}{3}", requestUrlBase, _token.AccessToken, InputLineFeatures, additonalParams);

        System.Net.HttpWebRequest webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(profileServiceUrl);
        webRequest.Timeout = 0xea60;
        System.Net.WebResponse response = await webRequest.GetResponseAsync(); 
        #endregion

        #region Use the jobId to check the status of the job. Keep checking if the jobStatus is not "Succeeded"
        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(JobStatus));
        _jobStatus = (JobStatus)serializer.ReadObject(response.GetResponseStream() as Stream);
        while (_jobStatus.Status.Contains("Executing") || _jobStatus.Status.Contains("esriJobWaiting") || _jobStatus.Status.Contains("Submitted"))
        {
          string statusUrl = string.Format("{0}jobs/{1}?f=pjson&token={2}", requestUrlBase, _jobStatus.Id, _token.AccessToken);
          webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(statusUrl);
          response = await webRequest.GetResponseAsync();
          _jobStatus = (JobStatus)serializer.ReadObject(response.GetResponseStream());
        } 
        #endregion

        #region The job has successfully completed. Use the jobId to retrieve the result, then use the result to create a profile line 
        if (_jobStatus.Status.Contains("Succeeded"))
        {
          string resultsUrl = string.Format("{0}jobs/{1}/results/OutputProfile?returnZ=true&returnM=true&f=pjson&token={2}", requestUrlBase, _jobStatus.Id, _token.AccessToken);
          webRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(resultsUrl);
          response = await webRequest.GetResponseAsync();

          serializer = new DataContractJsonSerializer(typeof(OutputProfile));

          //Parse the result as the output profile line
          _outputProfileLine = (OutputProfile)serializer.ReadObject(response.GetResponseStream());
          _outputProfileLine.FeatureSet.HasM = true; 
          _outputProfileLine.FeatureSet.HasZ = true;

          //Create a polyline (profile) from the geometry of the output profile line
          Polyline profile = new Polyline();
          foreach (var points in _outputProfileLine.FeatureSet.Features.FirstOrDefault().Geometry.Paths)
          {
            PointCollection collection = new PointCollection();
            foreach (var point in points)
              collection.Add(
                new MapPoint(
                  Convert.ToDouble(point[0]), //[0] is x
                  Convert.ToDouble(point[1]), //[1] is x
                  Convert.ToDouble(point[2]), //[2] is z
                  Convert.ToDouble(point[3]), //[3] is m
                  new ESRI.ArcGIS.Client.Geometry.SpatialReference(102100)));   
            profile.Paths.Add(collection);
          }

          return profile;
        }
        return null;
        #endregion
      }
      catch (Exception)
      {
        return null;
      }
    }