/// <summary>
        /// Process the incoming request and forms a formatted outgoing response.
        /// </summary>
        /// <param name="incomingRequest">Incoming request</param>
        /// <returns>Message instance containing the outgoing response</returns>
        public Message ProcessRequest(Request incomingRequest)
        {
            _baseUri = _serviceHost.ServiceBaseUri;

            _responseSerializationFormat = incomingRequest.ResponseSerializationFormat;

            // Check and fire request interceptor.
            if (_configuration.HasRequestInterceptors(this._scopeName, SyncOperations.Download))
            {
                // Init the SyncOperationContext
                this.InitRequestOperationContext();

                // Fire the request Interceptors if any
                base.ProcessRequestInterceptors();
            }

            IAsymmetricProviderService providerService =
                new SqlSyncProviderService(_configuration,
                                           Convert.ToString(incomingRequest.CommandParams[CommandParamType.ScopeName]),
                                           incomingRequest.ProviderParams,
                                           base._operationContext);

            _getChangesResponse = providerService.GetChanges(incomingRequest.SyncBlob);

            // Check and fire response interceptor.
            this.PrepareAndProcessResponseInterceptors();

            var oDataWriter = GetSyncWriterWithContents();

            return(base.CreateResponseMessage(incomingRequest.ResponseSerializationFormat, oDataWriter));
        }
        protected Message CreateResponseMessage(SyncSerializationFormat serializationFormat, SyncWriter oDataWriter)
        {
            var bodyWriter = new DelegateBodyWriter(WriteResponse, oDataWriter);

            Message message = Message.CreateMessage(MessageVersion.None, String.Empty, bodyWriter);

            switch (serializationFormat)
            {
            case SyncSerializationFormat.ODataAtom:
                message.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Xml));
                break;

            case SyncSerializationFormat.ODataJson:
                message.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Json));
                break;
            }

            var property = new HttpResponseMessageProperty {
                StatusCode = HttpStatusCode.OK
            };

            property.Headers[HttpResponseHeader.ContentType] = WebUtil.GetContentType(serializationFormat);

            // Copy the SyncOperationContext's ResponseHeaders if present
            if (this._operationContext != null)
            {
                property.Headers.Add(this._operationContext.ResponseHeaders);
            }

            message.Properties.Add(HttpResponseMessageProperty.Name, property);

            return(message);
        }
        protected Message CreateResponseMessage(SyncSerializationFormat serializationFormat, SyncWriter oDataWriter)
        {
            var bodyWriter = new DelegateBodyWriter(WriteResponse, oDataWriter);

            Message message = Message.CreateMessage(MessageVersion.None, String.Empty, bodyWriter);

            switch (serializationFormat)
            {
                case SyncSerializationFormat.ODataAtom:
                    message.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Xml));
                    break;
                case SyncSerializationFormat.ODataJson:
                    message.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Json));
                    break;
            }

            var property = new HttpResponseMessageProperty { StatusCode = HttpStatusCode.OK };
            property.Headers[HttpResponseHeader.ContentType] = WebUtil.GetContentType(serializationFormat);
            
            // Copy the SyncOperationContext's ResponseHeaders if present
            if (this._operationContext != null)
            {
                property.Headers.Add(this._operationContext.ResponseHeaders);
            }

            message.Properties.Add(HttpResponseMessageProperty.Name, property);

            return message;
        }
Exemple #4
0
        internal static string GetContentType(SyncSerializationFormat format)
        {
            switch (format)
            {
            case SyncSerializationFormat.ODataAtom:
                return("application/atom+xml");

            case SyncSerializationFormat.ODataJson:
                return("application/json");

            default:
                throw SyncServiceException.CreateBadRequestError("Unsupported serialization format");
            }
        }
Exemple #5
0
        internal static SyncReader GetSyncReader(SyncSerializationFormat serializationFormat, Stream stream, Type[] knownTypes)
        {
            switch (serializationFormat)
            {
            case SyncSerializationFormat.ODataAtom:
                return(new ODataAtomReader(stream, knownTypes));

            case SyncSerializationFormat.ODataJson:
                return(new ODataJsonReader(stream, knownTypes));

            default:
                throw new NotImplementedException();
            }
        }
