From 92a688b3c514c78af1dbf95412bef9916511eefa Mon Sep 17 00:00:00 2001 From: Nana Appiah Date: Mon, 3 Apr 2023 12:50:24 +0500 Subject: [PATCH 1/3] fixed remarks from Sonar --- .../Middleware/AcceptHeaderParser.cs | 908 +++++++++--------- .../Model/CustomizationEdmModelNames.cs | 524 +++++----- 2 files changed, 720 insertions(+), 712 deletions(-) diff --git a/NewPlatform.Flexberry.ORM.ODataService/Middleware/AcceptHeaderParser.cs b/NewPlatform.Flexberry.ORM.ODataService/Middleware/AcceptHeaderParser.cs index 0965c9b3..6e8e6a84 100644 --- a/NewPlatform.Flexberry.ORM.ODataService/Middleware/AcceptHeaderParser.cs +++ b/NewPlatform.Flexberry.ORM.ODataService/Middleware/AcceptHeaderParser.cs @@ -1,453 +1,455 @@ -#if NETSTANDARD - -// Основная часть кода взята из: -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// https://github.com/OData/odata.net/blob/7.5.0/src/Microsoft.OData.Client/ContentTypeUtil.cs -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// https://github.com/OData/odata.net/blob/7.5.0/test/FunctionalTests/Service/Microsoft/OData/Service/Error.cs -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// https://github.com/OData/odata.net/blob/7.5.0/src/Microsoft.OData.Client/Build.Portable/Parameterized.Microsoft.OData.Client.Portable.cs -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. -// https://github.com/OData/odata.net/blob/7.5.0/src/Microsoft.OData.Client/Build.Portable/Microsoft.OData.Client.Portable.cs - -namespace NewPlatform.Flexberry.ORM.ODataService.Middleware -{ - using System; - using System.Collections.Generic; - using System.Diagnostics; - using System.Globalization; - using System.Linq; - - /// - /// An accept header parser class. - /// - internal static class AcceptHeaderParser - { - /// Returns all MIME type directives from the specified . - /// Text, as it appears on an HTTP Accepts header. - /// An enumerable object with MIME type directives. - internal static IEnumerable MimeTypeDirectivesFromAcceptHeader(string text) - { - if (string.IsNullOrWhiteSpace(text)) - { - return new string[] { }; - } - - return MimeTypesFromAcceptHeader(text) - .Select(x => x.MimeType); - } - - /// Returns all MIME types from the specified (non-blank) . - /// Non-blank text, as it appears on an HTTP Accepts header. - /// An enumerable object with media type descriptions. - private static IEnumerable MimeTypesFromAcceptHeader(string text) - { - Debug.Assert(!String.IsNullOrEmpty(text), "!String.IsNullOrEmpty(text)"); - List mediaTypes = new List(); - int textIndex = 0; - while (!SkipWhitespace(text, ref textIndex)) - { - ReadMediaTypeAndSubtype(text, ref textIndex, out string type, out string subType); - - while (!SkipWhitespace(text, ref textIndex)) - { - if (text[textIndex] == ',') - { - textIndex++; - break; - } - - if (text[textIndex] != ';') - { - throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter); - } - - textIndex++; - if (SkipWhitespace(text, ref textIndex)) - { - // ';' should be a leading separator, but we choose to be a - // bit permissive and allow it as a final delimiter as well. - break; - } - - SkipMediaTypeParameter(text, ref textIndex); - } - - mediaTypes.Add(new MediaType(type, subType)); - } - - return mediaTypes; - } - - /// Read a parameter for a media type/range. - /// Text to read from. - /// Pointer in text. - private static void SkipMediaTypeParameter(string text, ref int textIndex) - { - int startIndex = textIndex; - if (ReadToken(text, ref textIndex)) - { - throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeMissingValue); - } - - string parameterName = text.Substring(startIndex, textIndex - startIndex); - if (text[textIndex] != '=') - { - throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeMissingValue); - } - - textIndex++; - - SkipQuotedParameterValue(parameterName, text, ref textIndex); - } - - /// - /// Reads Mime type parameter value for a particular parameter in the Content-Type/Accept headers. - /// - /// Name of parameter. - /// Header text. - /// Parsing index in . - /// String representing the value of the parameter. - private static void SkipQuotedParameterValue(string parameterName, string headerText, ref int textIndex) - { - // Check if the value is quoted. - bool valueIsQuoted = false; - if (textIndex < headerText.Length) - { - if (headerText[textIndex] == '\"') - { - textIndex++; - valueIsQuoted = true; - } - } - - while (textIndex < headerText.Length) - { - char currentChar = headerText[textIndex]; - - if (currentChar == '\\' || currentChar == '\"') - { - if (!valueIsQuoted) - { - throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_EscapeCharWithoutQuotes(parameterName)); - } - - textIndex++; - - // End of quoted parameter value. - if (currentChar == '\"') - { - valueIsQuoted = false; - break; - } - - if (textIndex >= headerText.Length) - { - throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_EscapeCharAtEnd(parameterName)); - } - } - else - if (!IsHttpToken(currentChar)) - { - // If the given character is special, we stop processing. - break; - } - - textIndex++; - } - - if (valueIsQuoted) - { - throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_ClosingQuoteNotFound(parameterName)); - } - } - - /// Reads the type and subtype specifications for a MIME type. - /// Text in which specification exists. - /// Pointer into text. - /// Type of media found. - /// Subtype of media found. - private static void ReadMediaTypeAndSubtype(string text, ref int textIndex, out string type, out string subType) - { - Debug.Assert(text != null, "text != null"); - int textStart = textIndex; - if (ReadToken(text, ref textIndex)) - { - throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeUnspecified); - } - - if (text[textIndex] != '/') - { - throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeRequiresSlash); - } - - type = text.Substring(textStart, textIndex - textStart); - textIndex++; - - int subTypeStart = textIndex; - ReadToken(text, ref textIndex); - - if (textIndex == subTypeStart) - { - throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeRequiresSubType); - } - - subType = text.Substring(subTypeStart, textIndex - subTypeStart); - } - - /// - /// Reads a token on the specified text by advancing an index on it. - /// - /// Text to read token from. - /// Index for the position being scanned on text. - /// true if the end of the text was reached; false otherwise. - private static bool ReadToken(string text, ref int textIndex) - { - while (textIndex < text.Length && IsHttpToken(text[textIndex])) - { - textIndex++; - } - - return (textIndex == text.Length); - } - - /// - /// Determines whether the specified character is a valid HTTP header token character. - /// - /// Character to verify. - /// true if c is a valid HTTP header token character; false otherwise. - private static bool IsHttpToken(char c) - { - // A token character is any character (0-127) except control (0-31) or - // separators. 127 is DEL, a control character. - return c < '\x7F' && c > '\x1F' && !IsHttpSeparator(c); - } - - /// - /// Determines whether the specified character is a valid HTTP separator. - /// - /// Character to verify. - /// true if c is a separator; false otherwise. - /// - /// See RFC 2616 2.2 for further information. - /// - private static bool IsHttpSeparator(char c) - { - return - c == '(' || c == ')' || c == '<' || c == '>' || c == '@' || - c == ',' || c == ';' || c == ':' || c == '\\' || c == '"' || - c == '/' || c == '[' || c == ']' || c == '?' || c == '=' || - c == '{' || c == '}' || c == ' ' || c == '\x9'; - } - - /// - /// Skips whitespace in the specified text by advancing an index to - /// the next non-whitespace character. - /// - /// Text to scan. - /// Index to begin scanning from. - /// true if the end of the string was reached, false otherwise. - private static bool SkipWhitespace(string text, ref int textIndex) - { - Debug.Assert(text != null, "text != null"); - Debug.Assert(text.Length >= 0, "text >= 0"); - Debug.Assert(textIndex <= text.Length, "text <= text.Length"); - - while (textIndex < text.Length && Char.IsWhiteSpace(text, textIndex)) - { - textIndex++; - } - - return (textIndex == text.Length); - } - - /// Use this class to represent a media type definition. - [DebuggerDisplay("MediaType [{type}/{subType}]")] - private sealed class MediaType - { - /// Sub-type specification (for example, 'plain'). - private readonly string subType; - - /// Type specification (for example, 'text'). - private readonly string type; - - /// - /// Initializes a new read-only instance. - /// - /// Type specification (for example, 'text'). - /// Sub-type specification (for example, 'plain'). - internal MediaType(string type, string subType) - { - Debug.Assert(type != null, "type != null"); - Debug.Assert(subType != null, "subType != null"); - - this.type = type; - this.subType = subType; - } - - /// Returns the MIME type in standard type/subtype form, without parameters. - internal string MimeType - { - get { return this.type + "/" + this.subType; } - } - } - - /// - /// Strongly-typed and parameterized exception factory. - /// - private static class Error - { - /// - /// Create and trace a HttpHeaderFailure - /// - /// errorCode - /// message - /// InvalidOperationException - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801", Justification = "errorCode ignored for code sharing")] - internal static InvalidOperationException HttpHeaderFailure(int errorCode, string message) - { - return Trace(new InvalidOperationException(message)); - } - - /// - /// Trace the exception - /// - /// type of the exception - /// exception object to trace - /// the exception parameter - private static T Trace(T exception) where T : Exception - { - return exception; - } - } - - /// - /// Strongly-typed and parameterized string resources. - /// - private static class Strings - { - /// - /// A string like "Media type is missing a parameter value." - /// - internal static string HttpProcessUtility_MediaTypeMissingValue - { - get - { - return TextRes.GetString(TextRes.HttpProcessUtility_MediaTypeMissingValue); - } - } - - /// - /// A string like "Media type requires a ';' character before a parameter definition." - /// - internal static string HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter - { - get - { - return TextRes.GetString(TextRes.HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter); - } - } - - /// - /// A string like "Media type requires a '/' character." - /// - internal static string HttpProcessUtility_MediaTypeRequiresSlash - { - get - { - return TextRes.GetString(TextRes.HttpProcessUtility_MediaTypeRequiresSlash); - } - } - - /// - /// A string like "Media type requires a subtype definition." - /// - internal static string HttpProcessUtility_MediaTypeRequiresSubType - { - get - { - return TextRes.GetString(TextRes.HttpProcessUtility_MediaTypeRequiresSubType); - } - } - - /// - /// A string like "Media type is unspecified." - /// - internal static string HttpProcessUtility_MediaTypeUnspecified - { - get - { - return TextRes.GetString(TextRes.HttpProcessUtility_MediaTypeUnspecified); - } - } - - /// - /// A string like "Value for MIME type parameter '{0}' is incorrect because it contained escape characters even though it was not quoted." - /// - internal static string HttpProcessUtility_EscapeCharWithoutQuotes(object o) - { - return TextRes.GetString(TextRes.HttpProcessUtility_EscapeCharWithoutQuotes, o); - } - - /// - /// A string like "Value for MIME type parameter '{0}' is incorrect because it terminated with escape character. Escape characters must always be followed by a character in a parameter value." - /// - internal static string HttpProcessUtility_EscapeCharAtEnd(object p0) - { - return TextRes.GetString(TextRes.HttpProcessUtility_EscapeCharAtEnd, p0); - } - - /// - /// A string like "Value for MIME type parameter '{0}' is incorrect because the closing quote character could not be found while the parameter value started with a quote character." - /// - internal static string HttpProcessUtility_ClosingQuoteNotFound(object p0) - { - return TextRes.GetString(TextRes.HttpProcessUtility_ClosingQuoteNotFound, p0); - } - } - - /// - /// String resources utility class. - /// - private static class TextRes - { - internal const string HttpProcessUtility_MediaTypeMissingValue = "HttpProcessUtility_MediaTypeMissingValue"; - internal const string HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter = "HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter"; - internal const string HttpProcessUtility_MediaTypeRequiresSlash = "HttpProcessUtility_MediaTypeRequiresSlash"; - internal const string HttpProcessUtility_MediaTypeRequiresSubType = "HttpProcessUtility_MediaTypeRequiresSubType"; - internal const string HttpProcessUtility_MediaTypeUnspecified = "HttpProcessUtility_MediaTypeUnspecified"; - internal const string HttpProcessUtility_EscapeCharWithoutQuotes = "Value for MIME type parameter '{0}' is incorrect because it contained escape characters even though it was not quoted."; - internal const string HttpProcessUtility_EscapeCharAtEnd = "Value for MIME type parameter '{0}' is incorrect because it terminated with escape character. Escape characters must always be followed by a character in a parameter value."; - internal const string HttpProcessUtility_ClosingQuoteNotFound = "Value for MIME type parameter '{0}' is incorrect because the closing quote character could not be found while the parameter value started with a quote character."; - - internal static string GetString(string template, params object[] args) - { - if (args != null && args.Length > 0) - { - for (int i = 0; i < args.Length; i++) - { - String value = args[i] as String; - if (value != null && value.Length > 1024) - { - args[i] = value.Substring(0, 1024 - 3) + "..."; - } - } - return String.Format(CultureInfo.CurrentCulture, template, args); - } - else - { - return template; - } - } - } - } -} -#endif +#if NETSTANDARD + +// Основная часть кода взята из: +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// https://github.com/OData/odata.net/blob/7.5.0/src/Microsoft.OData.Client/ContentTypeUtil.cs +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// https://github.com/OData/odata.net/blob/7.5.0/test/FunctionalTests/Service/Microsoft/OData/Service/Error.cs +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// https://github.com/OData/odata.net/blob/7.5.0/src/Microsoft.OData.Client/Build.Portable/Parameterized.Microsoft.OData.Client.Portable.cs +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// https://github.com/OData/odata.net/blob/7.5.0/src/Microsoft.OData.Client/Build.Portable/Microsoft.OData.Client.Portable.cs + +namespace NewPlatform.Flexberry.ORM.ODataService.Middleware +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Globalization; + using System.Linq; + + /// + /// An accept header parser class. + /// + internal static class AcceptHeaderParser + { + /// Returns all MIME type directives from the specified . + /// Text, as it appears on an HTTP Accepts header. + /// An enumerable object with MIME type directives. + internal static IEnumerable MimeTypeDirectivesFromAcceptHeader(string text) + { + if (string.IsNullOrWhiteSpace(text)) + { + return new string[] { }; + } + + return MimeTypesFromAcceptHeader(text) + .Select(x => x.MimeType); + } + + /// Returns all MIME types from the specified (non-blank) . + /// Non-blank text, as it appears on an HTTP Accepts header. + /// An enumerable object with media type descriptions. + private static IEnumerable MimeTypesFromAcceptHeader(string text) + { + Debug.Assert(!String.IsNullOrEmpty(text), "!String.IsNullOrEmpty(text)"); + List mediaTypes = new List(); + int textIndex = 0; + while (!SkipWhitespace(text, ref textIndex)) + { + ReadMediaTypeAndSubtype(text, ref textIndex, out string type, out string subType); + + while (!SkipWhitespace(text, ref textIndex)) + { + if (text[textIndex] == ',') + { + textIndex++; + break; + } + + if (text[textIndex] != ';') + { + throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter); + } + + textIndex++; + if (SkipWhitespace(text, ref textIndex)) + { + // ';' should be a leading separator, but we choose to be a + // bit permissive and allow it as a final delimiter as well. + break; + } + + SkipMediaTypeParameter(text, ref textIndex); + } + + mediaTypes.Add(new MediaType(type, subType)); + } + + return mediaTypes; + } + + /// Read a parameter for a media type/range. + /// Text to read from. + /// Pointer in text. + private static void SkipMediaTypeParameter(string text, ref int textIndex) + { + int startIndex = textIndex; + if (ReadToken(text, ref textIndex)) + { + throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeMissingValue); + } + + string parameterName = text.Substring(startIndex, textIndex - startIndex); + if (text[textIndex] != '=') + { + throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeMissingValue); + } + + textIndex++; + + SkipQuotedParameterValue(parameterName, text, ref textIndex); + } + + /// + /// Reads Mime type parameter value for a particular parameter in the Content-Type/Accept headers. + /// + /// Name of parameter. + /// Header text. + /// Parsing index in . + /// String representing the value of the parameter. + private static void SkipQuotedParameterValue(string parameterName, string headerText, ref int textIndex) + { + // Check if the value is quoted. + bool valueIsQuoted = false; + if (textIndex < headerText.Length) + { + if (headerText[textIndex] == '\"') + { + textIndex++; + valueIsQuoted = true; + } + } + + while (textIndex < headerText.Length) + { + char currentChar = headerText[textIndex]; + + if (currentChar == '\\' || currentChar == '\"') + { + if (!valueIsQuoted) + { + throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_EscapeCharWithoutQuotes(parameterName)); + } + + textIndex++; + + // End of quoted parameter value. + if (currentChar == '\"') + { + valueIsQuoted = false; + break; + } + + if (textIndex >= headerText.Length) + { + throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_EscapeCharAtEnd(parameterName)); + } + } + else + { + if (!IsHttpToken(currentChar)) + { + // If the given character is special, we stop processing. + break; + } + } + + textIndex++; + } + + if (valueIsQuoted) + { + throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_ClosingQuoteNotFound(parameterName)); + } + } + + /// Reads the type and subtype specifications for a MIME type. + /// Text in which specification exists. + /// Pointer into text. + /// Type of media found. + /// Subtype of media found. + private static void ReadMediaTypeAndSubtype(string text, ref int textIndex, out string type, out string subType) + { + Debug.Assert(text != null, "text != null"); + int textStart = textIndex; + if (ReadToken(text, ref textIndex)) + { + throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeUnspecified); + } + + if (text[textIndex] != '/') + { + throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeRequiresSlash); + } + + type = text.Substring(textStart, textIndex - textStart); + textIndex++; + + int subTypeStart = textIndex; + ReadToken(text, ref textIndex); + + if (textIndex == subTypeStart) + { + throw Error.HttpHeaderFailure(400, Strings.HttpProcessUtility_MediaTypeRequiresSubType); + } + + subType = text.Substring(subTypeStart, textIndex - subTypeStart); + } + + /// + /// Reads a token on the specified text by advancing an index on it. + /// + /// Text to read token from. + /// Index for the position being scanned on text. + /// true if the end of the text was reached; false otherwise. + private static bool ReadToken(string text, ref int textIndex) + { + while (textIndex < text.Length && IsHttpToken(text[textIndex])) + { + textIndex++; + } + + return (textIndex == text.Length); + } + + /// + /// Determines whether the specified character is a valid HTTP header token character. + /// + /// Character to verify. + /// true if c is a valid HTTP header token character; false otherwise. + private static bool IsHttpToken(char c) + { + // A token character is any character (0-127) except control (0-31) or + // separators. 127 is DEL, a control character. + return c < '\x7F' && c > '\x1F' && !IsHttpSeparator(c); + } + + /// + /// Determines whether the specified character is a valid HTTP separator. + /// + /// Character to verify. + /// true if c is a separator; false otherwise. + /// + /// See RFC 2616 2.2 for further information. + /// + private static bool IsHttpSeparator(char c) + { + return + c == '(' || c == ')' || c == '<' || c == '>' || c == '@' || + c == ',' || c == ';' || c == ':' || c == '\\' || c == '"' || + c == '/' || c == '[' || c == ']' || c == '?' || c == '=' || + c == '{' || c == '}' || c == ' ' || c == '\x9'; + } + + /// + /// Skips whitespace in the specified text by advancing an index to + /// the next non-whitespace character. + /// + /// Text to scan. + /// Index to begin scanning from. + /// true if the end of the string was reached, false otherwise. + private static bool SkipWhitespace(string text, ref int textIndex) + { + Debug.Assert(text != null, "text != null"); + Debug.Assert(text.Length >= 0, "text >= 0"); + Debug.Assert(textIndex <= text.Length, "text <= text.Length"); + + while (textIndex < text.Length && Char.IsWhiteSpace(text, textIndex)) + { + textIndex++; + } + + return (textIndex == text.Length); + } + + /// Use this class to represent a media type definition. + [DebuggerDisplay("MediaType [{type}/{subType}]")] + private sealed class MediaType + { + /// Sub-type specification (for example, 'plain'). + private readonly string subType; + + /// Type specification (for example, 'text'). + private readonly string type; + + /// + /// Initializes a new read-only instance. + /// + /// Type specification (for example, 'text'). + /// Sub-type specification (for example, 'plain'). + internal MediaType(string type, string subType) + { + Debug.Assert(type != null, "type != null"); + Debug.Assert(subType != null, "subType != null"); + + this.type = type; + this.subType = subType; + } + + /// Returns the MIME type in standard type/subtype form, without parameters. + internal string MimeType + { + get { return this.type + "/" + this.subType; } + } + } + + /// + /// Strongly-typed and parameterized exception factory. + /// + private static class Error + { + /// + /// Create and trace a HttpHeaderFailure + /// + /// errorCode + /// message + /// InvalidOperationException + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801", Justification = "errorCode ignored for code sharing")] + internal static InvalidOperationException HttpHeaderFailure(int errorCode, string message) + { + return Trace(new InvalidOperationException(message)); + } + + /// + /// Trace the exception + /// + /// type of the exception + /// exception object to trace + /// the exception parameter + private static T Trace(T exception) where T : Exception + { + return exception; + } + } + + /// + /// Strongly-typed and parameterized string resources. + /// + private static class Strings + { + /// + /// A string like "Media type is missing a parameter value." + /// + internal static string HttpProcessUtility_MediaTypeMissingValue + { + get + { + return TextRes.GetString(TextRes.HttpProcessUtility_MediaTypeMissingValue); + } + } + + /// + /// A string like "Media type requires a ';' character before a parameter definition." + /// + internal static string HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter + { + get + { + return TextRes.GetString(TextRes.HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter); + } + } + + /// + /// A string like "Media type requires a '/' character." + /// + internal static string HttpProcessUtility_MediaTypeRequiresSlash + { + get + { + return TextRes.GetString(TextRes.HttpProcessUtility_MediaTypeRequiresSlash); + } + } + + /// + /// A string like "Media type requires a subtype definition." + /// + internal static string HttpProcessUtility_MediaTypeRequiresSubType + { + get + { + return TextRes.GetString(TextRes.HttpProcessUtility_MediaTypeRequiresSubType); + } + } + + /// + /// A string like "Media type is unspecified." + /// + internal static string HttpProcessUtility_MediaTypeUnspecified + { + get + { + return TextRes.GetString(TextRes.HttpProcessUtility_MediaTypeUnspecified); + } + } + + /// + /// A string like "Value for MIME type parameter '{0}' is incorrect because it contained escape characters even though it was not quoted." + /// + internal static string HttpProcessUtility_EscapeCharWithoutQuotes(object o) + { + return TextRes.GetString(TextRes.HttpProcessUtility_EscapeCharWithoutQuotes, o); + } + + /// + /// A string like "Value for MIME type parameter '{0}' is incorrect because it terminated with escape character. Escape characters must always be followed by a character in a parameter value." + /// + internal static string HttpProcessUtility_EscapeCharAtEnd(object p0) + { + return TextRes.GetString(TextRes.HttpProcessUtility_EscapeCharAtEnd, p0); + } + + /// + /// A string like "Value for MIME type parameter '{0}' is incorrect because the closing quote character could not be found while the parameter value started with a quote character." + /// + internal static string HttpProcessUtility_ClosingQuoteNotFound(object p0) + { + return TextRes.GetString(TextRes.HttpProcessUtility_ClosingQuoteNotFound, p0); + } + } + + /// + /// String resources utility class. + /// + private static class TextRes + { + internal const string HttpProcessUtility_MediaTypeMissingValue = "HttpProcessUtility_MediaTypeMissingValue"; + internal const string HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter = "HttpProcessUtility_MediaTypeRequiresSemicolonBeforeParameter"; + internal const string HttpProcessUtility_MediaTypeRequiresSlash = "HttpProcessUtility_MediaTypeRequiresSlash"; + internal const string HttpProcessUtility_MediaTypeRequiresSubType = "HttpProcessUtility_MediaTypeRequiresSubType"; + internal const string HttpProcessUtility_MediaTypeUnspecified = "HttpProcessUtility_MediaTypeUnspecified"; + internal const string HttpProcessUtility_EscapeCharWithoutQuotes = "Value for MIME type parameter '{0}' is incorrect because it contained escape characters even though it was not quoted."; + internal const string HttpProcessUtility_EscapeCharAtEnd = "Value for MIME type parameter '{0}' is incorrect because it terminated with escape character. Escape characters must always be followed by a character in a parameter value."; + internal const string HttpProcessUtility_ClosingQuoteNotFound = "Value for MIME type parameter '{0}' is incorrect because the closing quote character could not be found while the parameter value started with a quote character."; + + internal static string GetString(string template, params object[] args) + { + if (args != null && args.Length > 0) + { + for (int i = 0; i < args.Length; i++) + { + String value = args[i] as String; + if (value != null && value.Length > 1024) + { + args[i] = value.Substring(0, 1024 - 3) + "..."; + } + } + return String.Format(CultureInfo.CurrentCulture, template, args); + } + else + { + return template; + } + } + } + } +} +#endif diff --git a/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs b/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs index 0b8b0703..6e816ce9 100644 --- a/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs +++ b/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs @@ -1,259 +1,265 @@ -namespace NewPlatform.Flexberry.ORM.ODataService.Tests.Model -{ - using System.Collections.Generic; - using System.Net; - using System.Net.Http; - - using ICSSoft.STORMNET; - using NewPlatform.Flexberry.ORM.ODataService.Tests.Extensions; - using NewPlatform.Flexberry.ORM.ODataService.Tests.Helpers; - - using Newtonsoft.Json; - - using Xunit; - - /// - /// Класс тестов для тестирования метаданных, получаемых от OData-сервиса. - /// - public class CustomizationEdmModelNames : BaseODataServiceIntegratedTest - { -#if NETCOREAPP - /// - /// Конструктор по-умолчанию. - /// - /// Фабрика для приложения. - public CustomizationEdmModelNames(CustomWebApplicationFactory factory, Xunit.Abstractions.ITestOutputHelper output) - : base(factory, output) - { - } -#endif - - /// - /// Осуществляет проверку того, что для объектов с кастомизацией имён работает чтение. - /// - [Fact] - public void CustomizationEdmModelReadTest() - { - ActODataService(args => - { - var наследник = new Наследник() { Свойство = 1234.5, Свойство1 = "str", Свойство2 = 22 }; - var детейл = new Детейл() { prop1 = 1 }; - var детейл2 = new Детейл2() { prop2 = "str2" }; - var мастер = new Мастер() { prop = "str3" }; - var мастер2 = new Мастер2() { свойство2 = -1 }; - var master = new Master() { property = "str4" }; - наследник.Master = master; - наследник.Мастер = мастер; - мастер.Мастер2 = мастер2; - наследник.Детейл.Add(детейл); - детейл.Детейл2.Add(детейл2); - - var objs = new DataObject[] { наследник }; - args.DataService.UpdateObjects(ref objs); - - // TODO: реализовать проверку чтения объектов через OData. - }); - } - - /// - /// Осуществляет проверку того, что сущности с алиасами, включая детейлы, могут быть успешно созданы через OData. - /// - [Fact(Skip = "TODO: Отладить работу с алиасами детейлов.")] - public void CustomizationEdmModelCreateWithDetailsTest() - { - string[] детейлPropertiesNames = - { - Information.ExtractPropertyPath<Детейл>(x => x.__PrimaryKey), - Information.ExtractPropertyPath<Детейл>(x => x.prop1), - }; - string[] детейл2PropertiesNames = - { - Information.ExtractPropertyPath<Детейл2>(x => x.__PrimaryKey), - Information.ExtractPropertyPath<Детейл2>(x => x.prop2), - }; - string[] наследникPropertiesNames = - { - Information.ExtractPropertyPath<Наследник>(x => x.__PrimaryKey), - Information.ExtractPropertyPath<Наследник>(x => x.Свойство), - Information.ExtractPropertyPath<Наследник>(x => x.Свойство1), - Information.ExtractPropertyPath<Наследник>(x => x.Свойство2), - Information.ExtractPropertyPath<Наследник>(x => x.Master.property), - Information.ExtractPropertyPath<Наследник>(x => x.Мастер.prop), - Information.ExtractPropertyPath<Наследник>(x => x.Мастер.Мастер2.свойство2), - }; - var детейлDynamicView = new View(new ViewAttribute("детейлDynamicView", детейлPropertiesNames), typeof(Детейл)); - var детейл2DynamicView = new View(new ViewAttribute("детейл2DynamicView", детейл2PropertiesNames), typeof(Детейл2)); - детейлDynamicView.AddDetailInView(Information.ExtractPropertyPath<Детейл>(x => x.Детейл2), детейл2DynamicView, true); - var наследникDynamicView = new View(new ViewAttribute("наследникDynamicView", наследникPropertiesNames), typeof(Наследник)); - наследникDynamicView.AddDetailInView(Information.ExtractPropertyPath<Наследник>(x => x.Детейл), детейлDynamicView, true); - - var наследник = new Наследник() { Свойство = 1234.5, Свойство1 = "str", Свойство2 = 22 }; - var детейл = new Детейл() { prop1 = 1 }; - var детейл2 = new Детейл2() { prop2 = "str2" }; - var мастер = new Мастер() { prop = "str3" }; - var мастер2 = new Мастер2() { свойство2 = -1 }; - var master = new Master() { property = "str4" }; - наследник.Master = master; - наследник.Мастер = мастер; - мастер.Мастер2 = мастер2; - наследник.Детейл.Add(детейл); - детейл.Детейл2.Add(детейл2); - - ActODataService(args => - { - string requestJsonData = наследник.ToJson(наследникDynamicView, args.Token.Model); - - string requestUrl = string.Format("http://localhost/odata/{0}", args.Token.Model.GetEdmEntitySet(typeof(Наследник)).Name); - using (HttpResponseMessage response = args.HttpClient.PostAsJsonStringAsync(requestUrl, requestJsonData).Result) - { - // Убедимся, что запрос завершился успешно. - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - } - }); - } - - /// - /// Осуществляет проверку того, что сущности с алиасами могут быть успешно созданы через OData. - /// - [Fact] - public void CustomizationEdmModelCreateTest() - { - string[] наследникPropertiesNames = - { - Information.ExtractPropertyPath<Наследник>(x => x.__PrimaryKey), - Information.ExtractPropertyPath<Наследник>(x => x.Свойство), - Information.ExtractPropertyPath<Наследник>(x => x.Свойство1), - Information.ExtractPropertyPath<Наследник>(x => x.Свойство2), - Information.ExtractPropertyPath<Наследник>(x => x.Master.property), - Information.ExtractPropertyPath<Наследник>(x => x.Мастер.prop), - Information.ExtractPropertyPath<Наследник>(x => x.Мастер.Мастер2.свойство2), - }; - var наследникDynamicView = new View(new ViewAttribute("наследникDynamicView", наследникPropertiesNames), typeof(Наследник)); - - var наследник = new Наследник() { Свойство = 1234.5, Свойство1 = "str", Свойство2 = 22 }; - var мастер = new Мастер() { prop = "str3" }; - var мастер2 = new Мастер2() { свойство2 = -1 }; - var master = new Master() { property = "str4" }; - наследник.Master = master; - наследник.Мастер = мастер; - мастер.Мастер2 = мастер2; - - ActODataService(args => - { - string requestJsonData = наследник.ToJson(наследникDynamicView, args.Token.Model); - - string requestUrl = string.Format("http://localhost/odata/{0}", args.Token.Model.GetEdmEntitySet(typeof(Наследник)).Name); - using (HttpResponseMessage response = args.HttpClient.PostAsJsonStringAsync(requestUrl, requestJsonData).Result) - { - // Убедимся, что запрос завершился успешно. - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - } - }); - } - - /// - /// Осуществляет проверку того, что при POST запросах происходит вставка и удаление связей объекта. - /// Зависимые объекты (мастера, детейлы) представлены в виде - Имя_Связи@odata.bind: Имя_Набора_Сущностей(ключ) или Имя_Связи@odata.bind: [ Имя_Набора_Сущностей(ключ) ] . - /// Тест проверяет следующие факты: - /// - /// Вставка связи мастерового объекта. - /// Удаление связи мастеровго объекта путём присвоения null свойству. - /// Удаление связи мастеровго объекта путём присвоения null для Имя_Связи@odata.bind. - /// - /// - [Fact] - public void PostNavigationPropertiesTest() - { - string[] детейлPropertiesNames = - { - Information.ExtractPropertyPath<Детейл>(x => x.prop1), - }; - string[] masterPropertiesNames = - { - Information.ExtractPropertyPath(x => x.property), - }; - string[] мастерPropertiesNames = - { - Information.ExtractPropertyPath<Мастер>(x => x.prop), - }; - string[] мастер2PropertiesNames = - { - Information.ExtractPropertyPath<Мастер2>(x => x.свойство2), - }; - string[] наследникPropertiesNames = - { - Information.ExtractPropertyPath<Наследник>(x => x.Свойство), - Information.ExtractPropertyPath<Наследник>(x => x.Свойство1), - Information.ExtractPropertyPath<Наследник>(x => x.Свойство2), - }; - var детейлDynamicView = new View(new ViewAttribute("детейлDynamicView", детейлPropertiesNames), typeof(Детейл)); - var masterDynamicView = new View(new ViewAttribute("masterDynamicView", masterPropertiesNames), typeof(Master)); - var мастерDynamicView = new View(new ViewAttribute("мастерDynamicView", мастерPropertiesNames), typeof(Мастер)); - var мастер2DynamicView = new View(new ViewAttribute("мастер2DynamicView", мастер2PropertiesNames), typeof(Мастер2)); - var наследникDynamicView = new View(new ViewAttribute("наследникDynamicView", наследникPropertiesNames), typeof(Наследник)); - - // Объекты для тестирования создания. - var наследник = new Наследник() { Свойство = 1234.5, Свойство1 = "str", Свойство2 = 22 }; - var детейл = new Детейл() { prop1 = 1 }; - var мастер = new Мастер() { prop = "str3" }; - var мастер2 = new Мастер2() { свойство2 = -1 }; - var master = new Master() { property = "str4" }; - наследник.Master = master; - наследник.Мастер = мастер; - мастер.Мастер2 = мастер2; - наследник.Детейл.Add(детейл); - ActODataService(args => - { - string requestUrl; - string receivedJsonMaster, receivedJsonМастер, receivedJsonНаследник; - string requestJsonData = master.ToJson(masterDynamicView, args.Token.Model); - requestUrl = string.Format("http://localhost/odata/{0}", args.Token.Model.GetEdmEntitySet(typeof(Master)).Name); - using (HttpResponseMessage response = args.HttpClient.PostAsJsonStringAsync(requestUrl, requestJsonData).Result) - { - // Убедимся, что запрос завершился успешно. - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - - // Получим строку с ответом (в ней должна вернуться созданная сущность). - receivedJsonMaster = response.Content.ReadAsStringAsync().Result.Beautify(); - } - - requestJsonData = мастер.ToJson(мастерDynamicView, args.Token.Model); - requestUrl = string.Format("http://localhost/odata/{0}", args.Token.Model.GetEdmEntitySet(typeof(Мастер)).Name); - using (HttpResponseMessage response = args.HttpClient.PostAsJsonStringAsync(requestUrl, requestJsonData).Result) - { - // Убедимся, что запрос завершился успешно. - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - - // Получим строку с ответом (в ней должна вернуться созданная сущность). - receivedJsonМастер = response.Content.ReadAsStringAsync().Result.Beautify(); - } - - requestJsonData = наследник.ToJson(наследникDynamicView, args.Token.Model); - DataObjectDictionary objJsonНаследник = DataObjectDictionary.Parse(requestJsonData, наследникDynamicView, args.Token.Model); - Dictionary receivedDict = JsonConvert.DeserializeObject>(receivedJsonMaster); - objJsonНаследник.Add("Master@odata.bind", string.Format( - "{0}({1})", - args.Token.Model.GetEdmEntitySet(typeof(Master)).Name, - receivedDict["__PrimaryKey"])); - receivedDict = JsonConvert.DeserializeObject>(receivedJsonМастер); - objJsonНаследник.Add("MasterAlias@odata.bind", string.Format( - "{0}({1})", - args.Token.Model.GetEdmEntitySet(typeof(Мастер)).Name, - receivedDict["__PrimaryKey"])); - objJsonНаследник.Add("DetailAlias@odata.bind", null); - requestJsonData = objJsonНаследник.Serialize(); - requestUrl = string.Format("http://localhost/odata/{0}", args.Token.Model.GetEdmEntitySet(typeof(Наследник)).Name); - using (HttpResponseMessage response = args.HttpClient.PostAsJsonStringAsync(requestUrl, requestJsonData).Result) - { - // Убедимся, что запрос завершился успешно. - Assert.Equal(HttpStatusCode.Created, response.StatusCode); - - // Получим строку с ответом (в ней должна вернуться созданная сущность). - receivedJsonНаследник = response.Content.ReadAsStringAsync().Result.Beautify(); - } - }); - } - - - } -} +namespace NewPlatform.Flexberry.ORM.ODataService.Tests.Model +{ + using System.Collections.Generic; + using System.Net; + using System.Net.Http; + using ICSSoft.STORMNET; + using NewPlatform.Flexberry.ORM.ODataService.Tests.Extensions; + using NewPlatform.Flexberry.ORM.ODataService.Tests.Helpers; + + using Newtonsoft.Json; + + using Xunit; + + /// + /// Класс тестов для тестирования метаданных, получаемых от OData-сервиса. + /// + public class CustomizationEdmModelNames : BaseODataServiceIntegratedTest + { +#if NETCOREAPP + /// + /// Конструктор по-умолчанию. + /// + /// Фабрика для приложения. + public CustomizationEdmModelNames(CustomWebApplicationFactory factory, Xunit.Abstractions.ITestOutputHelper output) + : base(factory, output) + { + } +#endif + + /// + /// Осуществляет проверку того, что для объектов с кастомизацией имён работает чтение. + /// + [Fact] + public void CustomizationEdmModelReadTest() + { + ActODataService(args => + { + const string property1Value = "str"; + var наследник = new Наследник() { Свойство = 1234.5, Свойство1 = property1Value, Свойство2 = 22 }; + var детейл = new Детейл() { prop1 = 1 }; + var детейл2 = new Детейл2() { prop2 = "str2" }; + var мастер = new Мастер() { prop = "str3" }; + var мастер2 = new Мастер2() { свойство2 = -1 }; + var master = new Master() { property = "str4" }; + наследник.Master = master; + наследник.Мастер = мастер; + мастер.Мастер2 = мастер2; + наследник.Детейл.Add(детейл); + детейл.Детейл2.Add(детейл2); + + var objs = new DataObject[] { наследник }; + args.DataService.UpdateObjects(ref objs); + Assert.NotNull(objs); + + var dt = new Наследник(); + dt.SetExistObjectPrimaryKey(наследник.__PrimaryKey); + args.DataService.LoadObject(Наследник.Views.БазовыйКлассE, dt); + Assert.NotNull(dt); + + Assert.Equal(property1Value, dt.Свойство1); + Assert.Equal(наследник.__PrimaryKey, dt.__PrimaryKey); + Assert.NotNull(dt.Свойство1); + }); + } + + /// + /// Осуществляет проверку того, что сущности с алиасами, включая детейлы, могут быть успешно созданы через OData. + /// + [Fact(Skip = "TODO: Отладить работу с алиасами детейлов.")] + public void CustomizationEdmModelCreateWithDetailsTest() + { + string[] детейлPropertiesNames = + { + Information.ExtractPropertyPath<Детейл>(x => x.__PrimaryKey), + Information.ExtractPropertyPath<Детейл>(x => x.prop1), + }; + string[] детейл2PropertiesNames = + { + Information.ExtractPropertyPath<Детейл2>(x => x.__PrimaryKey), + Information.ExtractPropertyPath<Детейл2>(x => x.prop2), + }; + string[] наследникPropertiesNames = + { + Information.ExtractPropertyPath<Наследник>(x => x.__PrimaryKey), + Information.ExtractPropertyPath<Наследник>(x => x.Свойство), + Information.ExtractPropertyPath<Наследник>(x => x.Свойство1), + Information.ExtractPropertyPath<Наследник>(x => x.Свойство2), + Information.ExtractPropertyPath<Наследник>(x => x.Master.property), + Information.ExtractPropertyPath<Наследник>(x => x.Мастер.prop), + Information.ExtractPropertyPath<Наследник>(x => x.Мастер.Мастер2.свойство2), + }; + var детейлDynamicView = new View(new ViewAttribute("детейлDynamicView", детейлPropertiesNames), typeof(Детейл)); + var детейл2DynamicView = new View(new ViewAttribute("детейл2DynamicView", детейл2PropertiesNames), typeof(Детейл2)); + детейлDynamicView.AddDetailInView(Information.ExtractPropertyPath<Детейл>(x => x.Детейл2), детейл2DynamicView, true); + var наследникDynamicView = new View(new ViewAttribute("наследникDynamicView", наследникPropertiesNames), typeof(Наследник)); + наследникDynamicView.AddDetailInView(Information.ExtractPropertyPath<Наследник>(x => x.Детейл), детейлDynamicView, true); + + var наследник = new Наследник() { Свойство = 1234.5, Свойство1 = "str", Свойство2 = 22 }; + var детейл = new Детейл() { prop1 = 1 }; + var детейл2 = new Детейл2() { prop2 = "str2" }; + var мастер = new Мастер() { prop = "str3" }; + var мастер2 = new Мастер2() { свойство2 = -1 }; + var master = new Master() { property = "str4" }; + наследник.Master = master; + наследник.Мастер = мастер; + мастер.Мастер2 = мастер2; + наследник.Детейл.Add(детейл); + детейл.Детейл2.Add(детейл2); + + ActODataService(args => + { + string requestJsonData = наследник.ToJson(наследникDynamicView, args.Token.Model); + + string requestUrl = string.Format("http://localhost/odata/{0}", args.Token.Model.GetEdmEntitySet(typeof(Наследник)).Name); + using (HttpResponseMessage response = args.HttpClient.PostAsJsonStringAsync(requestUrl, requestJsonData).Result) + { + // Убедимся, что запрос завершился успешно. + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + } + }); + } + + /// + /// Осуществляет проверку того, что сущности с алиасами могут быть успешно созданы через OData. + /// + [Fact] + public void CustomizationEdmModelCreateTest() + { + string[] наследникPropertiesNames = + { + Information.ExtractPropertyPath<Наследник>(x => x.__PrimaryKey), + Information.ExtractPropertyPath<Наследник>(x => x.Свойство), + Information.ExtractPropertyPath<Наследник>(x => x.Свойство1), + Information.ExtractPropertyPath<Наследник>(x => x.Свойство2), + Information.ExtractPropertyPath<Наследник>(x => x.Master.property), + Information.ExtractPropertyPath<Наследник>(x => x.Мастер.prop), + Information.ExtractPropertyPath<Наследник>(x => x.Мастер.Мастер2.свойство2), + }; + var наследникDynamicView = new View(new ViewAttribute("наследникDynamicView", наследникPropertiesNames), typeof(Наследник)); + + var наследник = new Наследник() { Свойство = 1234.5, Свойство1 = "str", Свойство2 = 22 }; + var мастер = new Мастер() { prop = "str3" }; + var мастер2 = new Мастер2() { свойство2 = -1 }; + var master = new Master() { property = "str4" }; + наследник.Master = master; + наследник.Мастер = мастер; + мастер.Мастер2 = мастер2; + + ActODataService(args => + { + string requestJsonData = наследник.ToJson(наследникDynamicView, args.Token.Model); + + string requestUrl = string.Format("http://localhost/odata/{0}", args.Token.Model.GetEdmEntitySet(typeof(Наследник)).Name); + using (HttpResponseMessage response = args.HttpClient.PostAsJsonStringAsync(requestUrl, requestJsonData).Result) + { + // Убедимся, что запрос завершился успешно. + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + } + }); + } + + /// + /// Осуществляет проверку того, что при POST запросах происходит вставка и удаление связей объекта. + /// Зависимые объекты (мастера, детейлы) представлены в виде - Имя_Связи@odata.bind: Имя_Набора_Сущностей(ключ) или Имя_Связи@odata.bind: [ Имя_Набора_Сущностей(ключ) ] . + /// Тест проверяет следующие факты: + /// + /// Вставка связи мастерового объекта. + /// Удаление связи мастеровго объекта путём присвоения null свойству. + /// Удаление связи мастеровго объекта путём присвоения null для Имя_Связи@odata.bind. + /// + /// + [Fact] + public void PostNavigationPropertiesTest() + { + string[] детейлPropertiesNames = + { + Information.ExtractPropertyPath<Детейл>(x => x.prop1), + }; + string[] masterPropertiesNames = + { + Information.ExtractPropertyPath(x => x.property), + }; + string[] мастерPropertiesNames = + { + Information.ExtractPropertyPath<Мастер>(x => x.prop), + }; + string[] мастер2PropertiesNames = + { + Information.ExtractPropertyPath<Мастер2>(x => x.свойство2), + }; + string[] наследникPropertiesNames = + { + Information.ExtractPropertyPath<Наследник>(x => x.Свойство), + Information.ExtractPropertyPath<Наследник>(x => x.Свойство1), + Information.ExtractPropertyPath<Наследник>(x => x.Свойство2), + }; + var детейлDynamicView = new View(new ViewAttribute("детейлDynamicView", детейлPropertiesNames), typeof(Детейл)); + var masterDynamicView = new View(new ViewAttribute("masterDynamicView", masterPropertiesNames), typeof(Master)); + var мастерDynamicView = new View(new ViewAttribute("мастерDynamicView", мастерPropertiesNames), typeof(Мастер)); + var мастер2DynamicView = new View(new ViewAttribute("мастер2DynamicView", мастер2PropertiesNames), typeof(Мастер2)); + var наследникDynamicView = new View(new ViewAttribute("наследникDynamicView", наследникPropertiesNames), typeof(Наследник)); + + // Объекты для тестирования создания. + var наследник = new Наследник() { Свойство = 1234.5, Свойство1 = "str", Свойство2 = 22 }; + var детейл = new Детейл() { prop1 = 1 }; + var мастер = new Мастер() { prop = "str3" }; + var мастер2 = new Мастер2() { свойство2 = -1 }; + var master = new Master() { property = "str4" }; + наследник.Master = master; + наследник.Мастер = мастер; + мастер.Мастер2 = мастер2; + наследник.Детейл.Add(детейл); + ActODataService(args => + { + string requestUrl; + string receivedJsonMaster, receivedJsonМастер, receivedJsonНаследник; + string requestJsonData = master.ToJson(masterDynamicView, args.Token.Model); + requestUrl = string.Format("http://localhost/odata/{0}", args.Token.Model.GetEdmEntitySet(typeof(Master)).Name); + using (HttpResponseMessage response = args.HttpClient.PostAsJsonStringAsync(requestUrl, requestJsonData).Result) + { + // Убедимся, что запрос завершился успешно. + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + + // Получим строку с ответом (в ней должна вернуться созданная сущность). + receivedJsonMaster = response.Content.ReadAsStringAsync().Result.Beautify(); + } + + requestJsonData = мастер.ToJson(мастерDynamicView, args.Token.Model); + requestUrl = string.Format("http://localhost/odata/{0}", args.Token.Model.GetEdmEntitySet(typeof(Мастер)).Name); + using (HttpResponseMessage response = args.HttpClient.PostAsJsonStringAsync(requestUrl, requestJsonData).Result) + { + // Убедимся, что запрос завершился успешно. + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + + // Получим строку с ответом (в ней должна вернуться созданная сущность). + receivedJsonМастер = response.Content.ReadAsStringAsync().Result.Beautify(); + } + + requestJsonData = наследник.ToJson(наследникDynamicView, args.Token.Model); + DataObjectDictionary objJsonНаследник = DataObjectDictionary.Parse(requestJsonData, наследникDynamicView, args.Token.Model); + Dictionary receivedDict = JsonConvert.DeserializeObject>(receivedJsonMaster); + objJsonНаследник.Add("Master@odata.bind", string.Format( + "{0}({1})", + args.Token.Model.GetEdmEntitySet(typeof(Master)).Name, + receivedDict["__PrimaryKey"])); + receivedDict = JsonConvert.DeserializeObject>(receivedJsonМастер); + objJsonНаследник.Add("MasterAlias@odata.bind", string.Format( + "{0}({1})", + args.Token.Model.GetEdmEntitySet(typeof(Мастер)).Name, + receivedDict["__PrimaryKey"])); + objJsonНаследник.Add("DetailAlias@odata.bind", null); + requestJsonData = objJsonНаследник.Serialize(); + requestUrl = string.Format("http://localhost/odata/{0}", args.Token.Model.GetEdmEntitySet(typeof(Наследник)).Name); + using (HttpResponseMessage response = args.HttpClient.PostAsJsonStringAsync(requestUrl, requestJsonData).Result) + { + // Убедимся, что запрос завершился успешно. + Assert.Equal(HttpStatusCode.Created, response.StatusCode); + + // Получим строку с ответом (в ней должна вернуться созданная сущность). + receivedJsonНаследник = response.Content.ReadAsStringAsync().Result.Beautify(); + } + }); + } + } +} From 4be1aed4f4cb924ac73403ae17b481ed8e1b3c01 Mon Sep 17 00:00:00 2001 From: Nana Appiah Date: Mon, 10 Apr 2023 16:47:22 +0500 Subject: [PATCH 2/3] changes made bases on comment --- .../Model/DataObjectEdmDetailSettings.cs | 44 +++++++++---------- .../Model/CustomizationEdmModelNames.cs | 3 +- 2 files changed, 24 insertions(+), 23 deletions(-) diff --git a/NewPlatform.Flexberry.ORM.ODataService/Model/DataObjectEdmDetailSettings.cs b/NewPlatform.Flexberry.ORM.ODataService/Model/DataObjectEdmDetailSettings.cs index 24de88eb..831450b8 100644 --- a/NewPlatform.Flexberry.ORM.ODataService/Model/DataObjectEdmDetailSettings.cs +++ b/NewPlatform.Flexberry.ORM.ODataService/Model/DataObjectEdmDetailSettings.cs @@ -1,24 +1,24 @@ -namespace NewPlatform.Flexberry.ORM.ODataService.Model -{ - using System; - - /// - /// Metadata class for detail relations. - /// - public sealed class DataObjectEdmDetailSettings - { - /// - /// The type of detail. - /// - public Type DetailType { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The type of detail. - public DataObjectEdmDetailSettings(Type detailType) +namespace NewPlatform.Flexberry.ORM.ODataService.Model +{ + using System; + + /// + /// Metadata class for detail relations. + /// + public sealed class DataObjectEdmDetailSettings + { + /// + /// The type of detail. + /// + public Type DetailType { get; } + + /// + /// Initializes a new instance of the class. + /// + /// The type of detail. + public DataObjectEdmDetailSettings(Type detailType) { - DetailType = detailType ?? throw new ArgumentNullException(nameof(detailType), "Contract assertion not met: detailType != null"); - } - } + DetailType = detailType ?? throw new ArgumentNullException(nameof(detailType), "Contract assertion not met: detailType != null"); + } + } } \ No newline at end of file diff --git a/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs b/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs index 6e816ce9..6fc2bc7b 100644 --- a/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs +++ b/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Net; using System.Net.Http; + using ICSSoft.STORMNET; using NewPlatform.Flexberry.ORM.ODataService.Tests.Extensions; using NewPlatform.Flexberry.ORM.ODataService.Tests.Helpers; @@ -59,7 +60,7 @@ public void CustomizationEdmModelReadTest() Assert.Equal(property1Value, dt.Свойство1); Assert.Equal(наследник.__PrimaryKey, dt.__PrimaryKey); - Assert.NotNull(dt.Свойство1); + Assert.NotNull(property1Value); }); } From 8fc8edf759eba7e559568cb429fd85f18f835ed2 Mon Sep 17 00:00:00 2001 From: Nana Appiah Date: Thu, 29 Jun 2023 11:40:34 +0500 Subject: [PATCH 3/3] corrected based on comment --- .../Model/CustomizationEdmModelNames.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs b/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs index 6fc2bc7b..9be86345 100644 --- a/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs +++ b/Tests/NewPlatform.Flexberry.ORM.ODataService.Tests/Model/CustomizationEdmModelNames.cs @@ -60,7 +60,7 @@ public void CustomizationEdmModelReadTest() Assert.Equal(property1Value, dt.Свойство1); Assert.Equal(наследник.__PrimaryKey, dt.__PrimaryKey); - Assert.NotNull(property1Value); + }); }