예제 #1
0
        private async Task <Tuple <T, KinveyException, int> > HandlePushPUT(PendingWriteAction pwa)
        {
            T               entity          = default(T);
            var             offset          = 0;
            KinveyException kinveyException = null;

            try
            {
                int result = 0;

                var localEntity = Cache.FindByID(pwa.entityId);

                NetworkRequest <T> request = Client.NetworkFactory.buildUpdateRequest <T>(pwa.collection, localEntity, pwa.entityId);
                entity = await request.ExecuteAsync().ConfigureAwait(false);

                Cache.UpdateCacheSave(entity, pwa.entityId);

                result = SyncQueue.Remove(pwa);

                if (result == 0)
                {
                    offset++;
                }
            }
            catch (KinveyException ke)
            {
                kinveyException = ke;
                offset++;
            }

            return(new Tuple <T, KinveyException, int>(entity, kinveyException, offset));
        }
예제 #2
0
        private async Task <Tuple <T, KinveyException, int> > HandlePushDELETE(PendingWriteAction pwa)
        {
            var             offset          = 0;
            KinveyException kinveyException = null;

            try
            {
                int result = 0;

                NetworkRequest <KinveyDeleteResponse> request = Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(pwa.collection, pwa.entityId);
                KinveyDeleteResponse kdr = await request.ExecuteAsync().ConfigureAwait(false);

                if (kdr.count == 1)
                {
                    result = SyncQueue.Remove(pwa);

                    if (result == 0)
                    {
                        offset++;
                    }
                }
            }
            catch (KinveyException ke)
            {
                kinveyException = ke;
                offset++;
            }

            return(new Tuple <T, KinveyException, int>(default(T), kinveyException, offset));
        }
예제 #3
0
        /// <summary>
        /// Executes the request asynchronously.
        /// </summary>
        /// <returns> The async task with the request result.</returns>
        public override async Task <uint> ExecuteAsync()
        {
            uint countResult = default(uint);

            switch (Policy)
            {
            case ReadPolicy.FORCE_LOCAL:
                // sync
                countResult = PerformLocalCount();
                break;

            case ReadPolicy.FORCE_NETWORK:
                // network
                countResult = await PerformNetworkCount().ConfigureAwait(false);

                break;

            case ReadPolicy.BOTH:
                // cache

                // first, perform local query
                PerformLocalCount(cacheDelegate);

                // once local query finishes, perform network query
                countResult = await PerformNetworkCount().ConfigureAwait(false);

                break;

            case ReadPolicy.NETWORK_OTHERWISE_LOCAL:
                // auto

                KinveyException networkKinveyException = null;
                try
                {
                    // first, perform a network request
                    countResult = await PerformNetworkCount().ConfigureAwait(false);
                }
                catch (KinveyException exception)
                {
                    if (exception.ErrorCategory != EnumErrorCategory.ERROR_DATASTORE_NETWORK || exception.ErrorCode != EnumErrorCode.ERROR_GENERAL)
                    {
                        throw;
                    }
                    networkKinveyException = exception;
                }

                // if the network request fails, fetch data from local cache
                if (networkKinveyException != null)
                {
                    countResult = PerformLocalCount();
                }
                break;

            default:
                throw new KinveyException(EnumErrorCategory.ERROR_GENERAL, EnumErrorCode.ERROR_GENERAL, "Invalid read policy");
            }

            return(countResult);
        }