Exemple #6
0
        internal static SyncWriter GetSyncWriter(SyncSerializationFormat serializationFormat, Uri baseUri)
        {
            switch (serializationFormat)
            {
            case SyncSerializationFormat.ODataAtom:
                return(new ODataAtomWriter(baseUri));

            case SyncSerializationFormat.ODataJson:
                return(new ODataJsonWriter(baseUri));

            default:
                throw new NotImplementedException();
            }
        }
Exemple #7
0
        internal Request ParseIncomingRequest()
        {
            // Steps:
            // 1. Parse and validate request URI format (/syncscope/syncoperation)
            // 2. Validate QueryString using the HttpContextServiceHost.VerifyQueryParameters method.
            // 3. Parse and save query string parameters
            // 4. Identify and save request type, scopename, syncblob, request body.

            // throw BadRequest if duplicates are found.

            /*
             * string[] RelativeUriSegments = new string[_serviceHost.RelativeUriSegments.Length - 1];
             * for (int i = 1; i < _serviceHost.RelativeUriSegments.Length; i++)
             *  RelativeUriSegments[i - 1] = _serviceHost.RelativeUriSegments[i];
             */
            string[] RelativeUriSegments = _serviceHost.RelativeUriSegments;


            _serviceHost.VerifyQueryParameters();
            SyncSerializationFormat outputSerializationFormat = _serviceHost.GetOutputSerializationFormat(_configuration.SerializationFormat);

            SyncTracer.Verbose("Output Serialization format: {0}", outputSerializationFormat);

            RequestCommand requestCommand = GetRequestCommandType(RelativeUriSegments);

            SyncTracer.Verbose("RequestCommand type: {0}", requestCommand);

            List <IOfflineEntity> entities = null;
            Dictionary <CommandParamType, object> commandParameters = null;

            // Get command paramaters (filter params, scope name etc.) for all request types except $syncScopes
            if (requestCommand != RequestCommand.SyncScopes)
            {
                commandParameters = GetCommandParameters(_serviceHost.QueryStringCollection, RelativeUriSegments);
            }

            // Read the payload, headers etc for upload and download request types.
            if (requestCommand == RequestCommand.DownloadChanges || requestCommand == RequestCommand.UploadChanges)
            {
                ReadIncomingRequestDetails();
                entities = GetEntityListFromRequest(requestCommand);
            }

            var request = new Request(requestCommand, _serviceHost, commandParameters, _syncBlob, entities, outputSerializationFormat)
            {
                IdToTempIdMapping = _idToTempIdMapping
            };

            return(request);
        }
Exemple #8
0
        /// <summary>
        /// Process the incoming request and forms a formatted outgoing response.
        /// </summary>
        /// <param name="incomingRequest">Incoming request</param>
        /// <returns>Message instance containing the outgoing response</returns>
        public Message ProcessRequest(Request incomingRequest)
        {
            _baseUri = _serviceHost.ServiceBaseUri;

            _responseSerializationFormat = incomingRequest.ResponseSerializationFormat;

            _incomingEntities = incomingRequest.EntityList;

            _idToTempIdMapping = incomingRequest.IdToTempIdMapping;

            // Check and invoke request interceptor
            this.PrepareAndProcessRequestInterceptor();

            IAsymmetricProviderService providerService =
                new SqlSyncProviderService(_configuration,
                                           Convert.ToString(incomingRequest.CommandParams[CommandParamType.ScopeName]),
                                           incomingRequest.ProviderParams,
                                           base._operationContext);

            // Set a callback for the ApplyClientChangeFailed delegate.
            ((SqlSyncProviderService)providerService).ApplyClientChangeFailed = ClientChangeFailedToApply;

            // Loop over client input and pull all inserts to a different collection.
            _incomingNewInsertEntities = _incomingEntities.Where(e => string.IsNullOrEmpty(e.ServiceMetadata.Id)).ToList();

            _applyChangesResponse = providerService.ApplyChanges(incomingRequest.SyncBlob, incomingRequest.EntityList);

            if (_applyChangesResponse.Errors.Count > 0)
            {
                throw new Exception(_applyChangesResponse.Errors[0].Description);
            }

            // Give the inserts permanent Ids
            AssignRealIdsForClientInserts(_incomingNewInsertEntities);

            // Process the rejected entities if any
            this.ProcessRejectedEntities((SqlSyncProviderService)providerService);

            // Check and fire response interceptor
            this.PrepareAndProcessResponseInterceptor(providerService);

            var oDataWriter = GetSyncWriterWithContents();

            return(base.CreateResponseMessage(incomingRequest.ResponseSerializationFormat, oDataWriter));
        }
