コード例 #1
0
        /// <summary>
        /// Method that performs a download. It gets the server blob anchor from the local provider and then creates an
        /// CacheRequest object for that download request. It then passes the processing asynchronously to the underlying
        /// CacheRequestHandler.
        /// </summary>
        void EnqueueDownloadRequest()
        {
            try
            {
                // Create a SyncRequest for download.
                CacheRequest request = new CacheRequest()
                {
                    Format        = this.ControllerBehavior.SerializationFormat,
                    RequestType   = CacheRequestType.DownloadChanges,
                    KnowledgeBlob = this.LocalProvider.GetServerBlob()
                };

                this._cacheRequestHandler.ProcessCacheRequestAsync(request, null /*state is null*/);
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }
                // Error. EndSession refresh and post callback
                CompleteAsyncWithException(e);
            }
        }
コード例 #2
0
        /// <summary>
        /// Method that does the actual processing.
        /// 1. It first creates an HttpWebRequest
        /// 2. Fills in the required method type and parameters.
        /// 3. Attaches the user specified ICredentials.
        /// 4. Serializes the input params (Server blob for downloads and input feed for uploads)
        /// 5. If user has specified an BeforeSendingRequest callback then invokes it
        /// 6. Else proceeds to issue the request
        /// </summary>
        /// <param name="wrapper">AsyncArgsWrapper object</param>
        void ProcessRequest(AsyncArgsWrapper wrapper)
        {
            try
            {
                StringBuilder requestUri = new StringBuilder();
                requestUri.AppendFormat("{0}{1}{2}/{3}",
                                        base.BaseUri,
                                        (base.BaseUri.ToString().EndsWith("/")) ? string.Empty : "/",
                                        Uri.EscapeUriString(base.ScopeName),
                                        wrapper.CacheRequest.RequestType.ToString());

                string prefix = "?";
                // Add the scope params if any
                foreach (KeyValuePair <string, string> kvp in this._scopeParameters)
                {
                    requestUri.AppendFormat("{0}{1}={2}", prefix, Uri.EscapeUriString(kvp.Key), Uri.EscapeUriString(kvp.Value));
                    if (prefix.Equals("?"))
                    {
                        prefix = "&";
                    }
                }

                //requestUri.AppendFormat("{0}{1}={2}", prefix, Uri.EscapeUriString("user"), Uri.EscapeUriString("test"));
                //requestUri.AppendFormat("{0}{1}={2}", "&", Uri.EscapeUriString("pwd"), Uri.EscapeUriString("test"));

                // CreateInstance the WebRequest
                HttpWebRequest webRequest = null;

                if (this._credentials != null)
                {
                    // CreateInstance the Client Http request
                    //webRequest = (HttpWebRequest)WebRequestCreator.ClientHttp.CreateInstance(new Uri(requestUri.ToString()));
                    webRequest = (HttpWebRequest)HttpWebRequest.Create(new Uri(requestUri.ToString().ToCurrentScheme(ApplicationContext.Current.Settings.HttpsDisabled)));

                    NetworkCredential credential = this._credentials.GetCredential(BaseUri, "Basic");

                    // Add credentials
                    webRequest.Credentials = this._credentials;

                    string svcCredentials =
                        Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(credential.UserName + ":" + credential.Password));
                    webRequest.Headers.Add("Authorization", "Basic " + svcCredentials);

                    webRequest.Headers.Add("configname:" + behaviors.ConfigName);
                    webRequest.Headers.Add("configversion:" + behaviors.ConfigVersion);

                    webRequest.Headers.Add("coreversion", behaviors.CoreVersion.ToString());
                }
                else
                {
                    // Use WebRequest.CreateInstance the request. This uses any user defined prefix preferences for certain paths
                    webRequest = (HttpWebRequest)WebRequest.Create(requestUri.ToString().ToCurrentScheme(ApplicationContext.Current.Settings.HttpsDisabled));
                }

                foreach (var item in behaviors.DeviceInfo)
                {
                    webRequest.Headers.Add(item.Key, item.Value);
                }

                webRequest.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
                webRequest.Timeout = 5000;

                // Set the method type
                //webRequest.Timeout = 10;
                //webRequest.ReadWriteTimeout = 10;
                webRequest.Method      = "POST";
                webRequest.Accept      = ApplicationContext.Current.Settings.BitMobileFormatterDisabled ? "application/atom+xml" : "application/bitmobile";
                webRequest.ContentType = ApplicationContext.Current.Settings.BitMobileFormatterDisabled ? "application/atom+xml" : "application/bitmobile";

                wrapper.WebRequest = webRequest;

                var requestData = new TimeoutRequestData()
                {
                    Request = wrapper.WebRequest
                };

                // Get the request stream
                if (wrapper.CacheRequest.RequestType == CacheRequestType.UploadChanges)
                {
                    lock (_timeoutSync)
                    {
                        IAsyncResult resultUpload = webRequest.BeginGetRequestStream(OnUploadGetRequestStreamCompleted, wrapper);
                        requestData.Handle = ThreadPool.RegisterWaitForSingleObject(resultUpload.AsyncWaitHandle,
                                                                                    new WaitOrTimerCallback(TimeOutCallback), requestData, TIMEOUT, true);
                    }
                }
                else
                {
                    lock (_timeoutSync)
                    {
                        IAsyncResult resultDownload = webRequest.BeginGetRequestStream(OnDownloadGetRequestStreamCompleted, wrapper);
                        requestData.Handle = ThreadPool.RegisterWaitForSingleObject(resultDownload.AsyncWaitHandle,
                                                                                    new WaitOrTimerCallback(TimeOutCallback), requestData, TIMEOUT, true);
                    }
                }
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }
                wrapper.Error = e;
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
        }
コード例 #3
0
        /// <summary>
        /// Called whenever the CacheRequestHandler proceeses an upload/download request. It is also responsible for
        /// issuing another request if it wasnt the last batch. In case of receiving an Upload response it calls the
        /// underlying provider with the status of the upload. In case of Download it notifies the local provider of the
        /// changes that it needs to save.
        /// </summary>
        /// <param name="sender">Object invoking this method. Usually its the CacheRequestHandler</param>
        /// <param name="e">The result of processing the CacheRequest</param>
        void ProcessCacheRequestCompleted(object sender, ProcessCacheRequestCompletedEventArgs e)
        {
            try
            {
                if (e.Error != null)
                {
                    // Check to see if it was a UploadRequest in which case we will have to call OnChangeSetUploaded
                    // with error to reset the dirty bits.
                    if (e.ChangeSetResponse != null)
                    {
                        // its an response to a upload
                        this._localProvider.OnChangeSetUploaded(e.Id, e.ChangeSetResponse);
                    }

                    // Finally complete Refresh with error.
                    CompleteAsyncWithException(e.Error);
                }
                else if (e.ChangeSetResponse != null)
                {
                    // its an response to a upload
                    this._localProvider.OnChangeSetUploaded(e.Id, e.ChangeSetResponse);

                    if (e.ChangeSetResponse.Error != null)
                    {
                        CompleteAsyncWithException(e.ChangeSetResponse.Error);
                        return;
                    }

                    // Increment the ChangeSets uploaded count
                    refreshStats.TotalChangeSetsUploaded++;
                    refreshStats.TotalUploads += (uint)e.BatchUploadCount;

                    // Update refresh stats
                    e.ChangeSetResponse.ConflictsInternal.ForEach((e1) =>
                    {
                        if (e1 is SyncConflict)
                        {
                            this.refreshStats.TotalSyncConflicts++;
                        }
                        else
                        {
                            this.refreshStats.TotalSyncErrors++;
                        }
                    });

                    // Dont enqueue another request if its been cancelled
                    if (!this.Cancelled)
                    {
                        if (!((bool)e.State))
                        {
                            // Check to see if this was the last batch or else enqueue another pending Upload request
                            this.EnqueueUploadRequest();
                        }
                        else
                        {
                            // That was the last batch. Issue an Download request
                            this.EnqueueDownloadRequest();
                        }
                    }
                    else
                    {
                        // This will process the queued Cancellation request
                        this._asyncWorkManager.CheckAndSendCancellationNotice();
                    }
                }
                else // It means its an Download response
                {
                    Debug.Assert(e.ChangeSet != null, "Completion is not for a download request.");

                    // Increment the refresh stats
                    this.refreshStats.TotalChangeSetsDownloaded++;
                    this.refreshStats.TotalDownloads += (uint)e.ChangeSet.Data.Count;

                    this.LocalProvider.SaveChangeSet(e.ChangeSet);

                    // Dont enqueue another request if its been cancelled
                    if (!this.Cancelled)
                    {
                        if (!e.ChangeSet.IsLastBatch)
                        {
                            // Enqueue the next download
                            this.EnqueueDownloadRequest();
                        }
                        else
                        {
                            // Uploads and downloads are done. Mark the session as complete
                            this._asyncWorkManager.EndChainedAsyncSession();
                            this._asyncWorkManager.CompleteWorkRequest(this._refreshRequestWorker, null);
                        }
                    }
                    else
                    {
                        // This will process the queued Cancellation request
                        this._asyncWorkManager.CheckAndSendCancellationNotice();
                    }
                }
            }
            catch (Exception exp)
            {
                if (ExceptionUtility.IsFatal(exp))
                {
                    throw;
                }
                // Calling in to user code here (OnChangeSetUploaded and SaveChangeSet). Catch exceptions and fail
                CompleteAsyncWithException(exp);
            }
        }
