Exemple #1
0
            public void Sync_with_inline_filter()
            {
                ISynchronousFilterChain defaultFilterChain = new DefaultSynchronousFilterChain(dataStore: null)
                                                             .Add(new DeleteInterceptorFilter());

                ISynchronousFilterChain finalChain = new DefaultSynchronousFilterChain(defaultFilterChain as DefaultSynchronousFilterChain)
                                                     .Add(new DefaultSynchronousFilter((req, next, logger) =>
                {
                    return(new DefaultResourceDataResult(
                               ResourceAction.Create,
                               typeof(IDictionary <string, object>),
                               req.Uri,
                               httpStatus: 200,
                               body: new Dictionary <string, object>()
                    {
                        { "Foo", "bar" }
                    }));
                }));

                var request = new DefaultResourceDataRequest(ResourceAction.Create, typeof(IAccount), new CanonicalUri("http://api.foo.bar"), false);
                var result  = finalChain.Filter(request, Substitute.For <ILogger>());

                result.Action.ShouldBe(ResourceAction.Create);
                result.Body.ShouldContainKeyAndValue("Foo", "bar");
            }
Exemple #2
0
        private bool DeleteCore <T>(string href)
            where T : IResource
        {
            if (string.IsNullOrEmpty(href))
            {
                throw new ArgumentNullException(nameof(href));
            }

            var uri = new CanonicalUri(this.uriQualifier.EnsureFullyQualified(href));

            this.logger.Trace($"Synchronously deleting resource {uri.ToString()}", "DefaultDataStore.DeleteCore");

            ISynchronousFilterChain chain = new DefaultSynchronousFilterChain(this.defaultSyncFilters as DefaultSynchronousFilterChain)
                                            .Add(new DefaultSynchronousFilter((req, next, logger) =>
            {
                var httpRequest = new DefaultHttpRequest(HttpMethod.Delete, req.Uri);
                var response    = this.Execute(httpRequest);

                return(new DefaultResourceDataResult(req.Action, typeof(T), req.Uri, response.StatusCode, body: null));
            }));

            var request = new DefaultResourceDataRequest(ResourceAction.Delete, typeof(T), uri, false);
            var result  = chain.Filter(request, this.logger);

            bool successfullyDeleted = result.HttpStatus == 204;

            return(successfullyDeleted);
        }
Exemple #3
0
        private IResourceDataResult GetResourceData <T>(string href, bool skipCache)
        {
            if (string.IsNullOrEmpty(href))
            {
                throw new ArgumentNullException(nameof(href));
            }

            var canonicalUri = new CanonicalUri(this.uriQualifier.EnsureFullyQualified(href));

            this.logger.Trace($"Synchronously getting resource type {typeof(T).Name} from: {canonicalUri.ToString()}", "DefaultDataStore.GetResource<T>");

            ISynchronousFilterChain chain = new DefaultSynchronousFilterChain(this.defaultSyncFilters as DefaultSynchronousFilterChain)
                                            .Add(new DefaultSynchronousFilter((req, next, logger) =>
            {
                var httpRequest = new DefaultHttpRequest(HttpMethod.Get, req.Uri);

                var response = this.Execute(httpRequest);
                var body     = this.GetBody <T>(response);

                return(new DefaultResourceDataResult(req.Action, typeof(T), req.Uri, response.StatusCode, body));
            }));

            var request = new DefaultResourceDataRequest(ResourceAction.Read, typeof(T), canonicalUri, skipCache);

            return(chain.Filter(request, this.logger));
        }
Exemple #4
0
            public void Sync_chain_terminating_on_second()
            {
                ISynchronousFilterChain filterChain = new DefaultSynchronousFilterChain(dataStore: null)
                                                      .Add(new CreateInterceptorFilter())
                                                      .Add(new DeleteInterceptorFilter());

                var request = new DefaultResourceDataRequest(ResourceAction.Delete, typeof(IAccount), new CanonicalUri("http://api.foo.bar"), false);
                var result  = filterChain.Filter(request, Substitute.For <ILogger>());

                result.Action.ShouldBe(ResourceAction.Delete);
                result.Body.ShouldBeNull();
            }
Exemple #5
0
        private ISynchronousFilterChain BuildDefaultSyncFilterChain()
        {
            var syncFilterChain = new DefaultSynchronousFilterChain(this);

            if (this.IsCachingEnabled())
            {
                syncFilterChain.Add(new ReadCacheFilter(this.baseUrl, this.cacheResolver));
                syncFilterChain.Add(new WriteCacheFilter(this.cacheResolver, this.resourceFactory));
            }

            syncFilterChain.Add(new ProviderAccountResultFilter());
            syncFilterChain.Add(new AccountStoreMappingCacheInvalidationFilter());

            return(syncFilterChain);
        }