예제 #4
0
        /// <summary>
        /// Executes the request asynchronously.
        /// </summary>
        /// <returns>The async.</returns>
        public override async Task <List <GroupAggregationResults> > ExecuteAsync()
        {
            List <GroupAggregationResults> aggregateResult = new List <GroupAggregationResults>();

            switch (Policy)
            {
            case ReadPolicy.FORCE_LOCAL:
                // sync
                aggregateResult = PerformLocalAggregateFind();
                break;

            case ReadPolicy.FORCE_NETWORK:
                // network
                aggregateResult = await PerformNetworkAggregateFind();

                break;

            case ReadPolicy.BOTH:
                // cache

                // first, perform local aggregation
                PerformLocalAggregateFind(cacheDelegate);

                // once local finishes, perform network aggregation
                aggregateResult = await PerformNetworkAggregateFind();

                break;

            case ReadPolicy.NETWORK_OTHERWISE_LOCAL:
                // auto

                KinveyException networkKinveyException = null;
                try
                {
                    // first, perform a network request
                    aggregateResult = await PerformNetworkAggregateFind();
                }
                catch (KinveyException exception)
                {
                    if (exception.ErrorCategory != EnumErrorCategory.ERROR_DATASTORE_NETWORK || exception.ErrorCode != EnumErrorCode.ERROR_GENERAL)
                    {
                        throw;
                    }
                    networkKinveyException = exception;
                }

                // if the network request fails, fetch data from local cache
                if (networkKinveyException != null)
                {
                    aggregateResult = PerformLocalAggregateFind();
                }
                break;

            default:
                throw new KinveyException(EnumErrorCategory.ERROR_GENERAL, EnumErrorCode.ERROR_GENERAL, "Invalid read policy");
            }

            return(aggregateResult);
        }
        /// <summary>
        /// Executes the request without any parsing.
        /// </summary>
        /// <returns>The unparsed.</returns>
        public HttpResponseMessage ExecuteUnparsed()
        {
            var client  = InitializeRestClient();
            var request = BuildRestRequest();

            RequestAuth.Authenticate(request);
            Logger.Log(request);
            var req      = client.SendAsync(request);
            var response = req.Result;

            Logger.Log(response);
            var contentType = response.Headers
                              .Where(x => x.Key.ToLower().Equals("content-type"))
                              .Select(x => x.Value)
                              .SingleOrDefault();

            if (contentType != null && contentType.Any() && !contentType.First().Contains("application/json"))
            {
                var kinveyException = new KinveyException(
                    EnumErrorCategory.ERROR_REQUIREMENT,
                    EnumErrorCode.ERROR_REQUIREMENT_CONTENT_TYPE_HEADER,
                    contentType.FirstOrDefault()
                    )
                {
                    RequestID = HelperMethods.getRequestID(response)
                };
                throw kinveyException;
            }

            lastResponseCode    = response.StatusCode;
            lastResponseMessage = response.StatusCode.ToString();
            lastResponseHeaders = new List <KeyValuePair <string, IEnumerable <string> > >();
            foreach (var header in response.Headers)
            {
                lastResponseHeaders.Add(header);
            }

            try
            {
                response.EnsureSuccessStatusCode();
            }
            catch (Exception ex)
            {
                throw new KinveyException(
                          EnumErrorCategory.ERROR_BACKEND,
                          EnumErrorCode.ERROR_JSON_RESPONSE,
                          ex.Message,
                          ex
                          );
            }


            return(response);
        }
예제 #6
0
        /// <summary>
        /// Executes this request async and parses the result.
        /// </summary>
        /// <returns>The async request.</returns>
        public async Task <KinveyAuthResponse> ExecuteAsync()
        {
            string json = null;
            HttpResponseMessage response = null;

            try
            {
                response = await ExecuteUnparsedAsync().ConfigureAwait(false);

                json = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                return(JsonConvert.DeserializeObject <KinveyAuthResponse>(json));
            }
            catch (JsonException ex)
            {
                KinveyException kinveyException = new KinveyException(
                    EnumErrorCategory.ERROR_DATASTORE_NETWORK,
                    EnumErrorCode.ERROR_JSON_PARSE,
                    HelperMethods.GetCustomParsingJsonErrorMessage(json, response?.RequestMessage.RequestUri.ToString(), typeof(KinveyAuthResponse).FullName),
                    null,
                    ex
                    )
                {
                    RequestID = HelperMethods.getRequestID(response)
                };
                throw kinveyException;
            }
            catch (KinveyException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new KinveyException(
                          EnumErrorCategory.ERROR_USER,
                          EnumErrorCode.ERROR_USER_LOGIN_ATTEMPT,
                          "Error deserializing response content.",
                          ex
                          );
            }
        }
예제 #7
0
        private async Task <Tuple <T, KinveyException, int> > HandlePushPOST(PendingWriteAction pwa)
        {
            T               entity          = default(T);
            var             offset          = 0;
            KinveyException kinveyException = null;

            try
            {
                int result = 0;

                string tempID = pwa.entityId;

                var localEntity = Cache.FindByID(pwa.entityId);

                JObject obj = JObject.FromObject(localEntity);
                obj["_id"]  = null;
                localEntity = Newtonsoft.Json.JsonConvert.DeserializeObject <T>(obj.ToString());

                NetworkRequest <T> request = Client.NetworkFactory.buildCreateRequest <T>(pwa.collection, localEntity);
                entity = await request.ExecuteAsync().ConfigureAwait(false);

                Cache.UpdateCacheSave(entity, tempID);

                result = SyncQueue.Remove(pwa);

                if (result == 0)
                {
                    offset++;
                }
            }
            catch (KinveyException ke)
            {
                kinveyException = ke;
                offset++;
            }

            return(new Tuple <T, KinveyException, int>(entity, kinveyException, offset));
        }
