Commit 8080597b authored by Matt Hyman's avatar Matt Hyman
Browse files

Consolidate the assert on a deserialization failure to all rest requests and...

Consolidate the assert on a deserialization failure to all rest requests and reduce duplicated logic.
parent 7a44caa1
Loading
Loading
Loading
Loading
+1 −5
Original line number Diff line number Diff line
@@ -151,9 +151,7 @@ namespace Microsoft.Tools.WindowsDevicePortal

                    if (dataStream != null)
                    {
                        DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HttpErrorResponse));

                        HttpErrorResponse errorResponse = (HttpErrorResponse)serializer.ReadObject(dataStream);
                        HttpErrorResponse errorResponse = DevicePortal.ReadJsonStream<HttpErrorResponse>(dataStream);

                        error.HResult = errorResponse.ErrorCode;
                        error.Reason = errorResponse.ErrorMessage;
@@ -168,8 +166,6 @@ namespace Microsoft.Tools.WindowsDevicePortal
                        {
                            error.Reason = errorResponse.Reason;
                        }

                        dataStream.Dispose();
                    }
                }
            }
+85 −0
Original line number Diff line number Diff line
@@ -4,7 +4,12 @@
// </copyright>
//----------------------------------------------------------------------------------------------

using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text.RegularExpressions;

namespace Microsoft.Tools.WindowsDevicePortal
{
@@ -13,6 +18,86 @@ namespace Microsoft.Tools.WindowsDevicePortal
    /// </content>
    public partial class DevicePortal
    {
        // <summary>
        /// The prefix for the <see cref="SystemPerformanceInformation" /> JSON formatting error.
        /// </summary>
        private static readonly string SysPerfInfoErrorPrefix = "{\"Reason\" : \"";

        /// <summary>
        /// The postfix for the <see cref="SystemPerformanceInformation" /> JSON formatting error.
        /// </summary>
        private static readonly string SysPerfInfoErrorPostfix = "\"}";

        /// <summary>
        /// Checks the JSON for any known formatting errors and fixes them.
        /// </summary>
        /// <typeparam name="T">Return type for the JSON message</typeparam>
        /// <param name="jsonStream">The stream that contains the JSON message to be checked.</param>
        private static void JsonFormatCheck<T>(Stream jsonStream)
        {
            if (typeof(T) == typeof(SystemPerformanceInformation))
            {
                StreamReader read = new StreamReader(jsonStream);
                string rawJsonString = read.ReadToEnd();

                // Recover from an error in which SystemPerformanceInformation is returned with an incorrect prefix, postfix and the message converted into JSON a second time.
                if (rawJsonString.StartsWith(SysPerfInfoErrorPrefix, StringComparison.OrdinalIgnoreCase) && rawJsonString.EndsWith(SysPerfInfoErrorPostfix, StringComparison.OrdinalIgnoreCase))
                {
                    // Remove the incorrect prefix and postfix from the JSON message.
                    rawJsonString = rawJsonString.Substring(SysPerfInfoErrorPrefix.Length, rawJsonString.Length - SysPerfInfoErrorPrefix.Length - SysPerfInfoErrorPostfix.Length);

                    // Undo the second JSON conversion.
                    rawJsonString = Regex.Replace(rawJsonString, "\\\\\"", "\"", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
                    rawJsonString = Regex.Replace(rawJsonString, "\\\\\\\\", "\\", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

                    // Overwrite the stream with the fixed JSON.
                    jsonStream.SetLength(0);
                    var sw = new StreamWriter(jsonStream);
                    sw.Write(rawJsonString);
                    sw.Flush();
                }

                jsonStream.Seek(0, SeekOrigin.Begin);
            }
        }

        /// <summary>
        /// Reads dataStream as T.
        /// </summary>
        /// <typeparam name="T">Return type for the JSON message</typeparam>
        /// <param name="jsonStream">The stream that contains the JSON message to be checked.</param>
        /// <param name="settings">Optional settings for JSON serialization.</param>
        public static T ReadJsonStream<T>(Stream dataStream, DataContractJsonSerializerSettings settings = null)
        {
            T data = default(T);
            object response = null;
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T), settings);

            using (dataStream)
            {
                if ((dataStream != null) &&
                    (dataStream.Length != 0))
                {
                    JsonFormatCheck<T>(dataStream);

                    try
                    {
                        response = serializer.ReadObject(dataStream);
                    }
                    catch (SerializationException)
                    {
                        // Assert on serialization failure.
                        Debug.Assert(false);
                        throw;
                    }

                    data = (T)response;
                }
            }

            return data;
        }

        #region Data contract