Exemple #6
0
        private TReturned SaveCore <T, TReturned>(T resource, string href, QueryString queryParams, HttpHeaders headers, bool create)
            where T : class
            where TReturned : class
        {
            if (string.IsNullOrEmpty(href))
            {
                throw new ArgumentNullException(nameof(href));
            }

            var canonicalUri = new CanonicalUri(this.uriQualifier.EnsureFullyQualified(href), queryParams);

            this.logger.Trace($"Synchronously saving resource of type {typeof(T).Name} to {canonicalUri.ToString()}", "DefaultDataStore.SaveCore");

            ISynchronousFilterChain chain = new DefaultSynchronousFilterChain(this.defaultSyncFilters as DefaultSynchronousFilterChain)
                                            .Add(new DefaultSynchronousFilter((req, next, logger) =>
            {
                bool contentTypeIsPresent = !string.IsNullOrEmpty(req.Headers?.ContentType);

                bool contentTypeIsFormUrlEncoded =
                    contentTypeIsPresent &&
                    string.Equals(req.Headers.ContentType, HttpHeaders.MediaTypeApplicationFormUrlEncoded, StringComparison.OrdinalIgnoreCase);

                string postBody = contentTypeIsFormUrlEncoded
                        ? new FormUrlEncoder(req.Properties).ToString()
                        : this.serializer.Serialize(req.Properties);

                var httpRequest = new DefaultHttpRequest(
                    HttpMethod.Post,
                    req.Uri,
                    queryParams: null,
                    headers: req.Headers,
                    body: postBody,
                    bodyContentType: contentTypeIsPresent ? req.Headers.ContentType : DefaultContentType);

                var response       = this.Execute(httpRequest);
                var responseBody   = this.GetBody <T>(response);
                var responseAction = this.GetPostAction(req, response);

                bool responseHasData      = responseBody.Any();
                bool responseIsProcessing = response.StatusCode == 202;
                bool responseOkay         = responseHasData || responseIsProcessing;

                if (!responseOkay)
                {
                    throw new ResourceException(DefaultError.WithMessage("Unable to obtain resource data from the API server."));
                }

                if (responseIsProcessing)
                {
                    this.logger.Warn($"Received a 202 response, returning empty result. Href: '{canonicalUri.ToString()}'", "DefaultDataStore.SaveCoreAsync");
                }

                return(new DefaultResourceDataResult(responseAction, typeof(TReturned), req.Uri, response.StatusCode, responseBody));
            }));

            Map propertiesMap = null;

            var abstractResource = resource as AbstractResource;

            if (abstractResource != null)
            {
                // Serialize properties
                propertiesMap = this.resourceConverter.ToMap(abstractResource);

                var  extendableInstanceResource = abstractResource as AbstractExtendableInstanceResource;
                bool includesCustomData         = extendableInstanceResource != null;
                if (includesCustomData)
                {
                    var customDataProxy = (extendableInstanceResource as IExtendableSync).CustomData as DefaultCustomDataProxy;

                    // Apply custom data deletes
                    if (customDataProxy.HasDeletedProperties())
                    {
                        if (customDataProxy.DeleteAll)
                        {
                            this.DeleteCore <ICustomData>(extendableInstanceResource.CustomData.Href);
                        }
                        else
                        {
                            customDataProxy.DeleteRemovedCustomDataProperties(extendableInstanceResource.CustomData.Href);
                        }
                    }

                    // Merge in custom data updates
                    if (customDataProxy.HasUpdatedCustomDataProperties())
                    {
                        propertiesMap["customData"] = customDataProxy.UpdatedCustomDataProperties;
                    }

                    // Remove custom data updates from proxy
                    extendableInstanceResource.ResetCustomData();
                }
            }

            // In some cases, all we need to save are custom data property deletions, which is taken care of above.
            // So, we should just refresh with the latest data from the server.
            // This doesn't apply to CREATEs, though, because sometimes we need to POST a null body.
            bool nothingToPost = propertiesMap.IsNullOrEmpty();

            if (!create && nothingToPost)
            {
                return(this.AsSyncInterface.GetResource <TReturned>(canonicalUri.ToString()));
            }

            var requestAction = create
                ? ResourceAction.Create
                : ResourceAction.Update;
            var request = new DefaultResourceDataRequest(requestAction, typeof(T), canonicalUri, headers, propertiesMap, false);

            var result = chain.Filter(request, this.logger);

            return(this.resourceFactory.Create <TReturned>(result.Body, resource as ILinkable));
        }