예제 #8
0
        public override async Task <List <T> > ExecuteAsync()
        {
            List <T> listResult = default(List <T>);

            switch (Policy)
            {
            case ReadPolicy.FORCE_LOCAL:
                // sync
                listResult = PerformLocalFind();
                break;

            case ReadPolicy.FORCE_NETWORK:
                // network
                var result = await RetrieveNetworkResults(this.BuildMongoQuery());

                listResult = result;
                break;

            case ReadPolicy.BOTH:
                // cache

                // first, perform local query
                PerformLocalFind(cacheDelegate);

                // once local query finishes, perform network query
                var resolved = await PerformNetworkFind();

                if (resolved.IsDeltaFetched)
                {
                    listResult = PerformLocalFind();
                }
                else
                {
                    listResult = resolved.ResultSet;
                }
                break;

            case ReadPolicy.NETWORK_OTHERWISE_LOCAL:
                // auto

                KinveyException networkKinveyException = null;
                try
                {
                    // first, perform a network request
                    var networkResult = await PerformNetworkFind();

                    if (networkResult.IsDeltaFetched)
                    {
                        listResult = PerformLocalFind();
                    }
                    else
                    {
                        listResult = networkResult.ResultSet;
                    }
                }
                catch (KinveyException exception)
                {
                    if (exception.ErrorCategory != EnumErrorCategory.ERROR_DATASTORE_NETWORK || exception.ErrorCode != EnumErrorCode.ERROR_GENERAL)
                    {
                        throw;
                    }
                    networkKinveyException = exception;
                }

                // if the network request fails, fetch data from local cache
                if (networkKinveyException != null)
                {
                    listResult = PerformLocalFind();
                }
                break;

            default:
                throw new KinveyException(EnumErrorCategory.ERROR_GENERAL, EnumErrorCode.ERROR_GENERAL, "Invalid read policy");
            }

            return(listResult);
        }
예제 #9
0
        public override async Task <T> ExecuteAsync()
        {
            T savedEntity = default(T);
            NetworkRequest <T> request  = null;
            string             entityID = null;;

            JToken idToken = JObject.FromObject(entity) ["_id"];

            if (idToken != null &&
                !String.IsNullOrEmpty(idToken.ToString()))
            {
                entityID = idToken.ToString();
                request  = Client.NetworkFactory.buildUpdateRequest(Collection, entity, entityID);
            }
            else
            {
                request = Client.NetworkFactory.buildCreateRequest(Collection, entity);
            }

            switch (Policy)
            {
            case WritePolicy.FORCE_LOCAL:
                // sync
                PendingWriteAction pendingAction = PendingWriteAction.buildFromRequest(request);

                string saveModeLocal = request.RequestMethod;
                string tempIdLocal   = null;

                if (String.Equals("POST", saveModeLocal))
                {
                    tempIdLocal            = PrepareCacheSave(ref entity);
                    savedEntity            = Cache.Save(entity);
                    pendingAction.entityId = tempIdLocal;
                }
                else
                {
                    savedEntity = Cache.Update(entity);
                }

                SyncQueue.Enqueue(pendingAction);

                break;

            case WritePolicy.FORCE_NETWORK:
                // network
                savedEntity = await request.ExecuteAsync();

                break;

            case WritePolicy.NETWORK_THEN_LOCAL:
                // cache
                string saveModeNetworkThenLocal = request.RequestMethod;
                string tempIdNetworkThenLocal   = null;

                if (String.Equals("POST", saveModeNetworkThenLocal))
                {
                    tempIdNetworkThenLocal = PrepareCacheSave(ref entity);
                    Cache.Save(entity);
                }
                else
                {
                    Cache.Update(entity);
                }

                // network save
                savedEntity = await request.ExecuteAsync();

                if (tempIdNetworkThenLocal != null)
                {
                    Cache.UpdateCacheSave(savedEntity, tempIdNetworkThenLocal);
                }

                break;

            case WritePolicy.LOCAL_THEN_NETWORK:
                string saveModeLocalThenNetwork = request.RequestMethod;

                // cache
                if (String.Equals("POST", saveModeLocalThenNetwork))
                {
                    entityID    = PrepareCacheSave(ref entity);
                    savedEntity = Cache.Save(entity);
                }
                else
                {
                    savedEntity = Cache.Update(entity);
                }

                KinveyException kinveyException = null;
                Exception       exception       = null;
                try
                {
                    // network save
                    savedEntity = await request.ExecuteAsync();
                }
                catch (KinveyException kinveyEx)
                {
                    kinveyException = kinveyEx;
                }
                catch (Exception ex)
                {
                    exception = ex;
                }

                if (kinveyException != null || exception != null)
                {
                    // if the network request fails, save data to sync queue
                    var localPendingAction = PendingWriteAction.buildFromRequest(request);
                    localPendingAction.entityId = entityID;

                    SyncQueue.Enqueue(localPendingAction);

                    if (kinveyException != null)
                    {
                        throw kinveyException;
                    }
                }
                else
                {
                    Cache.UpdateCacheSave(savedEntity, entityID);
                }

                break;

            default:
                throw new KinveyException(EnumErrorCategory.ERROR_GENERAL, EnumErrorCode.ERROR_GENERAL, "Invalid write policy");
            }

            return(savedEntity);
        }