コード例 #4
0
        void OnUploadCompleted(object sender, NSUrlEventArgs e)
        {
            _wrapper.UploadResponse = new ChangeSetResponse();

            FileStream fileStream = null;

            string filePath = null;

            try
            {
                if (e.Error == null)
                {
                    string responseDescription = "response is  null";
                    var    response            = (NSHttpUrlResponse)_currentTask.Response;
                    if (response != null)
                    {
                        responseDescription = response.Description;
                    }

                    filePath = e.FilePath.Replace("file://", "").Replace("%20", " ");
                    IIOContext io = IOContext.Current;
                    if (io.Exists(filePath))
                    {
                        fileStream = io.FileStream(filePath, FileMode.Open);
                        fileStream.Seek(0, SeekOrigin.Begin);

                        // CreateInstance the SyncReader
                        if (ApplicationContext.Current.Settings.BitMobileFormatterDisabled)
                        {
                            _syncReader = new ODataAtomReader(fileStream, _knownTypes);
                        }
                        else
                        {
                            _syncReader = new BMReader(fileStream, _knownTypes);
                        }

                        // Read the response
                        while (_syncReader.Next())
                        {
                            switch (_syncReader.ItemType)
                            {
                            case ReaderItemType.Entry:
                                IOfflineEntity entity      = _syncReader.GetItem();
                                IOfflineEntity ackedEntity = entity;
                                string         tempId      = null;

                                if (_syncReader.HasTempId() && _syncReader.HasConflictTempId())
                                {
                                    throw new CacheControllerException(string.Format("Service returned a TempId '{0}' in both live and conflicting entities.",
                                                                                     _syncReader.GetTempId()));
                                }

                                if (_syncReader.HasTempId())
                                {
                                    tempId = _syncReader.GetTempId();
                                    CheckEntityServiceMetadataAndTempIds(entity, tempId);
                                }

                                if (_syncReader.HasConflict())
                                {
                                    Conflict       conflict       = _syncReader.GetConflict();
                                    IOfflineEntity conflictEntity = (conflict is SyncConflict) ?
                                                                    ((SyncConflict)conflict).LosingEntity : ((SyncError)conflict).ErrorEntity;

                                    if (_syncReader.HasConflictTempId())
                                    {
                                        tempId = _syncReader.GetConflictTempId();
                                        CheckEntityServiceMetadataAndTempIds(conflictEntity, tempId);
                                    }

                                    _wrapper.UploadResponse.AddConflict(conflict);

                                    if (_syncReader.HasConflictTempId() && entity.ServiceMetadata.IsTombstone)
                                    {
                                        conflictEntity.ServiceMetadata.IsTombstone = true;
                                        ackedEntity = conflictEntity;
                                    }
                                }

                                if (!String.IsNullOrEmpty(tempId))
                                {
                                    _wrapper.UploadResponse.AddUpdatedItem(ackedEntity);
                                }

                                break;

                            case ReaderItemType.SyncBlob:
                                _wrapper.UploadResponse.ServerBlob = _syncReader.GetServerBlob();
                                break;
                            }
                        }
                    }
                    else
                    {
                        _wrapper.Error = new FileNotFoundException(String.Format("Downloaded data file not found! {0}, Description: {1}", e.FilePath, responseDescription));
                    }
                }
                else
                {
                    var response = _currentTask.Response as NSHttpUrlResponse;
                    HandleError(e.Error, response);
                }

                _workerManager.CompleteWorkRequest(_wrapper.WorkerRequest, _wrapper);
            }
            catch (Exception ex)
            {
                if (ExceptionUtility.IsFatal(ex))
                {
                    throw;
                }

                _wrapper.Error = ex;

                _workerManager.CompleteWorkRequest(_wrapper.WorkerRequest, _wrapper);
            }
            finally
            {
                if (fileStream != null)
                {
                    fileStream.Close();
                }

                if (filePath != null)
                {
                    IOContext.Current.Delete(filePath);
                }
            }
        }
コード例 #5
0
        /// <summary>
        /// Callback for the Upload HttpWebRequest.BeginGetResponse call
        /// </summary>
        private async Task ReadUploadResponse(HttpWebResponse response, AsyncArgsWrapper wrapper)
        {
            try
            {
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    using (Stream responseStream = GetWrappedStream(response))
                    {
                        using (var syncReader = (SerializationFormat == SerializationFormat.ODataAtom)
                            ? new ODataAtomReader(responseStream, this.knownTypes)
                            : (SyncReader) new ODataJsonReader(responseStream, this.knownTypes))
                        {
                            // Read the response
                            await Task.Factory.StartNew(() =>
                            {
                                while (syncReader.Next())
                                {
                                    switch (syncReader.ItemType)
                                    {
                                    case ReaderItemType.Entry:
                                        IOfflineEntity entity      = syncReader.GetItem();
                                        IOfflineEntity ackedEntity = entity;
                                        string tempId = null;

                                        // If conflict only one temp ID should be set
                                        if (syncReader.HasTempId() && syncReader.HasConflictTempId())
                                        {
                                            throw new CacheControllerException(
                                                string.Format(
                                                    "Service returned a TempId '{0}' in both live and conflicting entities.",
                                                    syncReader.GetTempId()));
                                        }

                                        // Validate the live temp ID if any, before adding anything to the offline context
                                        if (syncReader.HasTempId())
                                        {
                                            tempId = syncReader.GetTempId();
                                            CheckEntityServiceMetadataAndTempIds(wrapper, entity, tempId);
                                        }

                                        //  If conflict
                                        if (syncReader.HasConflict())
                                        {
                                            Conflict conflict             = syncReader.GetConflict();
                                            IOfflineEntity conflictEntity = (conflict is SyncConflict)
                                                                                    ? ((SyncConflict)conflict).LosingEntity
                                                                                    : ((SyncError)conflict).ErrorEntity;

                                            // Validate conflict temp ID if any
                                            if (syncReader.HasConflictTempId())
                                            {
                                                tempId = syncReader.GetConflictTempId();
                                                CheckEntityServiceMetadataAndTempIds(wrapper, conflictEntity, tempId);
                                            }

                                            // Add conflict
                                            wrapper.UploadResponse.AddConflict(conflict);

                                            //
                                            // If there is a conflict and the tempId is set in the conflict entity then the client version lost the
                                            // conflict and the live entity is the server version (ServerWins)
                                            //
                                            if (syncReader.HasConflictTempId() && entity.GetServiceMetadata().IsTombstone)
                                            {
                                                //
                                                // This is a ServerWins conflict, or conflict error. The winning version is a tombstone without temp Id
                                                // so there is no way to map the winning entity with a temp Id. The temp Id is in the conflict so we are
                                                // using the conflict entity, which has the PK, to build a tombstone entity used to update the offline context
                                                //
                                                // In theory, we should copy the service metadata but it is the same end result as the service fills in
                                                // all the properties in the conflict entity
                                                //

                                                // Add the conflict entity
                                                conflictEntity.GetServiceMetadata().IsTombstone = true;
                                                ackedEntity = conflictEntity;
                                            }
                                        }

                                        // Add ackedEntity to storage. If ackedEntity is still equal to entity then add non-conflict entity.
                                        if (!String.IsNullOrEmpty(tempId))
                                        {
                                            wrapper.UploadResponse.AddUpdatedItem(ackedEntity);
                                        }
                                        break;

                                    case ReaderItemType.SyncBlob:
                                        wrapper.UploadResponse.ServerBlob = syncReader.GetServerBlob();
                                        break;
                                    }
                                }
                            });


                            if (wrapper.TempIdToEntityMapping != null && wrapper.TempIdToEntityMapping.Count != 0)
                            {
                                // The client sent some inserts which werent ack'd by the service. Throw.
                                var builder =
                                    new StringBuilder(
                                        "Server did not acknowledge with a permanent Id for the following tempId's: ");
                                builder.Append(string.Join(",", wrapper.TempIdToEntityMapping.Keys.ToArray()));
                                throw new CacheControllerException(builder.ToString());
                            }
                        }
                    }
                }
                else
                {
                    wrapper.UploadResponse.Error = new CacheControllerException(
                        string.Format("Remote service returned error status. Status: {0}, Description: {1}",
                                      response.StatusCode,
                                      response.StatusDescription));
                }
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }

                wrapper.Error = e;
            }
        }
