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"); }
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); }
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)); }
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(); }
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); }
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)); }