示例#1
0
            public async Task Async_with_inline_filter()
            {
                IAsynchronousFilterChain defaultFilterChain = new DefaultAsynchronousFilterChain(dataStore: null)
                                                              .Add(new DeleteInterceptorFilter());

                IAsynchronousFilterChain finalChain = new DefaultAsynchronousFilterChain(defaultFilterChain as DefaultAsynchronousFilterChain)
                                                      .Add(new DefaultAsynchronousFilter((req, next, logger, ct) =>
                {
                    return(Task.FromResult <IResourceDataResult>(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  = await finalChain.FilterAsync(request, Substitute.For <ILogger>(), CancellationToken.None);

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

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

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

            IAsynchronousFilterChain chain = new DefaultAsynchronousFilterChain(this.defaultAsyncFilters as DefaultAsynchronousFilterChain)
                                             .Add(new DefaultAsynchronousFilter(async(req, next, logger, ct) =>
            {
                var httpRequest = new DefaultHttpRequest(HttpMethod.Delete, req.Uri);
                var response    = await this.ExecuteAsync(httpRequest, ct).ConfigureAwait(false);

                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  = await chain.FilterAsync(request, this.logger, cancellationToken).ConfigureAwait(false);

            bool successfullyDeleted = result.HttpStatus == 204;

            return(successfullyDeleted);
        }
示例#3
0
        private Task <IResourceDataResult> GetResourceDataAsync <T>(string href, bool skipCache, CancellationToken cancellationToken)
        {
            if (string.IsNullOrEmpty(href))
            {
                throw new ArgumentNullException(nameof(href));
            }

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

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

            IAsynchronousFilterChain chain = new DefaultAsynchronousFilterChain(this.defaultAsyncFilters as DefaultAsynchronousFilterChain)
                                             .Add(new DefaultAsynchronousFilter(async(req, next, logger, ct) =>
            {
                var httpRequest = new DefaultHttpRequest(HttpMethod.Get, req.Uri);

                var response = await this.ExecuteAsync(httpRequest, ct).ConfigureAwait(false);
                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.FilterAsync(request, this.logger, cancellationToken));
        }
示例#4
0
            public async Task Async_chain_terminating_on_second()
            {
                IAsynchronousFilterChain filterChain = new DefaultAsynchronousFilterChain(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  = await filterChain.FilterAsync(request, Substitute.For <ILogger>(), CancellationToken.None);

                result.Action.ShouldBe(ResourceAction.Delete);
                result.Body.ShouldBeNull();
            }
示例#5
0
        private IAsynchronousFilterChain BuildDefaultAsyncFilterChain()
        {
            var asyncFilterChain = new DefaultAsynchronousFilterChain(this);

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

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

            return(asyncFilterChain);
        }
示例#6
0
        private async Task <TReturned> SaveCoreAsync <T, TReturned>(T resource, string href, QueryString queryParams, HttpHeaders headers, bool create, CancellationToken cancellationToken)
            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($"Asynchronously saving resource of type {typeof(T).Name} to {canonicalUri.ToString()}", "DefaultDataStore.SaveCoreAsync");

            IAsynchronousFilterChain chain = new DefaultAsynchronousFilterChain(this.defaultAsyncFilters as DefaultAsynchronousFilterChain)
                                             .Add(new DefaultAsynchronousFilter(async(req, next, logger, ct) =>
            {
                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       = await this.ExecuteAsync(httpRequest, ct).ConfigureAwait(false);
                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 IExtendable).CustomData as DefaultCustomDataProxy;

                    // Apply custom data deletes
                    if (customDataProxy.HasDeletedProperties())
                    {
                        if (customDataProxy.DeleteAll)
                        {
                            await this.DeleteCoreAsync <ICustomData>(extendableInstanceResource.CustomData.Href, cancellationToken).ConfigureAwait(false);
                        }
                        else
                        {
                            await customDataProxy.DeleteRemovedCustomDataPropertiesAsync(extendableInstanceResource.CustomData.Href, cancellationToken).ConfigureAwait(false);
                        }
                    }

                    // 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(await this.AsAsyncInterface.GetResourceAsync <TReturned>(canonicalUri.ToString(), cancellationToken).ConfigureAwait(false));
            }

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

            var result = await chain.FilterAsync(request, this.logger, cancellationToken).ConfigureAwait(false);

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