        /// <summary>
+1 −17
Original line number Diff line number Diff line
@@ -42,28 +42,12 @@ namespace Microsoft.Tools.WindowsDevicePortal
            string apiPath,
            string payload = null) where T : new()
        {
            T data = default(T);

            Uri uri = Utilities.BuildEndpoint(
                this.deviceConnection.Connection,
                apiPath, 
                payload);

            DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));

            using (Stream dataStream = await this.DeleteAsync(uri))
            {
                if ((dataStream != null) &&
                    (dataStream.Length != 0))
                {
                    JsonFormatCheck<T>(dataStream);

                    object response = deserializer.ReadObject(dataStream);
                    data = (T)response;
                }
            }

            return data;
            return ReadJsonStream<T>(await this.DeleteAsync(uri));
        }
    }
}
+1 −60
Original line number Diff line number Diff line
@@ -20,49 +20,6 @@ namespace Microsoft.Tools.WindowsDevicePortal
    /// </content>
    public partial class DevicePortal
    {
        /// <summary>
        /// The prefix for the <see cref="SystemPerformanceInformation" /> JSON formatting error.
        /// </summary>
        private static readonly string SysPerfInfoErrorPrefix = "{\"Reason\" : \"";

        /// <summary>
        /// The postfix for the <see cref="SystemPerformanceInformation" /> JSON formatting error.
        /// </summary>
        private static readonly string SysPerfInfoErrorPostfix = "\"}";

        /// <summary>
        /// Checks the JSON for any known formatting errors and fixes them.
        /// </summary>
        /// <typeparam name="T">Return type for the JSON message</typeparam>
        /// <param name="jsonStream">The stream that contains the JSON message to be checked.</param>
        private static void JsonFormatCheck<T>(Stream jsonStream)
        {
            if (typeof(T) == typeof(SystemPerformanceInformation))
            {
                StreamReader read = new StreamReader(jsonStream);
                string rawJsonString = read.ReadToEnd();

                // Recover from an error in which SystemPerformanceInformation is returned with an incorrect prefix, postfix and the message converted into JSON a second time.
                if (rawJsonString.StartsWith(SysPerfInfoErrorPrefix, StringComparison.OrdinalIgnoreCase) && rawJsonString.EndsWith(SysPerfInfoErrorPostfix, StringComparison.OrdinalIgnoreCase))
                {
                    // Remove the incorrect prefix and postfix from the JSON message.
                    rawJsonString = rawJsonString.Substring(SysPerfInfoErrorPrefix.Length, rawJsonString.Length - SysPerfInfoErrorPrefix.Length - SysPerfInfoErrorPostfix.Length);

                    // Undo the second JSON conversion.
                    rawJsonString = Regex.Replace(rawJsonString, "\\\\\"", "\"", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
                    rawJsonString = Regex.Replace(rawJsonString, "\\\\\\\\", "\\", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);

                    // Overwrite the stream with the fixed JSON.
                    jsonStream.SetLength(0);
                    var sw = new StreamWriter(jsonStream);
                    sw.Write(rawJsonString);
                    sw.Flush();
                }

                jsonStream.Seek(0, SeekOrigin.Begin);
            }
        }

        /// <summary>
        /// Calls the specified API with the provided payload.
        /// </summary>
@@ -74,28 +31,12 @@ namespace Microsoft.Tools.WindowsDevicePortal
            string apiPath,
            string payload = null) where T : new()
        {
            T data = default(T);

            Uri uri = Utilities.BuildEndpoint(
                this.deviceConnection.Connection,
                apiPath,
                payload);

            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(T));

            using (Stream dataStream = await this.GetAsync(uri).ConfigureAwait(false))
            {
                if ((dataStream != null) &&
                    (dataStream.Length != 0))
                {
                    JsonFormatCheck<T>(dataStream);
 
                    object response = serializer.ReadObject(dataStream);
                    data = (T)response;
                }
            }

            return data;
            return ReadJsonStream<T>(await this.GetAsync(uri).ConfigureAwait(false));
        }
    }
}
+2 −18
Original line number Diff line number Diff line
@@ -87,28 +87,12 @@ namespace Microsoft.Tools.WindowsDevicePortal
            Stream requestStream = null,
            string requestStreamContentType = null) where T : new()
        {
            T data = default(T);

           Uri uri = Utilities.BuildEndpoint(
                this.deviceConnection.Connection,
                apiPath, 
                payload);

            DataContractJsonSerializer deserializer = new DataContractJsonSerializer(typeof(T));

            using (Stream dataStream = await this.PostAsync(uri, requestStream, requestStreamContentType))
            {
                if ((dataStream != null) &&
                    (dataStream.Length != 0))
                {
                    JsonFormatCheck<T>(dataStream);

                    object response = deserializer.ReadObject(dataStream);
                    data = (T)response;
                }
            }

            return data;
            return ReadJsonStream<T>(await this.PostAsync(uri, requestStream, requestStreamContentType));
        }
    }
}
Loading