예제 #10
0
        KinveyException HandleStatusMessage(PubnubApi.PNStatus status)
        {
            KinveyException ke = default(KinveyException);

            if (status.Error)
            {
                // Status indicates an error with PubNub
                var errorData = status.ErrorData;
                if (status.StatusCode == 403)
                {
                    ke = new KinveyException(EnumErrorCategory.ERROR_REALTIME,
                                             EnumErrorCode.ERROR_REALTIME_CRITICAL_NOT_AUTHORIZED_ON_CHANNEL,
                                             errorData.Information,
                                             errorData.Throwable);
                }
                else
                {
                    ke = new KinveyException(EnumErrorCategory.ERROR_REALTIME,
                                             EnumErrorCode.ERROR_REALTIME_ERROR,
                                             errorData.Information,
                                             errorData.Throwable);
                }
            }
            else
            {
                // TODO Figure out which status operations need to be logged.
                switch (status.Operation)
                {
                // Publish/Subscribe
                case PubnubApi.PNOperationType.PNPublishOperation:
                    break;

                case PubnubApi.PNOperationType.PNSubscribeOperation:
                    break;

                case PubnubApi.PNOperationType.PNUnsubscribeOperation:
                    break;

                // Channel Group and Channels
                case PubnubApi.PNOperationType.ChannelGroupAllGet:
                    break;

                case PubnubApi.PNOperationType.ChannelGroupAuditAccess:
                    break;

                case PubnubApi.PNOperationType.ChannelGroupGet:
                    break;

                case PubnubApi.PNOperationType.ChannelGroupGrantAccess:
                    break;

                case PubnubApi.PNOperationType.ChannelGroupRevokeAccess:
                    break;

                case PubnubApi.PNOperationType.PNAddChannelsToGroupOperation:
                    break;

                case PubnubApi.PNOperationType.PNChannelGroupsOperation:
                    break;

                case PubnubApi.PNOperationType.PNChannelsForGroupOperation:
                    break;

                case PubnubApi.PNOperationType.PNRemoveChannelsFromGroupOperation:
                    break;

                case PubnubApi.PNOperationType.PNRemoveGroupOperation:
                    break;

                // Access Manager
                case PubnubApi.PNOperationType.PNAccessManagerAudit:
                    break;

                case PubnubApi.PNOperationType.PNAccessManagerGrant:
                    break;

                // Presence
                case PubnubApi.PNOperationType.Presence:
                    break;

                case PubnubApi.PNOperationType.PresenceUnsubscribe:
                    break;

                // Push
                case PubnubApi.PNOperationType.PushGet:
                    break;

                case PubnubApi.PNOperationType.PushRegister:
                    break;

                case PubnubApi.PNOperationType.PushRemove:
                    break;

                case PubnubApi.PNOperationType.PushUnregister:
                    break;

                // Miscellaneous
                case PubnubApi.PNOperationType.Leave:
                    break;

                case PubnubApi.PNOperationType.None:
                    break;

                case PubnubApi.PNOperationType.RevokeAccess:
                    break;

                case PubnubApi.PNOperationType.PNFireOperation:
                    break;

                case PubnubApi.PNOperationType.PNGetStateOperation:
                    break;

                case PubnubApi.PNOperationType.PNHeartbeatOperation:
                    break;

                case PubnubApi.PNOperationType.PNHereNowOperation:
                    break;

                case PubnubApi.PNOperationType.PNHistoryOperation:
                    break;

                case PubnubApi.PNOperationType.PNSetStateOperation:
                    break;

                case PubnubApi.PNOperationType.PNTimeOperation:
                    break;

                case PubnubApi.PNOperationType.PNWhereNowOperation:
                    break;

                default:
                    break;
                }
            }

            return(ke);
        }