コード例 #6
0
        /// <summary>
        /// Callback for the Download HttpWebRequest.beginGetRequestStream. Deserializes the response feed to
        /// retrieve the list of IOfflineEntity objects and constructs an ChangeSet for that.
        /// </summary>
        /// <param name="asyncResult">IAsyncResult object</param>
        void OnDownloadGetResponseCompleted(IAsyncResult asyncResult)
        {
            AsyncArgsWrapper wrapper = asyncResult.AsyncState as AsyncArgsWrapper;

            wrapper.DownloadResponse = new ChangeSet();

            HttpWebResponse response = null;

            try
            {
                try
                {
                    response = wrapper.WebRequest.EndGetResponse(asyncResult) as HttpWebResponse;
                    if (String.IsNullOrEmpty(behaviors.UserId))
                    {
                        behaviors.UserId = response.Headers["userid"];
                    }
                    if (string.IsNullOrWhiteSpace(behaviors.UserEmail))
                    {
                        behaviors.UserEmail = response.Headers["email"];
                    }
                    behaviors.ResourceVersion = response.Headers["resourceversion"];
                }
                catch (WebException we)
                {
                    wrapper.Error = we;
                    // If we get here then it means we completed the request. Return to the original caller
                    this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
                    return;
                }
                catch (SecurityException se)
                {
                    wrapper.Error = se;
                    // If we get here then it means we completed the request. Return to the original caller
                    this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
                    return;
                }

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    behaviors.SaveUserSession();

                    int contentLength = (int)response.ContentLength;

                    if (response.Headers.AllKeys.Contains("unzippedcontentlength"))
                    {
                        string value = response.Headers["unzippedcontentlength"];
                        if (!int.TryParse(value, out contentLength))
                        {
                            throw new WebException("Invalid value of header unzippedcontentlength: " + value);
                        }
                    }

                    Stream responseStream = new ProgressStream(response.GetResponseStream()
                                                               , contentLength
                                                               , behaviors.ReadProgressCallback);

                    // CreateInstance the SyncReader
                    if (ApplicationContext.Current.Settings.BitMobileFormatterDisabled)
                    {
                        _syncReader = new ODataAtomReader(responseStream, _knownTypes);
                    }
                    else
                    {
                        _syncReader = new BMReader(responseStream, _knownTypes);
                    }

                    // Read the response
                    wrapper.DownloadResponse.Data = GetDownloadedValues(wrapper);

                    wrapper.WebResponse = response;
                    // Invoke user code on the correct synchronization context.
                    this.FirePostResponseHandler(wrapper);
                }
                else
                {
                    wrapper.Error = new CacheControllerException(
                        string.Format("Remote service returned error status. Status: {0}, Description: {1}",
                                      response.StatusCode,
                                      response.StatusDescription));
                }

                // If we get here then it means we completed the request. Return to the original caller
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }

                wrapper.Error = e;
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
        }
コード例 #7
0
        /// <summary>
        /// Method that performs a download. It gets the server blob anchor from the local provider and then creates an
        /// CacheRequest object for that download request. It then passes the processing asynchronously to the underlying
        /// CacheRequestHandler.
        /// </summary>
        private async Task <CacheRefreshStatistics> EnqueueDownloadRequest(CacheRefreshStatistics statistics,
                                                                           CancellationToken cancellationToken,
                                                                           IProgress <SyncProgressEvent> progress = null)
        {
            try
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                Boolean isLastBatch = false;

                while (!isLastBatch)
                {
                    if (cancellationToken.IsCancellationRequested)
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                    }

                    // Create a SyncRequest for download.
                    CacheRequest request = new CacheRequest
                    {
                        Format        = this.ControllerBehavior.SerializationFormat,
                        RequestType   = CacheRequestType.DownloadChanges,
                        KnowledgeBlob = this.localProvider.GetServerBlob()
                    };

                    // Get Changes
                    DateTime durationStartDate = DateTime.Now;
                    var      requestResult     = await this.cacheRequestHandler.ProcessCacheRequestAsync(
                        request, null, cancellationToken);

                    statistics = await this.ProcessCacheRequestResults(statistics, requestResult, cancellationToken);

                    // Check if we are at the end
                    if (requestResult.ChangeSet == null || requestResult.ChangeSet.IsLastBatch)
                    {
                        isLastBatch = true;
                    }

                    // Reporting progress after get changes from local store
                    if (progress != null)
                    {
                        progress.Report(new SyncProgressEvent(SyncStage.DownloadingChanges, DateTime.Now.Subtract(durationStartDate), true, (requestResult.ChangeSet != null ? requestResult.ChangeSet.Data : null)));
                    }
                }
            }
            catch (OperationCanceledException)
            {
                // Re throw the operation cancelled
                throw;
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }

                statistics.Error = e;
            }

            return(statistics);
        }
コード例 #8
0
        /// <summary>
        /// Callback for the Upload HttpWebRequest.beginGetRequestStream
        /// </summary>
        /// <param name="task">Task representing the future request stream</param>
        async Task OnUploadGetRequestStreamCompleted(Task <Stream> task, AsyncArgsWrapper wrapper)
        {
            try
            {
                Stream requestStream = await task.ConfigureAwait(false);

                // Create a SyncWriter to write the contents
                this._syncWriter = (base.SerializationFormat == SerializationFormat.ODataAtom)
                    ? (SyncWriter) new ODataAtomWriter(base.BaseUri)
                    : (SyncWriter) new ODataJsonWriter(base.BaseUri);

                this._syncWriter.StartFeed(wrapper.CacheRequest.IsLastBatch, wrapper.CacheRequest.KnowledgeBlob ?? new byte[0]);

                foreach (IOfflineEntity entity in wrapper.CacheRequest.Changes)
                {
                    // Skip tombstones that dont have a ID element.
                    if (entity.ServiceMetadata.IsTombstone && string.IsNullOrEmpty(entity.ServiceMetadata.Id))
                    {
                        continue;
                    }

                    string tempId = null;

                    // Check to see if this is an insert. i.e ServiceMetadata.Id is null or empty
                    if (string.IsNullOrEmpty(entity.ServiceMetadata.Id))
                    {
                        if (wrapper.TempIdToEntityMapping == null)
                        {
                            wrapper.TempIdToEntityMapping = new Dictionary <string, IOfflineEntity>();
                        }
                        tempId = Guid.NewGuid().ToString();
                        wrapper.TempIdToEntityMapping.Add(tempId, entity);
                    }

                    this._syncWriter.AddItem(entity, tempId);
                }

                if (base.SerializationFormat == SerializationFormat.ODataAtom)
                {
                    this._syncWriter.WriteFeed(XmlWriter.Create(requestStream));
                }
                else
                {
                    this._syncWriter.WriteFeed(JsonReaderWriterFactory.CreateJsonWriter(requestStream));
                }

                requestStream.Flush();
                requestStream.Close();

                if (this._beforeRequestHandler != null)
                {
                    // Invoke user code and wait for them to call back us when they are done with the input request
                    this._workerManager.PostProgress(wrapper.WorkerRequest, this.FirePreRequestHandler, wrapper);
                }
                else
                {
                    this.GetWebResponse(wrapper);
                }
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }
                wrapper.Error = e;
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
        }
コード例 #9
0
        /// <summary>
        /// Callback for the Upload HttpWebRequest.BeginGetResponse call
        /// </summary>
        /// <param name="task">IAsyncResult object</param>
        async Task OnUploadGetResponseCompleted(Task <WebResponse> task, AsyncArgsWrapper wrapper)
        {
            wrapper.UploadResponse = new ChangeSetResponse();

            HttpWebResponse response = null;

            try
            {
                try
                {
                    response = await task.ConfigureAwait(false) as HttpWebResponse;
                }
                catch (WebException we)
                {
                    wrapper.UploadResponse.Error = we;
                    // If we get here then it means we completed the request. Return to the original caller
                    this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
                    return;
                }
                catch (SecurityException se)
                {
                    wrapper.UploadResponse.Error = se;
                    // If we get here then it means we completed the request. Return to the original caller
                    this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
                    return;
                }

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    Stream responseStream = response.GetResponseStream();

                    // Create the SyncReader
                    this._syncReader = (base.SerializationFormat == ClientServices.SerializationFormat.ODataAtom)
                        ? (SyncReader) new ODataAtomReader(responseStream, this._knownTypes)
                        : (SyncReader) new ODataJsonReader(responseStream, this._knownTypes);

                    // Read the response
                    while (this._syncReader.Next())
                    {
                        switch (this._syncReader.ItemType)
                        {
                        case ReaderItemType.Entry:
                            IOfflineEntity entity      = this._syncReader.GetItem();
                            IOfflineEntity ackedEntity = entity;
                            string         tempId      = null;

                            // If conflict only one temp ID should be set
                            if (this._syncReader.HasTempId() && this._syncReader.HasConflictTempId())
                            {
                                throw new CacheControllerException(string.Format("Service returned a TempId '{0}' in both live and conflicting entities.",
                                                                                 this._syncReader.GetTempId()));
                            }

                            // Validate the live temp ID if any, before adding anything to the offline context
                            if (this._syncReader.HasTempId())
                            {
                                tempId = this._syncReader.GetTempId();
                                CheckEntityServiceMetadataAndTempIds(wrapper, entity, tempId);
                            }

                            //  If conflict
                            if (this._syncReader.HasConflict())
                            {
                                Conflict       conflict       = this._syncReader.GetConflict();
                                IOfflineEntity conflictEntity = (conflict is SyncConflict) ?
                                                                ((SyncConflict)conflict).LosingEntity : ((SyncError)conflict).ErrorEntity;

                                // Validate conflict temp ID if any
                                if (this._syncReader.HasConflictTempId())
                                {
                                    tempId = this._syncReader.GetConflictTempId();
                                    CheckEntityServiceMetadataAndTempIds(wrapper, conflictEntity, tempId);
                                }

                                // Add conflict
                                wrapper.UploadResponse.AddConflict(conflict);

                                //
                                // If there is a conflict and the tempId is set in the conflict entity then the client version lost the
                                // conflict and the live entity is the server version (ServerWins)
                                //
                                if (this._syncReader.HasConflictTempId() && entity.ServiceMetadata.IsTombstone)
                                {
                                    //
                                    // This is a ServerWins conflict, or conflict error. The winning version is a tombstone without temp Id
                                    // so there is no way to map the winning entity with a temp Id. The temp Id is in the conflict so we are
                                    // using the conflict entity, which has the PK, to build a tombstone entity used to update the offline context
                                    //
                                    // In theory, we should copy the service metadata but it is the same end result as the service fills in
                                    // all the properties in the conflict entity
                                    //

                                    // Add the conflict entity
                                    conflictEntity.ServiceMetadata.IsTombstone = true;
                                    ackedEntity = conflictEntity;
                                }
                            }

                            // Add ackedEntity to storage. If ackedEntity is still equal to entity then add non-conflict entity.
                            if (!String.IsNullOrEmpty(tempId))
                            {
                                wrapper.UploadResponse.AddUpdatedItem(ackedEntity);
                            }
                            break;

                        case ReaderItemType.SyncBlob:
                            wrapper.UploadResponse.ServerBlob = this._syncReader.GetServerBlob();
                            break;
                        }
                    }

                    if (wrapper.TempIdToEntityMapping != null && wrapper.TempIdToEntityMapping.Count != 0)
                    {
                        // The client sent some inserts which werent ack'd by the service. Throw.
                        StringBuilder builder = new StringBuilder("Server did not acknowledge with a permanent Id for the following tempId's: ");
                        builder.Append(string.Join(",", wrapper.TempIdToEntityMapping.Keys.ToArray()));
                        throw new CacheControllerException(builder.ToString());
                    }

                    wrapper.WebResponse = response;
                    // Invoke user code on the correct synchronization context.
                    this.FirePostResponseHandler(wrapper);
                }
                else
                {
                    wrapper.UploadResponse.Error = new CacheControllerException(
                        string.Format("Remote service returned error status. Status: {0}, Description: {1}",
                                      response.StatusCode,
                                      response.StatusDescription));
                }

                // If we get here then it means we completed the request. Return to the original caller
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }

                wrapper.Error = e;
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
        }
