private DataServiceProtocolVersion CalculateDataServiceProtocolVersion(ODataRequest request, ODataResponse response)
        {
            DataServiceProtocolVersion dataServiceVersion = VersionHelper.ConvertToDataServiceProtocolVersion(request.GetHeaderValueIfExists(HttpHeaders.DataServiceVersion));
            DataServiceProtocolVersion maxDataServiceVersion = VersionHelper.ConvertToDataServiceProtocolVersion(request.GetHeaderValueIfExists(HttpHeaders.MaxDataServiceVersion));

            var responseContentType = response.GetHeaderValueIfExists(HttpHeaders.ContentType);
            if (responseContentType != null)
            {
                if (responseContentType.StartsWith(MimeTypes.ApplicationJsonODataLightNonStreaming, StringComparison.OrdinalIgnoreCase) ||
                    responseContentType.StartsWith(MimeTypes.ApplicationJsonODataLightStreaming, StringComparison.OrdinalIgnoreCase))
                {
                    return DataServiceProtocolVersion.V4;
                }
            }

            if (response.StatusCode.IsError())
            {
                return DataServiceProtocolVersion.V4;
            }

            DataServiceProtocolVersion expectedVersion = DataServiceProtocolVersion.V4;
            
            // Apply minDsv if MPV > V2
            if (maxDataServiceVersion != DataServiceProtocolVersion.Unspecified && this.maxProtocolVersion >= maxDataServiceVersion)
            {
                expectedVersion = maxDataServiceVersion;
            }
            else
            {
                expectedVersion = this.maxProtocolVersion;
            }

            // If body of a response is empty, the version is V1 unless it has prefer header.
            if (!this.IsResponseBodyEmpty(response))
            {
                if (request.Uri.IsMetadata())
                {
                    // metadata payloads are not handled by the normal payload element visitor, but the response header will match the model version exactly
                    expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, this.ModelVersionCalculator.CalculateProtocolVersion(this.model));
                }
                else
                {
                    // GET requests are versioned based on the URI because type information is not known until serialization
                    if (request.GetEffectiveVerb() == HttpVerb.Get || request.Uri.IsServiceOperation() || request.Uri.IsAction())
                    {
                        expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, this.UriVersionCalculator.CalculateProtocolVersion(request.Uri, response.Headers[HttpHeaders.ContentType], this.maxProtocolVersion, dataServiceVersion, maxDataServiceVersion));
                    }

                    // Post and update requests are versioned based on the specific instance
                    if (response.RootElement != null)
                    {
                        expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, this.PayloadElementVersionCalculator.CalculateProtocolVersion(response.RootElement, response.Headers[HttpHeaders.ContentType], this.maxProtocolVersion, maxDataServiceVersion));
                    }
                }
            }
            else
            {
                if (request.Uri.IsAction())
                {
                    expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, this.UriVersionCalculator.CalculateProtocolVersion(request.Uri, response.GetHeaderValueIfExists(HttpHeaders.ContentType), this.maxProtocolVersion, dataServiceVersion, maxDataServiceVersion));
                }
            }

            // NOTE: the prefer verifier will ensure that this header is present if it should be, so our only concern here
            // is that the version is >= V3 if it is present
            if (response.Headers.ContainsKey(HttpHeaders.PreferenceApplied))
            {
                expectedVersion = VersionHelper.IncreaseVersionIfRequired(expectedVersion, DataServiceProtocolVersion.V4);
            }

            return expectedVersion;
        } 
        /// <summary>
        /// Helper method for getting the error payload from the response. Handles a special case for media-resource operations which may contain errors despite not normally
        /// being deserialized as such.
        /// </summary>
        /// <param name="response">The current response</param>
        /// <param name="formatSelector">The format selector to use if the response needs to be deserialized</param>
        /// <param name="errorPayload">The error payload if one was found</param>
        /// <returns>Whether or not an error payload was found</returns>
        internal static bool TryGetErrorPayloadFromResponse(ODataResponse response, IProtocolFormatStrategySelector formatSelector, out ODataErrorPayload errorPayload)
        {
            ExceptionUtilities.CheckArgumentNotNull(response, "response");

            errorPayload = null;
            var payload = response.RootElement;
            if (payload == null)
            {
                return false;
            }

            if (payload.ElementType == ODataPayloadElementType.ODataErrorPayload)
            {
                errorPayload = (ODataErrorPayload)payload;
                return true;
            }

            // From here out, try to handle special case for streams which come back with error payloads and are not interpreted
            if (payload.ElementType != ODataPayloadElementType.PrimitiveValue)
            {
                return false;
            }

            var body = ((PrimitiveValue)payload).ClrValue as byte[];
            if (body == null)
            {
                return false;
            }

            var contentType = response.GetHeaderValueIfExists(HttpHeaders.ContentType);
            if (contentType == null)
            {
                return false;
            }

            // deserialize it
            ExceptionUtilities.CheckArgumentNotNull(formatSelector, "formatSelector");
            var formatForContentType = formatSelector.GetStrategy(contentType, null);
            var deserializer = formatForContentType.GetDeserializer();
            payload = deserializer.DeserializeFromBinary(body, new ODataPayloadContext { EncodingName = HttpUtilities.GetContentTypeCharsetOrNull(contentType) });

            errorPayload = payload as ODataErrorPayload;
            return errorPayload != null;
        }
        /// <summary>
        /// Verifies the update succeeded
        /// </summary>
        /// <param name="request">The request to verify</param>
        /// <param name="response">The response to verify</param>
        public override void Verify(ODataRequest request, ODataResponse response)
        {
            base.Verify(request, response);

            var contentType = response.GetHeaderValueIfExists(HttpHeaders.ContentType);
            var version = response.GetDataServiceVersion();
            var options = this.ProtocolImplementationDetails.GetExpectedPayloadOptions(contentType, version, request.Uri);

            new NextLinkValidatingVisitor(request.Uri, options, this).ValidateNextLinks(response.RootElement);
        }
 /// <summary>
 /// Returns a value indicating whether this verifier applies to the given response
 /// </summary>
 /// <param name="response">The response</param>
 /// <returns>
 /// True if it applies, false otherwise
 /// </returns>
 public bool Applies(ODataResponse response)
 {
     return response.GetHeaderValueIfExists(HttpHeaders.ContentType).IfValid(false, c => c.StartsWith(MimeTypes.ApplicationJsonLight, StringComparison.OrdinalIgnoreCase));
 }