예제 #11
0
 internal void AddKinveyException(KinveyException e)
 {
     kinveyExceptions.Add(e);
 }
예제 #12
0
        /// <summary>
        /// Executes a multi insert request.
        /// </summary>
        /// <returns>An async task with the request result.</returns>
        public override async Task <KinveyMultiInsertResponse <T> > ExecuteAsync()
        {
            var kinveyDataStoreResponse = new KinveyMultiInsertResponse <T>
            {
                Entities = new List <T>(),
                Errors   = new List <Error>()
            };

            switch (Policy)
            {
            case WritePolicy.FORCE_LOCAL:
                //local cache
                for (var index = 0; index < entities.Count; index++)
                {
                    try
                    {
                        var cacheSaveResult = CacheSave(entities[index]);
                        SyncQueue.Enqueue(cacheSaveResult.Item1);
                        kinveyDataStoreResponse.Entities.Add(cacheSaveResult.Item2);
                    }
                    catch (Exception ex)
                    {
                        kinveyDataStoreResponse.Entities.Add(default(T));

                        var error = new Error
                        {
                            Index  = index,
                            Code   = 0,
                            Errmsg = ex.Message
                        };
                        kinveyDataStoreResponse.Errors.Add(error);
                    }
                }

                ThrowExceptionIfOnlyErrors(kinveyDataStoreResponse, EnumErrorCategory.ERROR_DATASTORE_CACHE, EnumErrorCode.ERROR_DATASTORE_CACHE_MULTIPLE_SAVE);

                break;

            case WritePolicy.FORCE_NETWORK:
                // network
                kinveyDataStoreResponse = await HandleNetworkRequestAsync(entities).ConfigureAwait(false);

                ThrowExceptionIfOnlyErrors(kinveyDataStoreResponse, EnumErrorCategory.ERROR_BACKEND, EnumErrorCode.ERROR_JSON_RESPONSE);
                break;

            case WritePolicy.LOCAL_THEN_NETWORK:
                //local cache
                KinveyMultiInsertResponse <T> kinveyDataStoreNetworkResponse = null;

                var pendingWriteActions = new List <PendingWriteAction>();

                for (var index = 0; index < entities.Count; index++)
                {
                    try
                    {
                        var cacheSaveResult = CacheSave(entities[index]);
                        pendingWriteActions.Add(cacheSaveResult.Item1);
                        kinveyDataStoreResponse.Entities.Add(cacheSaveResult.Item2);
                    }
                    catch (Exception ex)
                    {
                        kinveyDataStoreResponse.Entities.Add(default(T));

                        var error = new Error
                        {
                            Index  = index,
                            Code   = 0,
                            Errmsg = ex.Message
                        };
                        kinveyDataStoreResponse.Errors.Add(error);
                    }
                }

                ThrowExceptionIfOnlyErrors(kinveyDataStoreResponse, EnumErrorCategory.ERROR_DATASTORE_CACHE, EnumErrorCode.ERROR_DATASTORE_CACHE_MULTIPLE_SAVE);

                KinveyException kinveyException = null;
                Exception       exception       = null;
                try
                {
                    // network
                    kinveyDataStoreNetworkResponse = await HandleNetworkRequestAsync(entities).ConfigureAwait(false);
                }
                catch (KinveyException kinveyEx)
                {
                    kinveyException = kinveyEx;
                }
                catch (Exception ex)
                {
                    exception = ex;
                }

                if (kinveyException != null || exception != null)
                {
                    foreach (var pendingAction in pendingWriteActions)
                    {
                        SyncQueue.Enqueue(pendingAction);
                    }

                    if (kinveyException != null)
                    {
                        throw kinveyException;
                    }
                }
                else
                {
                    for (var index = 0; index < kinveyDataStoreResponse.Entities.Count; index++)
                    {
                        if (kinveyDataStoreNetworkResponse.Entities[index] != null)
                        {
                            if (kinveyDataStoreResponse.Entities[index] != null)
                            {
                                var obj = JObject.FromObject(kinveyDataStoreResponse.Entities[index]);
                                var id  = obj["_id"].ToString();
                                Cache.UpdateCacheSave(kinveyDataStoreNetworkResponse.Entities[index], id);
                            }
                            else
                            {
                                CacheSave(kinveyDataStoreNetworkResponse.Entities[index]);
                            }
                        }
                        else
                        {
                            if (kinveyDataStoreResponse.Entities[index] != null)
                            {
                                var obj = JObject.FromObject(kinveyDataStoreResponse.Entities[index]);
                                var id  = obj["_id"].ToString();

                                var existingPendingWriteAction = pendingWriteActions.Find(e => e.entityId.Equals(id));

                                if (existingPendingWriteAction != null)
                                {
                                    SyncQueue.Enqueue(existingPendingWriteAction);
                                }
                            }
                        }
                    }

                    kinveyDataStoreResponse = kinveyDataStoreNetworkResponse;
                }

                ThrowExceptionIfOnlyErrors(kinveyDataStoreResponse, EnumErrorCategory.ERROR_BACKEND, EnumErrorCode.ERROR_JSON_RESPONSE);

                break;

            default:
                throw new KinveyException(EnumErrorCategory.ERROR_GENERAL, EnumErrorCode.ERROR_GENERAL, "Invalid write policy");
            }

            return(kinveyDataStoreResponse);
        }