コード例 #10
0
        void OnUploadCompleted(object sender, NSUrlEventArgs e)
        {
            _wrapper.UploadResponse = new ChangeSetResponse();

            FileStream fileStream = null;

            string filePath = null;

            try {
                if (e.Error == null)
                {
                    string            responseDescription = "response is  null";
                    NSHttpUrlResponse response            = (NSHttpUrlResponse)_currentTask.Response;
                    if (response != null)
                    {
                        responseDescription = response.Description;
                    }

                    filePath = e.FilePath.Replace("file://", "").Replace("%20", " ");
                    if (File.Exists(filePath))
                    {
                        fileStream = File.OpenRead(filePath);
                        fileStream.Seek(0, SeekOrigin.Begin);

                        // Create the SyncReader
                        _syncReader = (SyncReader) new ODataAtomReader(fileStream, _knownTypes);

                        // Read the response
                        while (_syncReader.Next())
                        {
                            switch (_syncReader.ItemType)
                            {
                            case ReaderItemType.Entry:
                                IOfflineEntity entity      = _syncReader.GetItem();
                                IOfflineEntity ackedEntity = entity;
                                string         tempId      = null;

                                if (_syncReader.HasTempId() && _syncReader.HasConflictTempId())
                                {
                                    throw new CacheControllerException(string.Format("Service returned a TempId '{0}' in both live and conflicting entities.",
                                                                                     _syncReader.GetTempId()));
                                }

                                if (_syncReader.HasTempId())
                                {
                                    tempId = _syncReader.GetTempId();
                                    CheckEntityServiceMetadataAndTempIds(entity, tempId);
                                }

                                if (_syncReader.HasConflict())
                                {
                                    Conflict       conflict       = _syncReader.GetConflict();
                                    IOfflineEntity conflictEntity = (conflict is SyncConflict) ?
                                                                    ((SyncConflict)conflict).LosingEntity : ((SyncError)conflict).ErrorEntity;

                                    if (this._syncReader.HasConflictTempId())
                                    {
                                        tempId = _syncReader.GetConflictTempId();
                                        CheckEntityServiceMetadataAndTempIds(conflictEntity, tempId);
                                    }

                                    _wrapper.UploadResponse.AddConflict(conflict);

                                    if (_syncReader.HasConflictTempId() && entity.ServiceMetadata.IsTombstone)
                                    {
                                        conflictEntity.ServiceMetadata.IsTombstone = true;
                                        ackedEntity = conflictEntity;
                                    }
                                }

                                if (!String.IsNullOrEmpty(tempId))
                                {
                                    _wrapper.UploadResponse.AddUpdatedItem(ackedEntity);
                                }

                                break;

                            case ReaderItemType.SyncBlob:
                                _wrapper.UploadResponse.ServerBlob = _syncReader.GetServerBlob();
                                break;
                            }
                        }

                        if (_wrapper.TempIdToEntityMapping != null && _wrapper.TempIdToEntityMapping.Count != 0)
                        {
                            StringBuilder builder = new StringBuilder("Server did not acknowledge with a permanent Id for the following tempId's: ");
                            builder.Append(string.Join(",", _wrapper.TempIdToEntityMapping.Keys.ToArray()));
                            throw new CacheControllerException(builder.ToString());
                        }
                    }
                    else
                    {
                        _wrapper.Error = new FileNotFoundException(String.Format("Downloaded data file not found! {0}, Description: {1}", e.FilePath, responseDescription));
                    }
                }
                else
                {
                    NSHttpUrlResponse response = _currentTask.Response as NSHttpUrlResponse;
                    HandleError(e.Error, response);
                }

                _workerManager.CompleteWorkRequest(_wrapper.WorkerRequest, _wrapper);
            } catch (Exception ex) {
                if (ExceptionUtility.IsFatal(ex))
                {
                    throw ex;
                }

                _wrapper.Error = ex;

                _workerManager.CompleteWorkRequest(_wrapper.WorkerRequest, _wrapper);
            } finally {
                if (fileStream != null)
                {
                    fileStream.Close();
                }

                if (filePath != null && File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
            }
        }
コード例 #11
0
        void OnDownloadCompleted(object sender, NSUrlEventArgs e)
        {
            FileStream fileStream = null;
            string     filePath   = null;

            try {
                if (e.Error == null)
                {
                    filePath = e.FilePath.Replace("file://", "").Replace("%20", " ");

                    NSHttpUrlResponse response = (NSHttpUrlResponse)_currentTask.Response;
                    if (response != null)
                    {
                        HttpStatusCode code = (HttpStatusCode)response.StatusCode;
                        if (code == HttpStatusCode.OK)
                        {
                            NSDictionary headers = response.AllHeaderFields;
                            if (string.IsNullOrWhiteSpace(_behaviors.UserId))
                            {
                                _behaviors.UserId = headers ["userid"].ToString();
                            }
                            if (string.IsNullOrWhiteSpace(_behaviors.UserEmail))
                            {
                                _behaviors.UserEmail = headers ["email"].ToString();
                            }
                            ;
                            _behaviors.SaveUserSession();

                            if (File.Exists(filePath))
                            {
                                fileStream = File.OpenRead(filePath);

                                fileStream.Seek(0, SeekOrigin.Begin);
                                int contentLength;
                                if (!int.TryParse(headers ["unzippedcontentlength"].ToString(), out contentLength))
                                {
                                    contentLength = -1;
                                }
                                Stream responseStream = new ProgressStream(fileStream, contentLength, _behaviors.ReadProgressCallback);

                                // Create the SyncReader
                                _syncReader = (SyncReader) new ODataAtomReader(responseStream, _knownTypes);

                                _wrapper.DownloadResponse = new ChangeSet();

                                // Read the response
                                while (this._syncReader.Next())
                                {
                                    switch (this._syncReader.ItemType)
                                    {
                                    case ReaderItemType.Entry:
                                        _wrapper.DownloadResponse.AddItem(_syncReader.GetItem());
                                        break;

                                    case ReaderItemType.SyncBlob:
                                        _wrapper.DownloadResponse.ServerBlob = _syncReader.GetServerBlob();
                                        break;

                                    case ReaderItemType.HasMoreChanges:
                                        _wrapper.DownloadResponse.IsLastBatch = !_syncReader.GetHasMoreChangesValue();
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                _wrapper.Error = new FileNotFoundException(String.Format("Downloaded data file not found! {0}, Description: {1}", e.FilePath, response.Description));
                            }
                        }
                        else
                        {
                            _wrapper.Error = new CacheControllerWebException(string.Format("Remote service returned error status. Status: {0}, Description: {1}", code, response.Description), code);
                        }
                    }
                    else
                    {
                        _wrapper.Error = new CacheControllerException("Response is null");
                    }
                }
                else
                {
                    NSHttpUrlResponse response = _currentTask.Response as NSHttpUrlResponse;
                    HandleError(e.Error, response);
                }

                // If we get here then it means we completed the request. Return to the original caller
                _workerManager.CompleteWorkRequest(_wrapper.WorkerRequest, _wrapper);
            } catch (Exception ex) {
                if (ExceptionUtility.IsFatal(ex))
                {
                    throw;
                }

                _wrapper.Error = ex;

                _workerManager.CompleteWorkRequest(_wrapper.WorkerRequest, _wrapper);
            } finally {
                if (fileStream != null)
                {
                    fileStream.Close();
                }

                if (filePath != null && File.Exists(filePath))
                {
                    File.Delete(filePath);
                }
            }
        }
コード例 #12
0
        void ProcessRequest()
        {
            try {
                StringBuilder requestUri = new StringBuilder();
                requestUri.AppendFormat("{0}{1}{2}/{3}",
                                        base.BaseUri,
                                        (base.BaseUri.ToString().EndsWith("/")) ? string.Empty : "/",
                                        Uri.EscapeUriString(base.ScopeName),
                                        _wrapper.CacheRequest.RequestType.ToString());

                string prefix = "?";

                // Add the scope params if any
                foreach (KeyValuePair <string, string> kvp in _scopeParameters)
                {
                    requestUri.AppendFormat("{0}{1}={2}", prefix, Uri.EscapeUriString(kvp.Key), Uri.EscapeUriString(kvp.Value));
                    if (prefix.Equals("?"))
                    {
                        prefix = "&";
                    }
                }

                // Create the WebRequest
                NSMutableUrlRequest webRequest = new NSMutableUrlRequest(new NSUrl(requestUri.ToString()));
                if (this._credentials != null)
                {
                    NetworkCredential credential     = this._credentials.GetCredential(BaseUri, "Basic");
                    string            svcCredentials = Convert.ToBase64String(ASCIIEncoding.ASCII.GetBytes(credential.UserName + ":" + credential.Password));
                    webRequest ["Authorization"] = "Basic " + svcCredentials;

                    webRequest ["configname"]    = _behaviors.ConfigName;
                    webRequest ["configversion"] = _behaviors.ConfigVersion;

                    webRequest ["coreversion"] = _behaviors.CoreVersion.ToString();
                }
                else
                {
                    throw new Exception("Credentials is null");
                }

                foreach (var item in _behaviors.DeviceInfo)
                {
                    webRequest [item.Key] = item.Value;
                }

                webRequest.HttpMethod          = "POST";
                webRequest ["Accept"]          = (base.SerializationFormat == SerializationFormat.ODataAtom) ? "application/atom+xml" : "application/json";
                webRequest ["Content-Type"]    = (base.SerializationFormat == SerializationFormat.ODataAtom) ? "application/atom+xml" : "application/json";
                webRequest ["Accept-Encoding"] = "gzip, deflate";
                webRequest.TimeoutInterval     = TIMEOUT;

                webRequest.Body = CreateRequestBody();

                _wrapper.WebRequest = webRequest;

                if (_wrapper.CacheRequest.RequestType == CacheRequestType.UploadChanges)
                {
                    lock (_lockObject) {
                        _currentTask = CreateUploadSession().CreateDownloadTask(webRequest);
                        _currentTask.Resume();
                    }
                }
                else
                {
                    lock (_lockObject) {
                        _currentTask = CreateDownloadSession().CreateDownloadTask(webRequest);
                        _currentTask.Resume();
                    }
                }
            } catch (Exception e) {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }

                _wrapper.Error = e;

                _workerManager.CompleteWorkRequest(_wrapper.WorkerRequest, _wrapper);
            }
        }
コード例 #13
0
        /// <summary>
        /// Method that does the actual processing.
        /// 1. It first creates an HttpWebRequest
        /// 2. Fills in the required method type and parameters.
        /// 3. Attaches the user specified ICredentials.
        /// 4. Serializes the input params (Server blob for downloads and input feed for uploads)
        /// 5. If user has specified an BeforeSendingRequest callback then invokes it
        /// 6. Else proceeds to issue the request
        /// </summary>
        /// <param name="wrapper">AsyncArgsWrapper object</param>
        /// <param name="cancellationToken"> </param>
        private async Task <AsyncArgsWrapper> ProcessRequest(AsyncArgsWrapper wrapper,
                                                             CancellationToken cancellationToken)
        {
            HttpWebResponse webResponse = null;

            try
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                var requestUri = new StringBuilder();
                requestUri.AppendFormat("{0}{1}{2}/{3}",
                                        BaseUri,
                                        (BaseUri.ToString().EndsWith("/")) ? string.Empty : "/",
                                        Uri.EscapeUriString(ScopeName),
                                        wrapper.CacheRequest.RequestType.ToString());

                string prefix = "?";
                // Add the scope params if any
                foreach (var kvp in scopeParameters)
                {
                    requestUri.AppendFormat("{0}{1}={2}", prefix, Uri.EscapeUriString(kvp.Key),
                                            Uri.EscapeUriString(kvp.Value));
                    if (prefix.Equals("?"))
                    {
                        prefix = "&";
                    }
                }

                // Create the WebRequest
                HttpWebRequest webRequest;

                if (credentials != null)
                {
                    // Create the Client Http request
                    webRequest = WebRequest.CreateHttp(new Uri(requestUri.ToString()));
                    // Add credentials
                    webRequest.Credentials = credentials;
                }
                else
                {
                    // Use WebRequest.Create the request. This uses any user defined prefix preferences for certain paths
                    webRequest = (HttpWebRequest)WebRequest.Create(requestUri.ToString());
                }

                // Set the method type
                webRequest.Method = "POST";
                webRequest.Accept = (SerializationFormat == SerializationFormat.ODataAtom)
                                        ? "application/atom+xml"
                                        : "application/json";
                webRequest.ContentType = (SerializationFormat == SerializationFormat.ODataAtom)
                                             ? "application/atom+xml"
                                             : "application/json";


                // Write on the stream
#if !NETFX_CORE
                using (Stream stream = await Task.Factory.FromAsync <Stream>(
                           webRequest.BeginGetRequestStream,
                           webRequest.EndGetRequestStream, null))
#else
                using (Stream stream = await webRequest.GetRequestStreamAsync())
#endif
                {
                    if (wrapper.CacheRequest.RequestType == CacheRequestType.UploadChanges)
                    {
                        WriteUploadRequestStream(stream, wrapper);
                    }
                    else
                    {
                        WriteDownloadRequestStream(stream, wrapper);
                    }
                }

                // If error, return wrapper with error
                if (wrapper.Error != null)
                {
                    return(wrapper);
                }

                // Get Response
                if (wrapper.CacheRequest.RequestType == CacheRequestType.UploadChanges)
                {
                    wrapper.UploadResponse = new ChangeSetResponse();
                }
                else
                {
                    wrapper.DownloadResponse = new ChangeSet();
                }

#if !NETFX_CORE
                webResponse = (HttpWebResponse)(await Task.Factory.FromAsync <WebResponse>(
                                                    webRequest.BeginGetResponse,
                                                    webRequest.EndGetResponse, null));
#else
                webResponse = (HttpWebResponse)(await webRequest.GetResponseAsync());
#endif

                if (wrapper.CacheRequest.RequestType == CacheRequestType.UploadChanges)
                {
                    await ReadUploadResponse(webResponse, wrapper);
                }
                else
                {
                    await ReadDownloadResponse(webResponse, wrapper);
                }
            }
            catch (WebException we)
            {
                if (we.Response == null)
                {
                    wrapper.Error = we;
                }
                else
                {
                    var stream = we.Response.GetResponseStream();

                    var reader = SerializationFormat == SerializationFormat.ODataAtom ?
                                 XmlReader.Create(stream) :
                                 new XmlJsonReader(stream, XmlDictionaryReaderQuotas.Max);

                    if (reader.ReadToDescendant(FormatterConstants.ErrorDescriptionElementNamePascalCasing))
                    {
                        wrapper.Error = new Exception(reader.ReadElementContentAsString());
                    }
                }
            }
            catch (OperationCanceledException)
            {
                // Re throw the operation cancelled
                throw;
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }

                wrapper.Error = e;
                return(wrapper);
            }

            return(wrapper);
        }