Exemple #9
0
        internal Request(RequestCommand requestCommand, 
                        HttpContextServiceHost serviceHost, 
                        Dictionary<CommandParamType, object> commandParams, 
                        byte[] blob,
                        List<IOfflineEntity> entities, 
                        SyncSerializationFormat responseSerializationFormat)
        {
            IdToTempIdMapping = new Dictionary<string, string>();

            RequestCommand = requestCommand;
            ServiceHost = serviceHost;
            CommandParams = commandParams;
            SyncBlob = blob;
            ResponseSerializationFormat = responseSerializationFormat;

            if (null != entities && requestCommand != RequestCommand.UploadChanges)
            {
                throw SyncServiceException.CreateBadRequestError(Strings.EntitiesOnlyAllowedForUploadChangesRequest);
            }

            EntityList = entities;
        }
Exemple #10
0
        internal Request(RequestCommand requestCommand,
                         HttpContextServiceHost serviceHost,
                         Dictionary <CommandParamType, object> commandParams,
                         byte[] blob,
                         List <IOfflineEntity> entities,
                         SyncSerializationFormat responseSerializationFormat)
        {
            IdToTempIdMapping = new Dictionary <string, string>();

            RequestCommand = requestCommand;
            ServiceHost    = serviceHost;
            CommandParams  = commandParams;
            SyncBlob       = blob;
            ResponseSerializationFormat = responseSerializationFormat;

            if (null != entities && requestCommand != RequestCommand.UploadChanges)
            {
                throw SyncServiceException.CreateBadRequestError(Strings.EntitiesOnlyAllowedForUploadChangesRequest);
            }

            EntityList = entities;
        }
 /// <summary>
 /// Change the default serialization format. The default value is ODataAtom.
 /// </summary>
 /// <param name="serializationFormat">serialization format</param>
 public void SetDefaultSyncSerializationFormat(SyncSerializationFormat serializationFormat)
 {
     SerializationFormat = serializationFormat;
 }
        /// <summary>
        /// Process the incoming request and forms a formatted outgoing response.
        /// </summary>
        /// <param name="incomingRequest">Incoming request</param>
        /// <returns>Message instance containing the outgoing response</returns>
        public Message ProcessRequest(Request incomingRequest)
        {
            _baseUri = _serviceHost.ServiceBaseUri;

            _responseSerializationFormat = incomingRequest.ResponseSerializationFormat;

            _incomingEntities = incomingRequest.EntityList;

            _idToTempIdMapping = incomingRequest.IdToTempIdMapping;

            // Check and invoke request interceptor
            this.PrepareAndProcessRequestInterceptor();

            IAsymmetricProviderService providerService =
                new SqlSyncProviderService(_configuration,
                                           Convert.ToString(incomingRequest.CommandParams[CommandParamType.ScopeName]),
                                           incomingRequest.ProviderParams,
                                           base._operationContext);

            // Set a callback for the ApplyClientChangeFailed delegate.
            ((SqlSyncProviderService)providerService).ApplyClientChangeFailed = ClientChangeFailedToApply;

            // Loop over client input and pull all inserts to a different collection.
            _incomingNewInsertEntities = _incomingEntities.Where(e => string.IsNullOrEmpty(e.ServiceMetadata.Id)).ToList();

            _applyChangesResponse = providerService.ApplyChanges(incomingRequest.SyncBlob, incomingRequest.EntityList);

            // Give the inserts permanent Ids
            AssignRealIdsForClientInserts(_incomingNewInsertEntities);

            // Process the rejected entities if any
            this.ProcessRejectedEntities((SqlSyncProviderService)providerService);

            // Check and fire response interceptor
            this.PrepareAndProcessResponseInterceptor(providerService);

            var oDataWriter = GetSyncWriterWithContents();

            return base.CreateResponseMessage(incomingRequest.ResponseSerializationFormat, oDataWriter);
        }
 /// <summary>
 /// Change the default serialization format. The default value is ODataAtom.
 /// </summary>
 /// <param name="serializationFormat">serialization format</param>
 public void SetDefaultSyncSerializationFormat(SyncSerializationFormat serializationFormat)
 {
     SerializationFormat = serializationFormat;
 }
        /// <summary>
        /// Process the incoming request and forms a formatted outgoing response.
        /// </summary>
        /// <param name="incomingRequest">Incoming request</param>
        /// <returns>Message instance containing the outgoing response</returns>
        public Message ProcessRequest(Request incomingRequest)
        {
            _baseUri = _serviceHost.ServiceBaseUri;

            _responseSerializationFormat = incomingRequest.ResponseSerializationFormat;

            // Check and fire request interceptor.
            if (_configuration.HasRequestInterceptors(this._scopeName, SyncOperations.Download))
            {
                // Init the SyncOperationContext
                this.InitRequestOperationContext();

                // Fire the request Interceptors if any
                base.ProcessRequestInterceptors();
            }

            SqlSyncProviderService providerService =
                new SqlSyncProviderService(_configuration,
                                           Convert.ToString(incomingRequest.CommandParams[CommandParamType.ScopeName]),
                                           incomingRequest.ProviderParams, 
                                           base._operationContext);

            _getChangesResponse = providerService.GetChanges(incomingRequest.SyncBlob);

            // Check and fire response interceptor.
            this.PrepareAndProcessResponseInterceptors();

            var oDataWriter = GetSyncWriterWithContents();

            return base.CreateResponseMessage(incomingRequest.ResponseSerializationFormat, oDataWriter);
        }
        /// <summary>
        /// Get the serialization format for the response based on the value of the HTTP Accept header.
        ///
        /// If $format is not specified then the format comes from the accept header.
        ///
        /// The order in which a response content-type is chosen is based on the
        /// incoming "Accept" header and the types that the service supports.
        /// According to the HTTP/1.1 Header Field Definitions RFC
        /// (http:///www.w3.org/Protocols/rfc2616/rfc2616-sec14.html), an absence of the
        /// Accept header means that the client accepts all response types.
        ///
        /// Media ranges can be overridden by more specific media ranges, for example:
        /// both application/json and application/atom+xml would override */*.
        ///
        /// Depending on the service configuration application/atom+xml would override application/json
        /// if application/atom+xml if the default serialization format, and application/json would
        /// override application/atom+xml if the default serialization format is application/json.
        ///
        /// A client can also send a media range of the following type: application/*, which can be
        /// substituted for application/atom+xml or application/json depending on the service configuration.
        ///
        /// A. If the default configured serialization format is "application/atom+xml"
        ///
        ///  The formats in order of priority are:
        ///     1. application/atom+xml
        ///     2. application/json
        ///     3. application/* or */* substituted with application/atom+xml
        ///
        ///  Examples (order of accept headers doesn't matter):
        ///     "application/*" -> ATOM+XML
        ///     "application/*,application/JSON" -> JSON
        ///     "application/*,application/ATOM+XML" -> ATOM+XML
        ///     "application/*,application/ATOM+XML,application/JSON" -> ATOM+XML
        ///     "application/JSON" -> JSON
        ///     "application/ATOM+XML" -> ATOM+XML
        ///     "application/JSON,application/ATOM+XML" -> ATOM+XML
        ///
        /// B. If the default configured serialization format is "application/json"
        ///
        ///  The formats in order of priority are:
        ///     1. application/json
        ///     2. application/atom+xml
        ///     3. application/* or */* substituted with application/json
        ///
        ///  Examples (order of accept headers doesn't matter):
        ///     "application/*" -> JSON
        ///     "application/*,application/JSON" -> JSON
        ///     "application/*,application/ATOM+XML" -> ATOM+XML
        ///     "application/*,application/ATOM+XML,application/JSON" -> JSON
        ///     "application/JSON" -> JSON
        ///     "application/ATOM+XML" -> ATOM+XML
        ///     "application/JSON,application/ATOM+XML" -> JSON
        ///
        /// Note: headers from firefox need to be trimmed before we make a comparison.In other words the media range
        /// parameter as specified in the above RFC are ignored.
        /// </summary>
        /// <returns>Response serialization format</returns>
        internal SyncSerializationFormat GetOutputSerializationFormat(SyncSerializationFormat defaultSerializationFormat)
        {
            // Read $format from querystring first
            string formatQueryString = QueryStringCollection[SYNC_FORMAT_QUERYKEY];
            if (!String.IsNullOrEmpty(formatQueryString))
            {
                if (0 == String.Compare(formatQueryString.ToLowerInvariant(), "atom", StringComparison.InvariantCultureIgnoreCase))
                {
                    return SyncSerializationFormat.ODataAtom;
                }

                if (0 == String.Compare(formatQueryString.ToLowerInvariant(), "bitmobile", StringComparison.InvariantCultureIgnoreCase))
                {
                    return SyncSerializationFormat.ODataBM;
                }

                if (0 == String.Compare(formatQueryString.ToLowerInvariant(), "json", StringComparison.InvariantCultureIgnoreCase))
                {
                    return SyncSerializationFormat.ODataJson;
                }
            }
            else if (!String.IsNullOrEmpty(RequestAccept))
            {
                var header =
                    RequestAccept.ToLowerInvariant().Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(h => h.Trim());

                SyncSerializationFormat? outputSerializationFormat = null;

                foreach (string headerString in header)
                {
                    // Media range followed by optional semi-column and accept-params ,
                    string[] headerStringParts = headerString.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries);

                    if (0 == headerStringParts.Length)
                    {
                        continue;
                    }

                    // Is this header application/atom+xml
                    if (headerStringParts[0].Equals(CONTENT_TYPE_APPLICATION_ATOM, StringComparison.OrdinalIgnoreCase))
                    {
                        outputSerializationFormat = SyncSerializationFormat.ODataAtom;
                    }

                    // Is this header application/atom+xml
                    if (headerStringParts[0].Equals(CONTENT_TYPE_APPLICATION_BM, StringComparison.OrdinalIgnoreCase))
                    {
                        outputSerializationFormat = SyncSerializationFormat.ODataBM;
                    }

                    // Is this header application/json
                    if (headerStringParts[0].Equals(CONTENT_TYPE_APPLICATION_JSON, StringComparison.OrdinalIgnoreCase))
                    {
                        outputSerializationFormat = SyncSerializationFormat.ODataJson;
                    }

                    // If the default header has been set explicitly then no need to read other headers
                    if (outputSerializationFormat == defaultSerializationFormat)
                    {
                        break;
                    }

                    // Is this header application/* or */*
                    if ((null == outputSerializationFormat) &&
                        (headerStringParts[0].Equals(CONTENT_TYPE_APPLICATION_ANY) || headerStringParts[0].Equals(CONTENT_TYPE_ANY)))
                    {
                        // Do not exit the loop as this can be overwritten by an explicit json or atnm+xml header
                        outputSerializationFormat = defaultSerializationFormat;
                    }
                }

                if (null == outputSerializationFormat)
                {
                    throw SyncServiceException.CreateNotAcceptable(Strings.UnsupportedAcceptHeaderValue);
                }

                return outputSerializationFormat.Value;
            }

            // return the default serialization format.
            return defaultSerializationFormat;
        }