예제 #13
0
        public override async Task <KinveyDeleteResponse> ExecuteAsync()
        {
            var kdr = default(KinveyDeleteResponse);

            switch (Policy)
            {
            case WritePolicy.FORCE_LOCAL:
                // sync
                if (_query == null)
                {
                    // cache
                    kdr = Cache.DeleteByID(entityID);

                    var request = Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, entityID);

                    var pendingAction = PendingWriteAction.buildFromRequest(request);
                    SyncQueue.Enqueue(pendingAction);
                }
                else
                {
                    // cache
                    kdr = Cache.DeleteByQuery(_query);

                    foreach (var id in kdr.IDs)
                    {
                        var request       = Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, id);
                        var pendingAction = PendingWriteAction.buildFromRequest(request);
                        SyncQueue.Enqueue(pendingAction);
                    }
                }
                break;

            case WritePolicy.FORCE_NETWORK:
                // network
                if (_query == null)
                {
                    kdr = await Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, entityID).ExecuteAsync();
                }
                else
                {
                    var mongoQuery = KinveyMongoQueryBuilder.GetQueryForRemoveOperation <T>(_query);
                    kdr = await Client.NetworkFactory.buildDeleteRequestWithQuery <KinveyDeleteResponse>(Collection, mongoQuery).ExecuteAsync();
                }
                break;

            case WritePolicy.NETWORK_THEN_LOCAL:
                if (_query == null)
                {
                    // cache
                    kdr = Cache.DeleteByID(entityID);

                    // network
                    kdr = await Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, entityID).ExecuteAsync();
                }
                else
                {
                    // cache
                    kdr = Cache.DeleteByQuery(_query);

                    // network
                    var mongoQuery = KinveyMongoQueryBuilder.GetQueryForRemoveOperation <T>(_query);
                    kdr = await Client.NetworkFactory.buildDeleteRequestWithQuery <KinveyDeleteResponse>(Collection, mongoQuery).ExecuteAsync();
                }
                break;

            case WritePolicy.LOCAL_THEN_NETWORK:
                if (_query == null)
                {
                    // cache
                    kdr = Cache.DeleteByID(entityID);

                    var deleteRequest = Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, entityID);

                    KinveyException kinveyException = null;
                    Exception       exception       = null;
                    try
                    {
                        // network
                        kdr = await deleteRequest.ExecuteAsync();
                    }
                    catch (KinveyException kinveyEx)
                    {
                        kinveyException = kinveyEx;
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                    }

                    if (kinveyException != null || exception != null)
                    {
                        var pendingAction = PendingWriteAction.buildFromRequest(deleteRequest);
                        SyncQueue.Enqueue(pendingAction);

                        if (kinveyException != null)
                        {
                            throw kinveyException;
                        }
                    }
                }
                else
                {
                    // cache
                    kdr = Cache.DeleteByQuery(_query);

                    // network
                    KinveyException kinveyException = null;
                    Exception       exception       = null;
                    try
                    {
                        var mongoQuery = KinveyMongoQueryBuilder.GetQueryForRemoveOperation <T>(_query);
                        kdr = await Client.NetworkFactory.buildDeleteRequestWithQuery <KinveyDeleteResponse>(Collection, mongoQuery).ExecuteAsync();
                    }
                    catch (KinveyException kinveyEx)
                    {
                        kinveyException = kinveyEx;
                    }
                    catch (Exception ex)
                    {
                        exception = ex;
                    }

                    if (kinveyException != null || exception != null)
                    {
                        foreach (var id in kdr.IDs)
                        {
                            var request       = Client.NetworkFactory.buildDeleteRequest <KinveyDeleteResponse>(Collection, id);
                            var pendingAction = PendingWriteAction.buildFromRequest(request);
                            SyncQueue.Enqueue(pendingAction);
                        }

                        if (kinveyException != null)
                        {
                            throw kinveyException;
                        }
                    }
                }
                break;

            default:
                throw new KinveyException(EnumErrorCategory.ERROR_GENERAL, EnumErrorCode.ERROR_GENERAL, "Invalid write policy");
            }

            return(kdr);
        }
        public virtual async Task <T> ExecuteAsync()
        {
            var response = await ExecuteUnparsedAsync();

            if (OverrideRedirect)
            {
                string newLoc = string.Empty;
                foreach (var header in response.Headers)
                {
                    if (header.Key.ToLower().Equals("location"))
                    {
                        newLoc = header.Value.FirstOrDefault();
                        break;
                    }
                }
                //string newlocation = response.Headers.FirstOrDefault(stringToCheck => stringToCheck.ToString().Equals("Location")).ToString();
                return(await onRedirectAsync(newLoc));
            }
            // special case to handle void or empty responses
            if (response.Content == null)
            {
                return(default(T));
            }

            string path = response.RequestMessage.RequestUri.AbsolutePath;

            if (path != null &&
                path.Contains(Constants.STR_PATH_CUSTOM_ENDPOINT) &&
                (((int)response.StatusCode) < 200 || ((int)response.StatusCode) > 302))
            {
                // Seems like only Custom Endpoint/BL would result in having a successful response
                // without having a successful status code.  The BL executed successfully, but did
                // produce a successsful outcome.
                try
                {
                    response.EnsureSuccessStatusCode();
                }
                catch (Exception ex)
                {
                    var ke = new KinveyException(
                        EnumErrorCategory.ERROR_CUSTOM_ENDPOINT,
                        EnumErrorCode.ERROR_CUSTOM_ENDPOINT_ERROR,
                        response,
                        ex
                        );
                    throw ke;
                }
            }

            if (path != null &&
                path.Contains(Constants.STR_PATH_REALTIME_STREAM) &&
                (((int)response.StatusCode) < 200 || ((int)response.StatusCode) > 302))
            {
                // Appears as though there is a stream error.  A stream error could result in having a successful response
                // without having a successful status code, such as a 401.  The request was successful, but the response
                // indicates that there is an issue with what was being requested
                try
                {
                    response.EnsureSuccessStatusCode();
                }
                catch (Exception ex)
                {
                    var ke = new KinveyException(
                        EnumErrorCategory.ERROR_REALTIME,
                        EnumErrorCode.ERROR_REALTIME_ERROR,
                        response,
                        ex
                        );
                    throw ke;
                }
            }

            if (((int)response.StatusCode) < 200 || ((int)response.StatusCode) > 302)
            {
                try
                {
                    response.EnsureSuccessStatusCode();
                }
                catch (Exception ex)
                {
                    var kinveyException = new KinveyException(
                        EnumErrorCategory.ERROR_BACKEND,
                        EnumErrorCode.ERROR_JSON_RESPONSE,
                        response,
                        ex
                        )
                    {
                        RequestID = HelperMethods.getRequestID(response)
                    };
                    throw kinveyException;
                }
            }

            try
            {
                var json = await response.Content.ReadAsStringAsync();

                var result = JsonConvert.DeserializeObject <T>(json);

                RequestStartTime = HelperMethods.GetRequestStartTime(response);

                return(result);
            }
            catch (JsonException ex)
            {
                KinveyException kinveyException = new KinveyException(
                    EnumErrorCategory.ERROR_DATASTORE_NETWORK,
                    EnumErrorCode.ERROR_JSON_PARSE,
                    ex.Message,
                    ex
                    )
                {
                    RequestID = HelperMethods.getRequestID(response)
                };
                throw kinveyException;
            }
            catch (ArgumentException ex)
            {
                Logger.Log(ex.Message);
                return(default(T));
            }
            catch (NullReferenceException ex)
            {
                Logger.Log(ex.Message);
                return(default(T));
            }
        }
        public async Task <HttpResponseMessage> ExecuteUnparsedAsync()
        {
            var httClient = InitializeRestClient();
            var request   = BuildRestRequest();

            RequestAuth.Authenticate(request);
            Logger.Log(request);
            var response = await httClient.SendAsync(request);

            Logger.Log(response);
            var contentType = response.Headers
                              .Where(x => x.Key.ToLower().Equals("content-type"))
                              .Select(x => x.Value)
                              .FirstOrDefault()?
                              .FirstOrDefault();

            if (contentType != null && !contentType.Contains("application/json"))
            {
                var kinveyException = new KinveyException(
                    EnumErrorCategory.ERROR_REQUIREMENT,
                    EnumErrorCode.ERROR_REQUIREMENT_CONTENT_TYPE_HEADER,
                    contentType
                    )
                {
                    RequestID = HelperMethods.getRequestID(response)
                };
                throw kinveyException;
            }

            lastResponseCode    = response.StatusCode;
            lastResponseMessage = response.StatusCode.ToString();
            lastResponseHeaders = new List <KeyValuePair <string, IEnumerable <string> > >();

            foreach (var header in response.Headers)
            {
                lastResponseHeaders.Add(header);
            }

            if ((int)response.StatusCode == 401)
            {
                ServerError error = null;
                try
                {
                    var json = await response.Content.ReadAsStringAsync();

                    error = JsonConvert.DeserializeObject <ServerError>(json);
                }
                catch (Exception)
                {
                }

                if (error != null && !error.Error.Equals(Constants.STR_ERROR_BACKEND_INSUFFICIENT_CREDENTIALS))
                {
                    // Attempt to get the refresh token
                    Credential cred         = Client.Store.Load(Client.ActiveUser.Id, Client.SSOGroupKey);
                    string     refreshToken = null;
                    string     redirectUri  = null;
                    string     micClientId  = null;

                    if (cred != null)
                    {
                        refreshToken = cred.RefreshToken;
                        redirectUri  = cred.RedirectUri;
                        micClientId  = cred.MICClientID;

                        if (!string.IsNullOrEmpty(refreshToken) && !refreshToken.ToLower().Equals("null"))
                        {
                            if (!hasRetried)
                            {
                                // Attempting retry - set flag to prevent additional attempts
                                hasRetried = true;

                                //use the refresh token for a new access token
                                JObject result = await Client.ActiveUser.UseRefreshToken(refreshToken, redirectUri, micClientId).ExecuteAsync();

                                // log out the current user without removing the user record from the credential store
                                Client.ActiveUser.LogoutSoft();

                                //login with the access token
                                Provider provider = new Provider();
                                provider.kinveyAuth = new MICCredential(result["access_token"].ToString());
                                User u = await User.LoginAsync(new ThirdPartyIdentity(provider), Client);

                                //store the new refresh token
                                Credential currentCred = Client.Store.Load(Client.ActiveUser.Id, Client.SSOGroupKey);
                                currentCred.AccessToken  = result["access_token"].ToString();
                                currentCred.RefreshToken = result.GetValidValue("refresh_token");
                                currentCred.RedirectUri  = redirectUri;
                                Client.Store.Store(Client.ActiveUser.Id, Client.SSOGroupKey, currentCred);

                                // Retry the original request
                                RequestAuth = new KinveyAuthenticator(currentCred.AuthToken);
                                var retryResponse = await ExecuteUnparsedAsync();

                                return(retryResponse);
                            }
                            else
                            {
                                Client.ActiveUser.Logout();
                            }
                        }
                        else
                        {
                            //logout the current user
                            Client.ActiveUser.Logout();
                        }
                    }
                    else
                    {
                        Client.ActiveUser.Logout();
                    }
                }
            }

            try
            {
                response.EnsureSuccessStatusCode();
            }
            catch (Exception ex)
            {
                throw new KinveyException(
                          EnumErrorCategory.ERROR_BACKEND,
                          EnumErrorCode.ERROR_JSON_RESPONSE,
                          response,
                          ex
                          );
            }


            return(response);
        }