コード例 #14
0
        void OnDownloadCompleted(object sender, NSUrlEventArgs e)
        {
            try
            {
                if (e.Error == null)
                {
                    _filePath = e.FilePath.Replace("file://", "").Replace("%20", " ");

                    NSHttpUrlResponse response = (NSHttpUrlResponse)_currentTask.Response;
                    if (response != null)
                    {
                        HttpStatusCode code = (HttpStatusCode)response.StatusCode;
                        if (code == HttpStatusCode.OK)
                        {
                            NSDictionary headers = response.AllHeaderFields;
                            if (string.IsNullOrWhiteSpace(_behaviors.UserId))
                            {
                                _behaviors.UserId = headers["userid"].ToString();
                            }
                            if (string.IsNullOrWhiteSpace(_behaviors.UserEmail))
                            {
                                _behaviors.UserEmail = headers["email"].ToString();
                            }
                            _behaviors.ResourceVersion = headers["resourceversion"].ToString();

                            _behaviors.SaveUserSession();

                            IIOContext io = IOContext.Current;
                            if (io.Exists(_filePath))
                            {
                                FileStream fileStream = io.FileStream(_filePath, FileMode.Open);

                                fileStream.Seek(0, SeekOrigin.Begin);
                                int contentLength;
                                if (!int.TryParse(headers["unzippedcontentlength"].ToString(), out contentLength))
                                {
                                    contentLength = -1;
                                }
                                Stream responseStream = new ProgressStream(fileStream, contentLength, _behaviors.ReadProgressCallback);

                                // CreateInstance the SyncReader
                                if (ApplicationContext.Current.Settings.BitMobileFormatterDisabled)
                                {
                                    _syncReader = new ODataAtomReader(responseStream, _knownTypes);
                                }
                                else
                                {
                                    _syncReader = new BMReader(responseStream, _knownTypes);
                                }

                                _wrapper.DownloadResponse      = new ChangeSet();
                                _wrapper.DownloadResponse.Data = GetDownloadedValues(_wrapper);
                            }
                            else
                            {
                                _wrapper.Error = new FileNotFoundException(String.Format("Downloaded data file not found! {0}, Description: {1}", e.FilePath, response.Description));
                            }
                        }
                        else
                        {
                            _wrapper.Error = new CacheControllerWebException(string.Format("Remote service returned error status. Status: {0}, Description: {1}", code, response.Description), code);
                        }
                    }
                    else
                    {
                        _wrapper.Error = new CacheControllerException("Response is null");
                    }
                }
                else
                {
                    var response = _currentTask.Response as NSHttpUrlResponse;
                    HandleError(e.Error, response);
                }

                // If we get here then it means we completed the request. Return to the original caller
                _workerManager.CompleteWorkRequest(_wrapper.WorkerRequest, _wrapper);
            }
            catch (Exception ex)
            {
                if (ExceptionUtility.IsFatal(ex))
                {
                    throw;
                }

                _wrapper.Error = ex;

                _workerManager.CompleteWorkRequest(_wrapper.WorkerRequest, _wrapper);
            }
        }
