/// <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); }
#pragma warning disable CS1998 // No async operations in mock /// <summary> /// Implements the same method as the real service interface allowing the mock to be plugged in /// </summary> /// <typeparam name="Response"></typeparam> /// <typeparam name="Request"></typeparam> /// <param name="resource"></param> /// <param name="verb"></param> /// <param name="request"></param> /// <param name="deleteBody"></param> /// <param name="session"></param> /// <returns></returns> public async Task <ShippingApiResponse <Response> > HttpRequest <Response, Request>(string resource, HttpVerb verb, Request request, bool deleteBody, ISession session = null) where Request : IShippingApiRequest { string fullPath = request.RecordingFullPath(resource, session); if (File.Exists(fullPath)) { var apiResponse = new ShippingApiResponse <Response> { HttpStatus = HttpStatusCode.OK, Success = true }; long jsonPosition = 0; using (var fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read)) using (var mimeStream = new MimeStream(fileStream)) { mimeStream.SeekNextPart(); //request mimeStream.SeekNextPart(); //response mimeStream.ClearHeaders(); mimeStream.ReadHeaders(); // reads http headers as well if (!mimeStream.FirstLine.StartsWith("HTTP", StringComparison.InvariantCulture)) { apiResponse = new ShippingApiResponse <Response> { HttpStatus = HttpStatusCode.InternalServerError, Success = false }; session.LogDebug(string.Format("Mock request failed {0}", fullPath)); apiResponse.Errors.Add(new ErrorDetail() { ErrorCode = "Mock 500", Message = "Bad format " + fullPath }); return(apiResponse); } var hrc = mimeStream.FirstLine.Split(' '); apiResponse.HttpStatus = (HttpStatusCode)int.Parse(hrc[1]); apiResponse.Success = apiResponse.HttpStatus == HttpStatusCode.OK; foreach (var h in mimeStream.Headers) { apiResponse.ProcessResponseAttribute(h.Key, h.Value); } using (var recordingStream = new RecordingStream(mimeStream, request.RecordingFullPath(resource, session), FileMode.Create, RecordingStream.RecordType.PlainText)) { try { //dont open the record file recordingStream.IsRecording = false; ShippingApiResponse <Response> .Deserialize(session, recordingStream, apiResponse, jsonPosition); } catch (Exception ex) { session.LogError(string.Format("Mock request {0} got deserialization exception {1}", fullPath, ex.Message)); throw ex; } } } return(apiResponse); } else { var apiResponse = new ShippingApiResponse <Response> { HttpStatus = HttpStatusCode.NotFound, Success = false }; session.LogDebug(string.Format("Mock request failed {0}", fullPath)); apiResponse.Errors.Add(new ErrorDetail() { ErrorCode = "Mock 401", Message = "Could not find response file" + fullPath }); return(apiResponse); } }