Tuesday, May 5, 2015

REST Service reader using HttpWebRequest and HttpWebResponse (now deprecated, prefer using HttpClient)

Instructions: The key component here is Newtonsoft JSON library, specifically the SelectToken method. Use it to specify the path from where you want to start extracting your data from the json object the service serves.

Usage:
public class RESTServiceBL  
{  
     public Response<List<TServiceModel>> CallRESTService<TServiceModel>(RESTServiceRequest request)  
     {  
       return Integrator.GetData<TServiceModel>(request, Enums.DataRequestTypes.RESTService);  
     }  
}  
 using Fnx.Ambulatory.Data.Sql.Actions;  
 using Fnx.Ambulatory.Data.Sql.Contexts;  
 using Fnx.Ambulatory.Entities.Domain.DataEntities;  
 using Fnx.Ambulatory.Entities.Transfer.Request;  
 using Fnx.Ambulatory.Entities.Transfer.Response;  
 using Fnx.Ambulatory.Infrastructure.Common;  
 using Fnx.Ambulatory.Infrastructure.Common.Types;  
 using Newtonsoft;  
 using Newtonsoft.Json;  
 using Newtonsoft.Json.Linq;  
 using Phoenix.CommonUtils;  
 using System;  
 using System.Collections;  
 using System.Collections.Generic;  
 using System.Collections.ObjectModel;  
 using System.Data;  
 using System.Data.Entity;  
 using System.IO;  
 using System.Linq;  
 using System.Net;  
 using System.Reflection;  
 using System.Text;  
 namespace Fnx.Ambulatory.Data.Integrator  
 {  
   public static class Integrator  
   {  
     public static Response<List<T>> GetData<T>(object parameter, Enums.DataRequestTypes requestType)  
     {  
       Response<List<T>> response = new Response<List<T>>();  
       switch (requestType)  
       {  
         case Enums.DataRequestTypes.Database:  
           Enums.DatabaseDataRequestTypes databaseRequestType;  
           AmbulatoryRequestActions ambulatoryRequestAction = new AmbulatoryRequestActions();  
           Enum.TryParse<Enums.DatabaseDataRequestTypes>(parameter.ToString(), out databaseRequestType);  
           switch (databaseRequestType)  
           {  
             //TODO - all the implementation for obtaining data from the DB...  
             case Enums.DatabaseDataRequestTypes.GetTable:  
               AmbulatoryBaseContext db = new AmbulatoryBaseContext();  
               Type type = typeof(AmbulatoryBaseContext);  
               List<PropertyInfo> properties = type.GetProperties(BindingFlags.Public).ToList();  
               Type t = properties.Find(property => property.PropertyType.Name == typeof(T).Name).PropertyType;  
               //    MethodInfo method = t.GetMethod("GenericMethod");  
               //    MethodInfo generic = method.MakeGenericMethod(myType);  
               //    generic.Invoke(this, null);  
               //    data = db.AmbulatoryRequests.ToList<type>();  
               //    //data = //dbContext as IEnumerable<AmbulatoryRequest>;  
               break;  
           }  
           //response.Data = data as List<AmbulatoryRequest>;  
           break;  
         case Enums.DataRequestTypes.RESTService:  
           response = CallRESTService<T>(parameter as RESTServiceRequest);  
           break;  
         case Enums.DataRequestTypes.SOAPService:  
           break;  
       }  
       return response;  
     }  
     private static Response<List<TServiceModel>> CallRESTService<TServiceModel>(RESTServiceRequest request)  
     {  
       Response<object> response = new Response<object> { Data = string.Empty };  
       List<TServiceModel> modelList = new List<TServiceModel>();  
       if (!string.IsNullOrEmpty(request.URI))  
       {  
         Logger.Info(string.Format("About to call REST Service... Service URI: [{0}].", request.URI));  
         response = GetRESTServiceResponse(request.URI);  
         if (response.Status == Enums.ResponseStatus.Success)  
         {  
           try  
           {  
             JArray entries = JToken.Parse(response.Data.ToString()).SelectToken(request.CollectionPath) as JArray;  
             string modelJsonStr = string.Empty;  
             //if no Entry element was found, skip...  
             if (entries != null)  
             {  
               foreach (JToken entry in entries)  
               {  
                 modelList.Add(JToken.Parse(CustomizeEntryString(entry, request.ViewModelPath, request.ReplaceStrings)).ToObject<TServiceModel>());  
               }  
             }  
             // server returned a single Entry JSON  
             else  
             {  
               modelList.Add(JToken.Parse(CustomizeEntryString(JToken.Parse(response.Data.ToString()).SelectToken(request.CollectionPath), request.ViewModelPath, request.ReplaceStrings)).ToObject<TServiceModel>());  
             }  
           }  
           catch (JsonSerializationException ex)  
           {  
             string msg = "Error in parsing REST json response.";  
             Logger.Error(string.Format("{0}\n{1}. Response: [{2}]", msg, ex.Message, response.Data.ToString()));  
             response.Status = Enums.ResponseStatus.Error;  
             response.Message = msg;  
           }  
         }  
       }  
       return new Response<List<TServiceModel>> { ServiceURI = response.ServiceURI, Data = modelList, Message = response.Message, Status = response.Status, MetaData = response.MetaData };  
     }  
     private static Response<object> GetRESTServiceResponse(string requestURI)  
     {  
       HttpWebRequest httpWebRequest = null;  
       ESBServiceResponseMetadata responseMetadata = new ESBServiceResponseMetadata();  
       HttpWebResponse httpWebResponse = null;  
       Stream responseStream = null;  
       StreamReader responseStreamReader = null;  
       StringBuilder httpActivityLog = new StringBuilder();  
       Response<object> response = new Response<object> { ServiceURI = requestURI, Data = string.Empty, Message = string.Empty };  
       bool tryAgain;  
       try  
       {  
         httpWebRequest = WebRequest.Create(requestURI) as HttpWebRequest;  
         Logger.Info(string.Format("HttpWebRequest object created for request [{0}].", requestURI));  
         LogHTTPHeaderData(httpWebRequest.Headers, httpActivityLog);  
         do  
         {  
           tryAgain = false;  
           try  
           {  
             httpWebResponse = httpWebRequest.GetResponse() as HttpWebResponse;  
             LogHTTPHeaderData(httpWebResponse.Headers, httpActivityLog);  
             Logger.Info(httpActivityLog.ToString());  
             try  
             {  
               responseStream = httpWebResponse.GetResponseStream();  
               responseStreamReader = new StreamReader(responseStream);  
               response.Data = responseStreamReader.ReadToEnd();  
               JToken esbServiceToken = JToken.Parse(response.Data.ToString()).SelectToken("feed.ESBServiceResponseMetadata");  
               if (esbServiceToken != null)  
               {  
                 try  
                 {  
                   responseMetadata = esbServiceToken.ToObject<ESBServiceResponseMetadata>();  
                   response.MetaData = responseMetadata;  
                   if (responseMetadata.ResponseStatus == Enums.ESBResponseStatuses.TechnicalError)  
                   {  
                     if (responseMetadata.ResponseDescription.IndexOf("Failed to establish a backside connection") > -1)  
                     {  
                       tryAgain = true;  
                     }  
                   }  
                 }  
                 catch (JsonSerializationException ex)  
                 {  
                   string msg = "Error in parsing REST json response.";  
                   Logger.Error(string.Format("{0}\n{1}. Response: [{2}]", msg, ex.Message, response.Data.ToString()));  
                   response.Status = Enums.ResponseStatus.Error;  
                   response.Message = msg;  
                   Logger.Error(ex);  
                 }  
                 response.Status = responseMetadata.ResponseStatus == Enums.ESBResponseStatuses.Success ? Enums.ResponseStatus.Success : Enums.ResponseStatus.Error;  
                 //response.Message = Enums.GetEnumDescription(responseMetadata.ResponseDescription);  
                 response.Message = responseMetadata.ResponseDescription;  
               }  
               else  
               {  
                 response.Status = Enums.ResponseStatus.Error;  
                 response.Message = "Could not find path 'feed.ESBServiceResponseMetadata' in JSON string.";  
               }  
             }  
             catch (WebException ex)  
             {  
               if (ex.Message.ToLower().IndexOf("timed out") > -1)  
               {  
                 tryAgain = true;  
                 response.FailedAttempts++;  
                 Logger.Error(string.Format("Response timed out. Commencing retry number {0}.", response.FailedAttempts));  
                 Logger.Error(ex);  
               }  
             }  
           }  
           catch (WebException ex)  
           {  
             if (ex.Message.ToLower().IndexOf("timed out") > -1)  
             {  
               tryAgain = true;  
               response.FailedAttempts++;  
               Logger.Error(string.Format("Response timed out. Commencing retry number {0}.", response.FailedAttempts));  
               Logger.Error(ex);  
             }  
           }  
           catch (Exception ex)  
           {  
             Logger.Error(string.Format("Error in getting request's Response Stream object for [{0}].\n{1}\n{2}", requestURI, ex.Message, ex.InnerException != null ? ex.InnerException.Message : string.Empty));  
             Logger.Error(ex);  
             Logger.Info(httpActivityLog.ToString());  
             response.Status = Enums.ResponseStatus.Error;  
             response.Message = string.Format("Error in getting request's Response Stream object for [{0}].\n{1}\n{2}", requestURI, ex.Message, ex.InnerException != null ? ex.InnerException.Message : string.Empty);  
             response.Data = httpActivityLog.ToString();  
           }  
         }  
         while (tryAgain);  
       }  
       catch (Exception ex)  
       {  
         httpWebRequest.Abort();  
         Logger.Error(string.Format("Error in creating HttpWebRequest object for [{0}].", requestURI));  
         Logger.Error(ex);  
         Logger.Info(httpActivityLog.ToString());  
         response.Status = Enums.ResponseStatus.Error;  
         response.Message = string.Format("Error in creating HttpWebRequest object for [{0}].\n{1}", requestURI, ex.Message);  
         response.Data = httpActivityLog.ToString();  
       }  
       finally  
       {  
         if (httpWebResponse != null)  
           httpWebResponse.Close();  
         if (responseStream != null)  
           responseStream.Dispose();  
         if (responseStreamReader != null)  
           responseStreamReader.Dispose();  
       }  
       return response;  
     }  
     private static string CustomizeEntryString(JToken entry, string viewModelPath, List<string> replaceStrings)  
     {  
       string modelJsonStr = string.Empty;  
       modelJsonStr = entry.SelectToken(viewModelPath).ToString();  
       #region Remove unwanted characters  
       /*  
            * In case there are characters that need to be removed from the Json structure the service returns,  
            * so the names of the fields in the Json object match our model field names - and the cast/mapping works  
            */  
       foreach (string replaceStr in replaceStrings)  
       {  
         modelJsonStr = modelJsonStr.Replace(replaceStr, "");  
       }  
       #endregion Remove unwanted characters  
       return modelJsonStr;  
     }  
     private static void LogHTTPHeaderData(WebHeaderCollection webHeaderCollection, StringBuilder httpActivityLog)  
     {  
       for (int i = 0; i < webHeaderCollection.Count; ++i)  
         httpActivityLog.AppendLine(string.Format("\nHTTP header parameter:{0}, Value :{1}", webHeaderCollection.Keys[i], webHeaderCollection[i]));  
     }  
   }  
 }  

No comments:

Post a Comment