コード例 #15
0
        /// <summary>
        /// Callback for the Upload HttpWebRequest.beginGetRequestStream
        /// </summary>
        /// <param name="asyncResult">IAsyncResult object</param>
        void OnUploadGetRequestStreamCompleted(IAsyncResult asyncResult)
        {
            AsyncArgsWrapper wrapper = asyncResult.AsyncState as AsyncArgsWrapper;

            try
            {
                Stream requestStream = wrapper.WebRequest.EndGetRequestStream(asyncResult);

                // CreateInstance a SyncWriter to write the contents

                if (ApplicationContext.Current.Settings.BitMobileFormatterDisabled)
                {
                    _syncWriter = new ODataAtomWriter(BaseUri);
                }
                else
                {
                    _syncWriter = new BMWriter(BaseUri);
                }

                this._syncWriter.StartFeed(wrapper.CacheRequest.IsLastBatch, wrapper.CacheRequest.KnowledgeBlob ?? new byte[0]);

                foreach (IOfflineEntity entity in wrapper.CacheRequest.Changes)
                {
                    var ientity = entity as IEntity;

                    // Skip tombstones that dont have a ID element.
                    if (entity.ServiceMetadata.IsTombstone && string.IsNullOrEmpty(entity.ServiceMetadata.Id))
                    {
                        if (ientity != null)
                        {
                            LogManager.Logger.SyncUpload(ientity.EntityType, true);
                        }
                        continue;
                    }

                    string tempId = null;

                    // Check to see if this is an insert. i.e ServiceMetadata.Id is null or empty
                    if (string.IsNullOrEmpty(entity.ServiceMetadata.Id))
                    {
                        if (wrapper.TempIdToEntityMapping == null)
                        {
                            wrapper.TempIdToEntityMapping = new Dictionary <string, IOfflineEntity>();
                        }
                        tempId = Guid.NewGuid().ToString();
                        wrapper.TempIdToEntityMapping.Add(tempId, entity);
                    }

                    this._syncWriter.AddItem(entity, tempId);

                    if (ientity != null)
                    {
                        LogManager.Logger.SyncUpload(ientity.EntityType);
                    }
                }

                if (base.SerializationFormat == SerializationFormat.ODataAtom)
                {
                    this._syncWriter.WriteFeed(XmlWriter.Create(requestStream));
                }
                else
                {
                    this._syncWriter.WriteFeed(JsonReaderWriterFactory.CreateJsonWriter(requestStream));
                }

                requestStream.Flush();
                requestStream.Close();

                if (this._beforeRequestHandler != null)
                {
                    // Invoke user code and wait for them to call back us when they are done with the input request
                    this._workerManager.PostProgress(wrapper.WorkerRequest, this.FirePreRequestHandler, wrapper);
                }
                else
                {
                    this.GetWebResponse(wrapper);
                }
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }
                wrapper.Error = e;
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
        }
        /// <summary>
        /// Method that does the actual processing.
        /// 1. It first creates an HttpWebRequest
        /// 2. Fills in the required method type and parameters.
        /// 3. Attaches the user specified ICredentials.
        /// 4. Serializes the input params (Server blob for downloads and input feed for uploads)
        /// 5. If user has specified an BeforeSendingRequest callback then invokes it
        /// 6. Else proceeds to issue the request
        /// </summary>
        /// <param name="wrapper">AsyncArgsWrapper object</param>
        void ProcessRequest(AsyncArgsWrapper wrapper)
        {
            try
            {
                StringBuilder requestUri = new StringBuilder();
                requestUri.AppendFormat("{0}{1}{2}/{3}",
                                        base.BaseUri,
                                        (base.BaseUri.ToString().EndsWith("/")) ? string.Empty : "/",
                                        Uri.EscapeUriString(base.ScopeName),
                                        wrapper.CacheRequest.RequestType.ToString());

                string prefix = "?";
                // Add the scope params if any
                foreach (KeyValuePair <string, string> kvp in this._scopeParameters)
                {
                    requestUri.AppendFormat("{0}{1}={2}", prefix, Uri.EscapeUriString(kvp.Key), Uri.EscapeUriString(kvp.Value));
                    if (prefix.Equals("?"))
                    {
                        prefix = "&";
                    }
                }

                // Create the WebRequest
                HttpWebRequest webRequest = null;

                if (this._credentials != null)
                {
                    // Create the Client Http request
                    webRequest = (HttpWebRequest)WebRequestCreator.ClientHttp.Create(new Uri(requestUri.ToString()));
                    // Add credentials
                    webRequest.Credentials = this._credentials;
                }
                else
                {
                    // Use WebRequest.Create the request. This uses any user defined prefix preferences for certain paths
                    webRequest = (HttpWebRequest)WebRequest.Create(requestUri.ToString());
                }

                // Set the method type
                webRequest.Method      = "POST";
                webRequest.Accept      = (base.SerializationFormat == SerializationFormat.ODataAtom) ? "application/atom+xml" : "application/json";
                webRequest.ContentType = (base.SerializationFormat == SerializationFormat.ODataAtom) ? "application/atom+xml" : "application/json";

                wrapper.WebRequest = webRequest;

                // Get the request stream
                if (wrapper.CacheRequest.RequestType == CacheRequestType.UploadChanges)
                {
                    webRequest.BeginGetRequestStream(OnUploadGetRequestStreamCompleted, wrapper);
                }
                else
                {
                    webRequest.BeginGetRequestStream(OnDownloadGetRequestStreamCompleted, wrapper);
                }
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }
                wrapper.Error = e;
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
        }