Exemple #16
0
        /// <summary>
        /// Get the serialization format for the response based on the value of the HTTP Accept header.
        ///
        /// If $format is not specified then the format comes from the accept header.
        ///
        /// The order in which a response content-type is chosen is based on the
        /// incoming "Accept" header and the types that the service supports.
        /// According to the HTTP/1.1 Header Field Definitions RFC
        /// (http:///www.w3.org/Protocols/rfc2616/rfc2616-sec14.html), an absence of the
        /// Accept header means that the client accepts all response types.
        ///
        /// Media ranges can be overridden by more specific media ranges, for example:
        /// both application/json and application/atom+xml would override */*.
        ///
        /// Depending on the service configuration application/atom+xml would override application/json
        /// if application/atom+xml if the default serialization format, and application/json would
        /// override application/atom+xml if the default serialization format is application/json.
        ///
        /// A client can also send a media range of the following type: application/*, which can be
        /// substituted for application/atom+xml or application/json depending on the service configuration.
        ///
        /// A. If the default configured serialization format is "application/atom+xml"
        ///
        ///  The formats in order of priority are:
        ///     1. application/atom+xml
        ///     2. application/json
        ///     3. application/* or */* substituted with application/atom+xml
        ///
        ///  Examples (order of accept headers doesn't matter):
        ///     "application/*" -> ATOM+XML
        ///     "application/*,application/JSON" -> JSON
        ///     "application/*,application/ATOM+XML" -> ATOM+XML
        ///     "application/*,application/ATOM+XML,application/JSON" -> ATOM+XML
        ///     "application/JSON" -> JSON
        ///     "application/ATOM+XML" -> ATOM+XML
        ///     "application/JSON,application/ATOM+XML" -> ATOM+XML
        ///
        /// B. If the default configured serialization format is "application/json"
        ///
        ///  The formats in order of priority are:
        ///     1. application/json
        ///     2. application/atom+xml
        ///     3. application/* or */* substituted with application/json
        ///
        ///  Examples (order of accept headers doesn't matter):
        ///     "application/*" -> JSON
        ///     "application/*,application/JSON" -> JSON
        ///     "application/*,application/ATOM+XML" -> ATOM+XML
        ///     "application/*,application/ATOM+XML,application/JSON" -> JSON
        ///     "application/JSON" -> JSON
        ///     "application/ATOM+XML" -> ATOM+XML
        ///     "application/JSON,application/ATOM+XML" -> JSON
        ///
        /// Note: headers from firefox need to be trimmed before we make a comparison.In other words the media range
        /// parameter as specified in the above RFC are ignored.
        /// </summary>
        /// <returns>Response serialization format</returns>
        internal SyncSerializationFormat GetOutputSerializationFormat(SyncSerializationFormat defaultSerializationFormat)
        {
            // Read $format from querystring first
            string formatQueryString = QueryStringCollection[SYNC_FORMAT_QUERYKEY];

            if (!String.IsNullOrEmpty(formatQueryString))
            {
                if (0 == String.Compare(formatQueryString.ToLowerInvariant(), "atom", StringComparison.InvariantCultureIgnoreCase))
                {
                    return(SyncSerializationFormat.ODataAtom);
                }

                if (0 == String.Compare(formatQueryString.ToLowerInvariant(), "json", StringComparison.InvariantCultureIgnoreCase))
                {
                    return(SyncSerializationFormat.ODataJson);
                }
            }
            else if (!String.IsNullOrEmpty(RequestAccept))
            {
                var header =
                    RequestAccept.ToLowerInvariant().Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(h => h.Trim());

                SyncSerializationFormat?outputSerializationFormat = null;

                foreach (string headerString in header)
                {
                    // Media range followed by optional semi-column and accept-params ,
                    string[] headerStringParts = headerString.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);

                    if (0 == headerStringParts.Length)
                    {
                        continue;
                    }

                    // Is this header application/atom+xml
                    if (headerStringParts[0].Equals(CONTENT_TYPE_APPLICATION_ATOM, StringComparison.OrdinalIgnoreCase))
                    {
                        outputSerializationFormat = SyncSerializationFormat.ODataAtom;
                    }

                    // Is this header application/json
                    if (headerStringParts[0].Equals(CONTENT_TYPE_APPLICATION_JSON, StringComparison.OrdinalIgnoreCase))
                    {
                        outputSerializationFormat = SyncSerializationFormat.ODataJson;
                    }

                    // If the default header has been set explicitly then no need to read other headers
                    if (outputSerializationFormat == defaultSerializationFormat)
                    {
                        break;
                    }

                    // Is this header application/* or */*
                    if ((null == outputSerializationFormat) &&
                        (headerStringParts[0].Equals(CONTENT_TYPE_APPLICATION_ANY) || headerStringParts[0].Equals(CONTENT_TYPE_ANY)))
                    {
                        // Do not exit the loop as this can be overwritten by an explicit json or atnm+xml header
                        outputSerializationFormat = defaultSerializationFormat;
                    }
                }

                if (null == outputSerializationFormat)
                {
                    throw SyncServiceException.CreateNotAcceptable(Strings.UnsupportedAcceptHeaderValue);
                }

                return(outputSerializationFormat.Value);
            }

            // return the default serialization format.
            return(defaultSerializationFormat);
        }