internal static void SerializeBody(IShippingApiRequest request, StreamWriter writer, ISession session) { switch (request.ContentType) { case "application/json": var serializer = new JsonSerializer() { ContractResolver = new ShippingApiContractResolver() }; serializer.Error += delegate(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) { // only log an error once if (args.CurrentObject == args.ErrorContext.OriginalObject) { session.LogError(String.Format("Deserialization error at path {0}: {1}", args.ErrorContext.Path, args.ErrorContext.Error)); } if (!session.ThrowExceptions) { args.ErrorContext.Handled = true; } }; ((ShippingApiContractResolver)serializer.ContractResolver).Registry = session.SerializationRegistry; serializer.NullValueHandling = NullValueHandling.Ignore; serializer.Formatting = Formatting.Indented; serializer.Serialize(writer, request); writer.Flush(); return; case "application/x-www-form-urlencoded": bool isFirst = true; foreach (var propertyInfo in request.GetType().GetProperties()) { foreach (object attribute in propertyInfo.GetCustomAttributes(true)) { if (attribute is JsonPropertyAttribute) { if (!isFirst) { writer.WriteLine(); isFirst = false; } writer.Write(((JsonPropertyAttribute)attribute).PropertyName); writer.Write('='); writer.Write((string)propertyInfo.GetValue(request)); } } } writer.Flush(); return; default: session.LogConfigError("Unrecognized request content type:" + request.ContentType); throw new InvalidOperationException("Unrecognized request content type:" + request.ContentType); } }
/// <summary> /// Call the shipping API for given request object. /// </summary> /// <returns>The call.</returns> /// <param name="request">Request.</param> /// <param name="session">Session.</param> public ShippingApiResponse Call(IShippingApiRequest request, ISession session) { MethodInfo method; MethodInfo generic; if (request != null) { session.LogDebug("Mock - calling method"); switch (Verb) { case HttpVerb.DELETE: method = typeof(WebMethod).GetMethod("DeleteWithBodySync"); generic = method.MakeGenericMethod(new Type[] { ResponseType, request.GetType() }); return((ShippingApiResponse)generic.Invoke(null, new object[] { UriRegex, request, session })); case HttpVerb.POST: method = typeof(WebMethod).GetMethod("PostSync"); generic = method.MakeGenericMethod(new Type[] { ResponseType, request.GetType() }); return((ShippingApiResponse)generic.Invoke(null, new object[] { UriRegex, request, session })); case HttpVerb.PUT: method = typeof(WebMethod).GetMethod("PutSync"); generic = method.MakeGenericMethod(new Type[] { ResponseType, request.GetType() }); return((ShippingApiResponse)generic.Invoke(null, new object[] { UriRegex, request, session })); default: throw new Exception("Attempt to GET with a body"); } } else { switch (Verb) { case HttpVerb.DELETE: method = typeof(WebMethod).GetMethod("DeleteSync"); generic = method.MakeGenericMethod(new Type[] { ResponseType, request.GetType() }); return((ShippingApiResponse)generic.Invoke(null, new object[] { UriRegex, request, session })); case HttpVerb.GET: method = typeof(WebMethod).GetMethod("GetSync"); generic = method.MakeGenericMethod(new Type[] { ResponseType, request.GetType() }); return((ShippingApiResponse)generic.Invoke(null, new object[] { UriRegex, request, session })); default: throw new Exception(String.Format("Attempt to {0} without a body", Verb.ToString())); } } }
internal static void SerializeBody(IShippingApiRequest request, StreamWriter writer, ISession session) { switch (request.ContentType) { case "application/json": var serializer = new JsonSerializer() { ContractResolver = new ShippingApiContractResolver() }; ((ShippingApiContractResolver)serializer.ContractResolver).Registry = session.SerializationRegistry; serializer.NullValueHandling = NullValueHandling.Ignore; serializer.Formatting = Formatting.Indented; serializer.Serialize(writer, request); writer.Flush(); return; case "application/x-www-form-urlencoded": bool isFirst = true; foreach (var propertyInfo in request.GetType().GetProperties()) { foreach (object attribute in propertyInfo.GetCustomAttributes(true)) { if (attribute is JsonPropertyAttribute) { if (!isFirst) { writer.WriteLine(); isFirst = false; } writer.Write(((JsonPropertyAttribute)attribute).PropertyName); writer.Write('='); writer.Write((string)propertyInfo.GetValue(request)); } } } writer.Flush(); return; default: session.LogConfigError("Unrecognized request content type:" + request.ContentType); throw new InvalidOperationException("Unrecognized request content type:" + request.ContentType); } }
/// <summary> /// Full path to the recording file /// </summary> /// <param name="request"></param> /// <param name="resource"></param> /// <param name="session"></param> /// <returns></returns> public static string RecordingFullPath(IShippingApiRequest request, string resource, ISession session) { string dirname = session.RecordPath; StringBuilder uriBuilder = new StringBuilder(resource); ShippingApiRequest.SubstitueResourceParameters(request, uriBuilder); string fullPath = (dirname + uriBuilder.ToString().ToLower() + @"\") .Replace('?', Path.DirectorySeparatorChar) .Replace('&', Path.DirectorySeparatorChar) .Replace('/', Path.DirectorySeparatorChar) .Replace('=', '-'); string fileName = "default"; if (session == null) { session = Globals.DefaultSession; } foreach (var h in request.GetHeaders()) { if (h.Item3.ToLower().Equals("authorization")) { if (fileName.Equals("default")) { fileName = h.Item2.Substring(0, 8).ToLower(); } } if (h.Item1.Name.ToLower().Equals("x-pb-transactionid")) { fileName = h.Item2.ToLower(); } } fileName += request.RecordingSuffix; fileName += ".http"; return(fullPath + Path.DirectorySeparatorChar + fileName); }
/// <summary> /// Full path to the recording file /// </summary> /// <param name="request"></param> /// <param name="resource"></param> /// <param name="session"></param> /// <returns></returns> public static string RecordingFullPath(IShippingApiRequest request, string resource, ISession session) { #pragma warning disable CS0618 var dirname = session.RecordPath; #pragma warning restore CS0618 var uriBuilder = new StringBuilder(resource); ShippingApiRequest.SubstitueResourceParameters(request, uriBuilder); var pathBuilder = new StringBuilder("/"); var uriComponents = uriBuilder.ToString().Split('/'); for (int i = 1; i < Math.Min(3, uriComponents.Length); i++) { pathBuilder.Append(uriComponents[i]); pathBuilder.Append(Path.DirectorySeparatorChar); } var fileNameBuilder = new StringBuilder(); for (int i = 3; i < uriComponents.Length; i++) { fileNameBuilder.Append(uriComponents[i]); fileNameBuilder.Append('_'); } var s = fileNameBuilder.ToString().ToLower(); string fileName = ""; if (s.Length > 0) { fileName = s.Substring(0, s.Length - 1) .Replace('?', '-') .Replace('&', '-') .Replace('=', '.'); } // At this point // dirname is base directory // pathBuilder.ToString() is the relative path based on 2 levels of uri path // fileName is the name built from the remaining uri path and any parameters return(dirname + pathBuilder.ToString() + fileName + request.RecordingSuffix + ".txt"); }
/// <summary> /// Request the specified mimeStream, methods and session. /// </summary> /// <returns>The request.</returns> /// <param name="mimeStream">MIME stream.</param> /// <param name="methods">Methods.</param> /// <param name="session">Session.</param> public static ShippingApiMethodRequest Request(MimeStream mimeStream, List <ShippingApiMethod> methods, ISession session) { mimeStream.ReadHeaders(); // reads http headers as well Dictionary <string, string> headers = new Dictionary <string, string>(); foreach (var h in mimeStream.Headers.Keys) { StringBuilder sb = new StringBuilder(); bool first = true; foreach (var s in mimeStream.Headers[h]) { if (first) { first = false; } else { sb.Append(';'); } sb.Append(s); } headers.Add(h, sb.ToString()); } var firstLine = mimeStream.FirstLine.Split(' '); var verb = firstLine[0]; string pattern = "(?<file>/[a-zA-Z0-9/]+)(\\?(?<parameters>.*))*"; var urlRegex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.Compiled); var match = urlRegex.Match(firstLine[1]); if (!match.Success) { throw new Exception("Could not parse URI"); } var uri = match.Groups[urlRegex.GroupNumberFromName("file")].Value; var parameters = match.Groups[urlRegex.GroupNumberFromName("parameters")].Value; var requestParameters = new Dictionary <string, string>(); if (parameters != null && !parameters.Equals("")) { var p1 = parameters.Split('&'); foreach (var p2 in p1) { var h = p2.Split('='); requestParameters[h[0]] = h[1]; } } var deserializer = new JsonSerializer(); deserializer.Error += DeserializationError; deserializer.ContractResolver = new ShippingApiContractResolver(); if (session.TraceWriter != null) { deserializer.TraceWriter = session.TraceWriter; } foreach (var method in methods) { if (method.Verb.ToString() != verb) { continue; } var re = new Regex(method.UriRegex, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.CultureInvariant | RegexOptions.Compiled); var m = re.Match(uri); if (m.Success) { IShippingApiRequest request = null; // create the request using (var reader = new StreamReader(mimeStream)) { ((ShippingApiContractResolver)deserializer.ContractResolver).Registry = session.SerializationRegistry; // if wrapped create wrapper object if (method.RequestInterface != null) { var obj = deserializer.Deserialize(reader, method.RequestType); Type[] typeArgs = { obj.GetType() }; var wrapperType = session.SerializationRegistry.GetWrapperFor(method.RequestInterface).MakeGenericType(typeArgs); request = (IShippingApiRequest)Activator.CreateInstance(wrapperType, obj); } else { request = (IShippingApiRequest)deserializer.Deserialize(reader, method.RequestType); } } // set params in the URI for (int g = 0; g < m.Groups.Count; g++) { var paramName = re.GroupNameFromNumber(g); // set property of the request matching capture name if (!Regex.IsMatch(paramName, "^\\d+$")) { PropertyInfo prop = method.RequestType.GetProperty("paramName"); prop.SetValue(request, match.Groups[g].Value, null); } } // query properties ShippingApiRequest.ProcessRequestAttributes <ShippingApiQueryAttribute>(request, (a, s, v, p) => { // p is prop name if (requestParameters.ContainsKey(s)) { PropertyInfo prop = request.GetType().GetProperty(p); //TODO: better handling of JSON encoding var sb = new StringBuilder(requestParameters[s]).Replace("\"", "\\\"").Append("\""); sb.Insert(0, "\""); var tx = new StringReader(sb.ToString()); var o = deserializer.Deserialize(tx, prop.PropertyType); prop.SetValue(request, o); } } ); // header properties ShippingApiRequest.ProcessRequestAttributes <ShippingApiHeaderAttribute>(request, (a, s, v, p) => { foreach (var h in headers) { if (h.Key.ToLower() == s.ToLower()) { PropertyInfo prop = request.GetType().GetProperty(p); var sb = new StringBuilder(h.Value).Replace("\"", "\\\"").Append("\""); sb.Insert(0, "\""); var tx = new StringReader(sb.ToString()); var o = deserializer.Deserialize(tx, prop.PropertyType); prop.SetValue(request, o); break; } } } ); return(new ShippingApiMethodRequest() { Method = method, Request = request }); } } return(null); }