コード例 #17
0
        /// <summary>
        /// Callback for the Upload HttpWebRequest.BeginGetResponse call
        /// </summary>
        /// <param name="asyncResult">IAsyncResult object</param>
        void OnUploadGetResponseCompleted(IAsyncResult asyncResult)
        {
            AsyncArgsWrapper wrapper = asyncResult.AsyncState as AsyncArgsWrapper;

            wrapper.UploadResponse = new ChangeSetResponse();

            HttpWebResponse response = null;

            try
            {
                try
                {
                    response = wrapper.WebRequest.EndGetResponse(asyncResult) as HttpWebResponse;
                }
                catch (WebException we)
                {
                    wrapper.UploadResponse.Error = we;
                    // If we get here then it means we completed the request. Return to the original caller
                    this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
                    return;
                }
                catch (SecurityException se)
                {
                    wrapper.UploadResponse.Error = se;
                    // If we get here then it means we completed the request. Return to the original caller
                    this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
                    return;
                }

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    Stream responseStream = response.GetResponseStream();

                    // CreateInstance the SyncReader
                    if (ApplicationContext.Current.Settings.BitMobileFormatterDisabled)
                    {
                        _syncReader = new ODataAtomReader(responseStream, _knownTypes);
                    }
                    else
                    {
                        _syncReader = new BMReader(responseStream, _knownTypes);
                    }

                    // Read the response
                    while (this._syncReader.Next())
                    {
                        switch (this._syncReader.ItemType)
                        {
                        case ReaderItemType.Entry:
                            IOfflineEntity entity      = this._syncReader.GetItem();
                            IOfflineEntity ackedEntity = entity;
                            string         tempId      = null;

                            // If conflict only one temp ID should be set
                            if (this._syncReader.HasTempId() && this._syncReader.HasConflictTempId())
                            {
                                throw new CacheControllerException(string.Format("Service returned a TempId '{0}' in both live and conflicting entities.",
                                                                                 this._syncReader.GetTempId()));
                            }

                            // Validate the live temp ID if any, before adding anything to the offline context
                            if (this._syncReader.HasTempId())
                            {
                                tempId = this._syncReader.GetTempId();
                                CheckEntityServiceMetadataAndTempIds(wrapper, entity, tempId);
                            }

                            //  If conflict
                            if (this._syncReader.HasConflict())
                            {
                                Conflict       conflict       = this._syncReader.GetConflict();
                                IOfflineEntity conflictEntity = (conflict is SyncConflict) ?
                                                                ((SyncConflict)conflict).LosingEntity : ((SyncError)conflict).ErrorEntity;

                                // Validate conflict temp ID if any
                                if (this._syncReader.HasConflictTempId())
                                {
                                    tempId = this._syncReader.GetConflictTempId();
                                    CheckEntityServiceMetadataAndTempIds(wrapper, conflictEntity, tempId);
                                }

                                // Add conflict
                                wrapper.UploadResponse.AddConflict(conflict);

                                //
                                // If there is a conflict and the tempId is set in the conflict entity then the client version lost the
                                // conflict and the live entity is the server version (ServerWins)
                                //
                                if (this._syncReader.HasConflictTempId() && entity.ServiceMetadata.IsTombstone)
                                {
                                    //
                                    // This is a ServerWins conflict, or conflict error. The winning version is a tombstone without temp Id
                                    // so there is no way to map the winning entity with a temp Id. The temp Id is in the conflict so we are
                                    // using the conflict entity, which has the PK, to build a tombstone entity used to update the offline context
                                    //
                                    // In theory, we should copy the service metadata but it is the same end result as the service fills in
                                    // all the properties in the conflict entity
                                    //

                                    // Add the conflict entity
                                    conflictEntity.ServiceMetadata.IsTombstone = true;
                                    ackedEntity = conflictEntity;
                                }
                            }

                            // Add ackedEntity to storage. If ackedEntity is still equal to entity then add non-conflict entity.
                            if (!String.IsNullOrEmpty(tempId))
                            {
                                wrapper.UploadResponse.AddUpdatedItem(ackedEntity);
                            }
                            break;

                        case ReaderItemType.SyncBlob:
                            wrapper.UploadResponse.ServerBlob = this._syncReader.GetServerBlob();
                            break;
                        }
                    }

                    wrapper.WebResponse = response;
                    // Invoke user code on the correct synchronization context.
                    this.FirePostResponseHandler(wrapper);
                }
                else
                {
                    wrapper.UploadResponse.Error = new CacheControllerException(
                        string.Format("Remote service returned error status. Status: {0}, Description: {1}",
                                      response.StatusCode,
                                      response.StatusDescription));
                }

                // If we get here then it means we completed the request. Return to the original caller
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }

                wrapper.Error = e;
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
        }
        /// <summary>
        /// Callback for the Download HttpWebRequest.beginGetRequestStream. Deserializes the response feed to
        /// retrieve the list of IOfflineEntity objects and constructs an ChangeSet for that.
        /// </summary>
        /// <param name="asyncResult">IAsyncResult object</param>
        void OnDownloadGetResponseCompleted(IAsyncResult asyncResult)
        {
            AsyncArgsWrapper wrapper = asyncResult.AsyncState as AsyncArgsWrapper;

            wrapper.DownloadResponse = new ChangeSet();

            HttpWebResponse response = null;

            try
            {
                try
                {
                    response = wrapper.WebRequest.EndGetResponse(asyncResult) as HttpWebResponse;
                }
                catch (WebException we)
                {
                    wrapper.Error = we;
                    // If we get here then it means we completed the request. Return to the original caller
                    this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
                    return;
                }
                catch (SecurityException se)
                {
                    wrapper.Error = se;
                    // If we get here then it means we completed the request. Return to the original caller
                    this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
                    return;
                }

                if (response.StatusCode == HttpStatusCode.OK)
                {
                    Stream responseStream = response.GetResponseStream();

                    // Create the SyncReader
                    this._syncReader = (base.SerializationFormat == ClientServices.SerializationFormat.ODataAtom)
                        ? (SyncReader) new ODataAtomReader(responseStream, this._knownTypes)
                        : (SyncReader) new ODataJsonReader(responseStream, this._knownTypes);

                    // Read the response
                    while (this._syncReader.Next())
                    {
                        switch (this._syncReader.ItemType)
                        {
                        case ReaderItemType.Entry:
                            wrapper.DownloadResponse.AddItem(this._syncReader.GetItem());
                            break;

                        case ReaderItemType.SyncBlob:
                            wrapper.DownloadResponse.ServerBlob = this._syncReader.GetServerBlob();
                            break;

                        case ReaderItemType.HasMoreChanges:
                            wrapper.DownloadResponse.IsLastBatch = !this._syncReader.GetHasMoreChangesValue();
                            break;
                        }
                    }

                    wrapper.WebResponse = response;
                    // Invoke user code on the correct synchronization context.
                    this.FirePostResponseHandler(wrapper);
                }
                else
                {
                    wrapper.Error = new CacheControllerException(
                        string.Format("Remote service returned error status. Status: {0}, Description: {1}",
                                      response.StatusCode,
                                      response.StatusDescription));
                }

                // If we get here then it means we completed the request. Return to the original caller
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }

                wrapper.Error = e;
                this._workerManager.CompleteWorkRequest(wrapper.WorkerRequest, wrapper);
            }
        }
コード例 #19
0
        /// <summary>
        /// Method that performs an upload. It gets the ChangeSet from the local provider and then creates an
        /// CacheRequest object for that ChangeSet and then passed the processing asynchronously to the underlying
        /// CacheRequestHandler.
        /// </summary>
        private async Task <CacheRefreshStatistics> EnqueueUploadRequest(CacheRefreshStatistics statistics,
                                                                         CancellationToken cancellationToken,
                                                                         IProgress <SyncProgressEvent> progress = null)
        {
            this.changeSetId = Guid.NewGuid();

            try
            {
                // Check if cancellation has occured
                if (cancellationToken.IsCancellationRequested)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                // Get Changes
                DateTime  durationStartDate = DateTime.Now;
                ChangeSet changeSet         = await this.localProvider.GetChangeSet(this.changeSetId);

                // Reporting progress after get changes from local store
                if (progress != null)
                {
                    progress.Report(new SyncProgressEvent(SyncStage.GetChanges, DateTime.Now.Subtract(durationStartDate), true, (changeSet != null ? changeSet.Data : null)));
                }


                // No data to upload. Skip upload phase.
                if (changeSet == null || changeSet.Data == null || changeSet.Data.Count == 0)
                {
                    return(statistics);
                }

                // Create a SyncRequest out of this.
                CacheRequest request = new CacheRequest
                {
                    RequestId     = this.changeSetId,
                    Format        = this.ControllerBehavior.SerializationFormat,
                    RequestType   = CacheRequestType.UploadChanges,
                    Changes       = changeSet.Data,
                    KnowledgeBlob = changeSet.ServerBlob,
                    IsLastBatch   = changeSet.IsLastBatch
                };


                // Upload changes to server
                durationStartDate = DateTime.Now;
                var requestResult = await this.cacheRequestHandler.ProcessCacheRequestAsync(
                    request, changeSet.IsLastBatch, cancellationToken);

                // Get response from server if mb any conflicts or updated items
                statistics = await this.ProcessCacheRequestResults(statistics, requestResult, cancellationToken);

                // Reporting progress after uploading changes, and mb get back Conflicts and new Id from insterted items
                if (progress != null)
                {
                    progress.Report(new SyncProgressEvent(SyncStage.UploadingChanges, DateTime.Now.Subtract(durationStartDate), true,
                                                          changeSet.Data, requestResult.ChangeSetResponse.Conflicts, requestResult.ChangeSetResponse.UpdatedItems));
                }
            }
            catch (OperationCanceledException)
            {
                // Re throw the operation cancelled
                throw;
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }

                statistics.Error = e;
            }


            return(statistics);
        }
コード例 #20
0
        /// <summary>
        /// Method that does the actual processing.
        /// 1. It first creates an HttpWebRequest
        /// 2. Fills in the required method type and parameters.
        /// 3. Attaches the user specified ICredentials.
        /// 4. Serializes the input params (Server blob for downloads and input feed for uploads)
        /// 5. If user has specified an BeforeSendingRequest callback then invokes it
        /// 6. Else proceeds to issue the request
        /// </summary>
        /// <param name="wrapper">AsyncArgsWrapper object</param>
        /// <param name="cancellationToken"> </param>
        private async Task <AsyncArgsWrapper> ProcessRequest(AsyncArgsWrapper wrapper,
                                                             CancellationToken cancellationToken)
        {
            HttpWebResponse webResponse = null;

            try
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                var requestUri = new StringBuilder();
                requestUri.AppendFormat("{0}{1}{2}/{3}",
                                        BaseUri,
                                        (BaseUri.ToString().EndsWith("/")) ? string.Empty : "/",
                                        Uri.EscapeUriString(ScopeName),
                                        wrapper.CacheRequest.RequestType.ToString());

                string prefix = "?";
                // Add the scope params if any
                foreach (var kvp in scopeParameters)
                {
                    requestUri.AppendFormat("{0}{1}={2}", prefix, Uri.EscapeUriString(kvp.Key),
                                            Uri.EscapeUriString(kvp.Value));
                    if (prefix.Equals("?"))
                    {
                        prefix = "&";
                    }
                }

                // Create the WebRequest
                HttpWebRequest webRequest;

                if (credentials != null)
                {
                    // Create the Client Http request
                    webRequest = WebRequest.CreateHttp(new Uri(requestUri.ToString()));
                    // Add credentials
                    webRequest.Credentials = credentials;
                }
                else
                {
                    // Use WebRequest.Create the request. This uses any user defined prefix preferences for certain paths
                    webRequest = (HttpWebRequest)WebRequest.Create(requestUri.ToString());
                }

                // set cookies if exists
                if (CookieContainer != null)
                {
                    webRequest.CookieContainer = CookieContainer;
                }

                // Set the method type
                webRequest.Method = "POST";
                webRequest.Accept = (SerializationFormat == SerializationFormat.ODataAtom)
                                        ? "application/atom+xml"
                                        : "application/json";
                webRequest.ContentType = (SerializationFormat == SerializationFormat.ODataAtom)
                                             ? "application/atom+xml"
                                             : "application/json";
#if !WINDOWS_PHONE
                if (automaticDecompression)
                {
                    webRequest.Headers["Accept-Encoding"] = "gzip, deflated";
                }
#endif
                foreach (var kvp in customHeaders)
                {
                    webRequest.Headers[kvp.Key] = kvp.Value;
                }
                // To be sure where it could be raise an error, just mark the step
                wrapper.Step = HttpState.WriteRequest;

#if !NETFX_CORE
                using (Stream stream = await Task.Factory.FromAsync <Stream>(
                           webRequest.BeginGetRequestStream,
                           webRequest.EndGetRequestStream, null))
#else
                using (Stream stream = await webRequest.GetRequestStreamAsync())
#endif
                {
                    if (wrapper.CacheRequest.RequestType == CacheRequestType.UploadChanges)
                    {
                        WriteUploadRequestStream(stream, wrapper);
                    }
                    else
                    {
                        WriteDownloadRequestStream(stream, wrapper);
                    }
                }

                // If error, return wrapper with error
                if (wrapper.Error != null)
                {
                    return(wrapper);
                }

                // Get Response
                if (wrapper.CacheRequest.RequestType == CacheRequestType.UploadChanges)
                {
                    wrapper.UploadResponse = new ChangeSetResponse();
                }
                else
                {
                    wrapper.DownloadResponse = new ChangeSet();
                }

                wrapper.Step = HttpState.ReadResponse;

#if !NETFX_CORE
                webResponse = (HttpWebResponse)(await Task.Factory.FromAsync <WebResponse>(
                                                    webRequest.BeginGetResponse,
                                                    webRequest.EndGetResponse, null));
#else
                webResponse = (HttpWebResponse)(await webRequest.GetResponseAsync());
#endif

                if (wrapper.CacheRequest.RequestType == CacheRequestType.UploadChanges)
                {
                    await ReadUploadResponse(webResponse, wrapper);
                }
                else
                {
                    await ReadDownloadResponse(webResponse, wrapper);
                }

                if (webResponse != null)
                {
                    wrapper.Step = HttpState.End;
                    webResponse.Dispose();
                    webResponse = null;
                }
            }
            catch (WebException we)
            {
                // if (we.Response == null)
                // {
                // default to this, there will be cases where the we.Response is != null but the content length = 0
                // e.g 413 and other server errors. e.g the else branch of reader.ReadToDescendent. By defaulting to this
                // we always capture the error rather then returning an error of null in some cases
                wrapper.Error = we;
                //}

                if (we.Response != null)
                {
                    using (var stream = GetWrappedStream(we.Response))
                    {
                        using (var reader = SerializationFormat == SerializationFormat.ODataAtom ?
                                            XmlReader.Create(stream) :
                                            new XmlJsonReader(stream, XmlDictionaryReaderQuotas.Max))
                        {
                            if (reader.ReadToDescendant(FormatterConstants.ErrorDescriptionElementNamePascalCasing))
                            {
                                wrapper.Error = new Exception(reader.ReadElementContentAsString());
                            }
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
                // Re throw the operation cancelled
                throw;
            }
            catch (Exception e)
            {
                if (ExceptionUtility.IsFatal(e))
                {
                    throw;
                }

                wrapper.Error = e;
                return(wrapper);
            }

            return(wrapper);
        }
コード例 #21
0
        /// <summary>
        /// Called whenever the CacheRequestHandler proceeses an upload/download request. It is also responsible for
        /// issuing another request if it wasnt the last batch. In case of receiving an Upload response it calls the
        /// underlying provider with the status of the upload. In case of Download it notifies the local provider of the
        /// changes that it needs to save.
        /// </summary>
        private async Task <CacheRefreshStatistics> ProcessCacheRequestResults(
            CacheRefreshStatistics statistics, CacheRequestResult cacheRequestResult, CancellationToken cancellationToken)
        {
            try
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                #region Error
                if (cacheRequestResult.Error != null)
                {
                    // We have an error but we have a ChangeSetResponse with reading the upload respose
                    // So we can serialize results and update dirty bits
                    if (cacheRequestResult.ChangeSetResponse != null &&
                        cacheRequestResult.HttpStep == HttpState.End)
                    {
                        await this.localProvider.OnChangeSetUploaded(cacheRequestResult.Id, cacheRequestResult.ChangeSetResponse);
                    }

                    // Finally complete Refresh with error.
                    statistics.Error = cacheRequestResult.Error;

                    return(statistics);
                }
                #endregion

                #region Upload response

                if (cacheRequestResult.ChangeSetResponse != null)
                {
                    if (cacheRequestResult.ChangeSetResponse.Error == null &&
                        cacheRequestResult.HttpStep == HttpState.End)
                    {
                        await this.localProvider.OnChangeSetUploaded(cacheRequestResult.Id, cacheRequestResult.ChangeSetResponse);
                    }

                    if (cacheRequestResult.ChangeSetResponse.Error != null)
                    {
                        statistics.Error = cacheRequestResult.ChangeSetResponse.Error;
                        return(statistics);
                    }

                    // Increment the ChangeSets uploaded count
                    statistics.TotalChangeSetsUploaded++;
                    statistics.TotalUploads += cacheRequestResult.BatchUploadCount;

                    // Update refresh stats
                    foreach (var e1 in cacheRequestResult.ChangeSetResponse.ConflictsInternal)
                    {
                        if (e1 is SyncConflict)
                        {
                            statistics.TotalSyncConflicts++;
                        }
                        else
                        {
                            statistics.TotalSyncErrors++;
                        }
                    }

                    return(statistics);
                }
                #endregion

                #region Download Response

                // it's a response to download
                Debug.Assert(cacheRequestResult.ChangeSet != null, "Completion is not for a download request.");

                // Increment the refresh stats
                if (cacheRequestResult.ChangeSet != null && cacheRequestResult.ChangeSet.Data != null && cacheRequestResult.ChangeSet.Data.Count > 0)
                {
                    statistics.TotalChangeSetsDownloaded++;
                    statistics.TotalDownloads += (uint)cacheRequestResult.ChangeSet.Data.Count;

                    await this.localProvider.SaveChangeSet(cacheRequestResult.ChangeSet);
                }

                return(statistics);

                #endregion
            }

            catch (OperationCanceledException)
            {
                // Re throw the operation cancelled
                throw;
            }
            catch (Exception exp)
            {
                if (ExceptionUtility.IsFatal(exp))
                {
                    throw;
                }
                statistics.Error = exp;
            }

            return(statistics);
        }
コード例 #22
0
        /// <summary>
        /// Called whenever the CacheRequestHandler proceeses an upload/download request. It is also responsible for
        /// issuing another request if it wasnt the last batch. In case of receiving an Upload response it calls the
        /// underlying provider with the status of the upload. In case of Download it notifies the local provider of the
        /// changes that it needs to save.
        /// </summary>
        private async Task <CacheRefreshStatistics> ProcessCacheRequestResults(CacheRefreshStatistics statistics, CacheRequestResult e, CancellationToken cancellationToken)
        {
            try
            {
                if (cancellationToken.IsCancellationRequested)
                {
                    cancellationToken.ThrowIfCancellationRequested();
                }

                if (e.Error != null)
                {
                    // Check to see if it was a UploadRequest in which case we will have to call OnChangeSetUploaded
                    // with error to reset the dirty bits.
                    if (e.ChangeSetResponse != null)
                    {
                        // its an response to a upload
                        this.localProvider.OnChangeSetUploaded(e.Id, e.ChangeSetResponse);
                    }

                    // Finally complete Refresh with error.
                    statistics.Error = e.Error;
                }
                else if (e.ChangeSetResponse != null)
                {
                    // its an response to a upload
                    this.localProvider.OnChangeSetUploaded(e.Id, e.ChangeSetResponse);

                    if (e.ChangeSetResponse.Error != null)
                    {
                        statistics.Error = e.ChangeSetResponse.Error;
                        return(statistics);
                    }

                    // Increment the ChangeSets uploaded count
                    statistics.TotalChangeSetsUploaded++;
                    statistics.TotalUploads += e.BatchUploadCount;

                    // Update refresh stats
                    foreach (var e1 in e.ChangeSetResponse.ConflictsInternal)
                    {
                        if (e1 is SyncConflict)
                        {
                            statistics.TotalSyncConflicts++;
                        }
                        else
                        {
                            statistics.TotalSyncErrors++;
                        }
                    }

                    // Dont enqueue another request if its been cancelled
                    if (!cancellationToken.IsCancellationRequested)
                    {
                        if (!((bool)e.State))
                        {
                            // Check to see if this was the last batch or else enqueue another pending Upload request
                            statistics = await this.EnqueueUploadRequest(statistics, cancellationToken);
                        }
                        else
                        {
                            // That was the last batch. Issue an Download request
                            statistics = await this.EnqueueDownloadRequest(statistics, cancellationToken);
                        }
                    }
                    else
                    {
                        cancellationToken.ThrowIfCancellationRequested();
                    }
                }
                else // It means its an Download response
                {
                    Debug.Assert(e.ChangeSet != null, "Completion is not for a download request.");

                    // Increment the refresh stats
                    if (e.ChangeSet != null)
                    {
                        statistics.TotalChangeSetsDownloaded++;
                        statistics.TotalDownloads += (uint)e.ChangeSet.Data.Count;

                        await this.localProvider.SaveChangeSet(e.ChangeSet);

                        // Dont enqueue another request if its been cancelled
                        if (!cancellationToken.IsCancellationRequested)
                        {
                            if (!e.ChangeSet.IsLastBatch)
                            {
                                // Enqueue the next download
                                statistics = await this.EnqueueDownloadRequest(statistics, cancellationToken);
                            }
                        }
                        else
                        {
                            cancellationToken.ThrowIfCancellationRequested();
                        }
                    }
                }
            }
            catch (OperationCanceledException)
            {
                // Re throw the operation cancelled
                throw;
            }
            catch (Exception exp)
            {
                if (ExceptionUtility.IsFatal(exp))
                {
                    throw;
                }
                statistics.Error = exp;
            }

            return(statistics);
        }