Esempio n. 1
0
        private object GetSingleRelated(object model, string rltnName)
        {
            var resource = ModelRegistry.GetResource(model);
            var request  = HttpRequestBuilder.GetRelated(resource.Id, resource.Type, rltnName);
            var response = HttpClient.SendAsync(request).GetAwaiter().GetResult();

            HttpResponseListener.GetRelated(response.StatusCode, resource.Id, resource.Type, rltnName);
            if (response.StatusCode == HttpStatusCode.NotFound)
            {
                return(null);
            }
            response.CheckStatusCode();

            // TODO: perhaps use a 3rd ResourceRoot with JToken Data to determine if array was erroneously returned
            var root = response.GetContentModel <ResourceRootSingle>(JsonSettings).GetAwaiter().GetResult();

            var rltn = root.Data;

            if (rltn == null)
            {
                return(null);
            }

            var rltnModel = CreateResourceModel(rltn);

            Cache.Update(rltn.Id, rltnModel);
            return(rltnModel);
        }
Esempio n. 2
0
        public async Task Update <TModel>(TModel model)
        {
            // guard from kunckleheads
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }
            ThrowIfUnmanaged(model);

            var patch = BuildPatch(model);

            // if nothing was updated, no need to continue
            if (patch == null)
            {
                return;
            }

            var allModels = ModelRegistry.IncludedModelsCreate(model);

            foreach (var newModel in allModels)
            {
                var newResource = BuildModelResource(newModel);
                // Update the model instance in the argument
                var initialize = newModel.GetType().GetInitializeMethod();
                initialize.Invoke(newModel, new object[] { newResource, this });
            }

            var includes = allModels.Select(ModelRegistry.GetResource).ToArray();

            var originalResource = ModelRegistry.GetResource(model);

            var root    = ResourceRootSingle.FromResource(patch, includes);
            var request = await HttpRequestBuilder.UpdateResource(originalResource, root);

            var response = await HttpClient.SendAsync(request).ConfigureAwait(false);

            HttpResponseListener.UpdateResource(response.StatusCode, originalResource, root);
            response.CheckStatusCode();

            if (response.StatusCode == HttpStatusCode.OK)
            {
                var responseRoot = await response.GetContentModel <ResourceRootSingle>(JsonSettings);

                // Update the model instance in the argument
                var initialize = typeof(TModel).GetInitializeMethod();
                initialize.Invoke(model, new object[] { responseRoot.Data, this });
                Cache.Update(responseRoot.Data.Id, model);
            }
            else if (response.StatusCode == HttpStatusCode.NoContent)
            {
                ModelRegistry.ApplyPatch(model, patch);
            }

            // create and cache includes
            await Task.WhenAll(allModels.Select(x => Task.Run(() =>
            {
                var resource = ModelRegistry.GetResource(x);
                Cache.Update(resource.Id, x);
            })));
        }
Esempio n. 3
0
        public async Task Delete <TModel>(Guid id)
        {
            var resourceType = ModelRegistry.GetResourceType <TModel>();
            var request      = HttpRequestBuilder.DeleteResource(resourceType, id);
            var response     = await HttpClient.SendAsync(request);

            HttpResponseListener.DeleteResource(response.StatusCode, id, resourceType);
            response.CheckStatusCode();
            var model = Cache.Retrieve <TModel>(id);

            if (model != null)
            {
                ModelRegistry.DetachModel(model);
            }
            Cache.Remove(id);
        }
Esempio n. 4
0
        public async Task <IEnumerable <TModel> > Query <TModel>(IQueryContext query)
        {
            query = query ?? new QueryContext <TModel>();

            if (query.PageLimit != null && query.PageLimit <= 0)
            {
                return(Enumerable.Empty <TModel>());
            }
            if (query.PageSize != null && query.PageSize <= 0)
            {
                return(Enumerable.Empty <TModel>());
            }

            var include = ModelRegistry.GetInclude <TModel>();

            var request = HttpRequestBuilder.QueryResources(query, include);

            var response = await HttpClient.SendAsync(request).ConfigureAwait(false);

            HttpResponseListener.QueryResources(response.StatusCode, query);
            if (response.StatusCode == HttpStatusCode.NotFound)
            {
                return(Enumerable.Empty <TModel>());
            }
            response.CheckStatusCode();

            var root = await response.GetContentModel <ResourceRootCollection>(JsonSettings);

            var createData = Task.WhenAll(root.Data.Select(x => Task.Run(() =>
            {
                var dataModel = CreateResourceModel <TModel>(x);
                Cache.Update(x.Id, dataModel);
                return(dataModel);
            })));
            var createIncludes = root.Included != null
                ? Task.WhenAll(root.Included.Select(x => Task.Run(() =>
            {
                var includedModel = CreateResourceModel(x);
                Cache.Update(x.Id, includedModel);
            })))
                : Task.CompletedTask;

            await Task.WhenAll(createIncludes, createData);

            return(createData.Result);
        }
Esempio n. 5
0
        public void InitializeCollection(IRemoteCollection collection)
        {
            // TODO: abstract this into a collection loader/initializer
            // TODO: brute force this for now
            // TODO: don't run this task if the resource collection is empty/null!

            var resource = ModelRegistry.GetResource(collection.Owner);

            // determine if the cache is missing any models for this relationship
            var relationships = ModelRegistry.GetResource(collection.Owner).Relationships;

            if (relationships != null && relationships.TryGetValue(collection.Name, out var rltn))
            {
                if (rltn?.Data.Type == JTokenType.Array &&
                    rltn.Data.ToObject <IEnumerable <ResourceIdentifier> >()
                    .All(x => Cache.Retrieve <object>(x.Id) != null))
                {
                    return;
                }
            }

            var request  = HttpRequestBuilder.GetRelated(resource.Id, resource.Type, collection.Name);
            var response = HttpClient.SendAsync(request).GetAwaiter().GetResult();

            HttpResponseListener.GetRelated(response.StatusCode, resource.Id, resource.Type, collection.Name);
            if (response.StatusCode == HttpStatusCode.NotFound)
            {
                return;
            }

            response.CheckStatusCode();

            // TODO: perhaps use a 3rd ResourceRoot with JToken Data to determine if object was erroneously returned
            var root    = response.GetContentModel <ResourceRootCollection>(JsonSettings).GetAwaiter().GetResult();
            var related = root.Data?.Select(x =>
            {
                var rltnModel = CreateResourceModel(x);
                Cache.Update(x.Id, rltnModel);
                return(rltnModel);
            })
                          .ToArray();

            collection.SetItems(related);
        }
Esempio n. 6
0
        public IEnumerable <TRltn> GetRelated <TParent, TRltn>(
            Guid id,
            Expression <Func <TParent, IEnumerable <TRltn> > > relationship)
        {
            var modelType = typeof(TParent);

            if (!(relationship.Body is MemberExpression mExpression))
            {
                throw new NotSupportedException();
            }
            var attr = mExpression.Member.CustomAttributes
                       .SingleOrDefault(a => a.AttributeType == typeof(HasManyAttribute));

            if (attr == null)
            {
                throw new RelationshipNotRegisteredExecption(mExpression.Member.Name, modelType);
            }

            var resourceType = ModelRegistry.GetResourceType(typeof(TParent));
            var rltnName     = mExpression.Member.GetJsonName(typeof(HasManyAttribute));

            var request  = HttpRequestBuilder.GetRelated(id, resourceType, rltnName);
            var response = HttpClient.SendAsync(request).GetAwaiter().GetResult();

            HttpResponseListener.GetRelated(response.StatusCode, id, resourceType, rltnName);
            if (response.StatusCode == HttpStatusCode.NotFound)
            {
                return(Enumerable.Empty <TRltn>());
            }

            response.CheckStatusCode();

            var root    = response.GetContentModel <ResourceRootCollection>(JsonSettings).GetAwaiter().GetResult();
            var related = root.Data?
                          .Select(CreateResourceModel)
                          .Cast <TRltn>()
                          .ToArray();

            return(related);
        }
Esempio n. 7
0
        public async Task <TModel> Get <TModel>(Guid id)
        {
            ThrowIfDisposed();

            var model = Cache.Retrieve <TModel>(id);

            if (model != null)
            {
                return(model);
            }

            var resourceType = ModelRegistry.GetResourceType <TModel>();
            var include      = ModelRegistry.GetInclude <TModel>();
            var request      = HttpRequestBuilder.GetResource(id, resourceType, include);
            var response     = await HttpClient.SendAsync(request).ConfigureAwait(false);

            HttpResponseListener.GetResource(response.StatusCode, id, resourceType);
            if (response.StatusCode == HttpStatusCode.NotFound)
            {
                return(default(TModel)); // null
            }
            response.CheckStatusCode();

            var root = await response.GetContentModel <ResourceRootSingle>(JsonSettings);

            model = CreateResourceModel <TModel>(root.Data);
            Cache.Update(id, model);
            if (root.Included != null)
            {
                await Task.WhenAll(root.Included.Select(x => Task.Run(() =>
                {
                    var includedModel = CreateResourceModel(x);
                    Cache.Update(x.Id, includedModel);
                })));
            }
            return(model);
        }
Esempio n. 8
0
 public IRemoteConfigurator Use(HttpResponseListener httpResponseListener)
 {
     HttpResponseListeners.Add(httpResponseListener);
     return(this);
 }
Esempio n. 9
0
        private async Task <TModel> Create <TModel>(Type rootModelType, object model)
        {
            ThrowIfDisposed();

            // set Id if unset
            var modelId = model == null
                ? Guid.NewGuid()
                : ModelRegistry.GetOrCreateId(model);

            if (modelId == Guid.Empty)
            {
                modelId = Guid.NewGuid();
                ModelRegistry.SetId(model, modelId);
            }

            // Create a new model instance if not already existing
            if (model == null)
            {
                model = Activator.CreateInstance <TModel>();
                ModelRegistry.SetId(model, modelId);
            }

            if (ModelRegistry.IsManagedModel(model))
            {
                throw new ManagedModelCreationException(model.GetType(), modelId);
            }

            // all unmanaged models in the object graph, including root
            var allModels = ModelRegistry.IncludedModelsCreate(model);

            foreach (var newModel in allModels)
            {
                var newResource = BuildModelResource(newModel);
                // Update the model instance in the argument
                var initialize = newModel.GetType().GetInitializeMethod();
                initialize.Invoke(newModel, new object[] { newResource, this });
            }

            var rootResource = ModelRegistry.GetResource(model);
            var includes     = allModels.Where(x => x != model).Select(ModelRegistry.GetResource).ToArray();

            if (Log.IsDebugEnabled())
            {
                Log.Debug(() => $"preparing to POST {rootResource.Type}:{{{rootResource.Id}}}");
                foreach (var include in includes)
                {
                    Log.Debug(() => $"preparing to POST included {include.Type}:{{{include.Id}}}");
                }
            }


            var root    = ResourceRootSingle.FromResource(rootResource, includes);
            var request = await HttpRequestBuilder.CreateResource(root);

            var response = await HttpClient.SendAsync(request).ConfigureAwait(false);

            HttpResponseListener.CreateResource(response.StatusCode, root);
            response.CheckStatusCode();
            if (response.StatusCode == HttpStatusCode.Created)
            {
                var responseRoot = await response.GetContentModel <ResourceRootSingle>(JsonSettings);

                // Update the model instance in the argument
                var initialize = rootModelType.GetInitializeMethod();
                initialize.Invoke(model, new object[] { responseRoot.Data, this });
            }

            // create and cache includes
            await Task.WhenAll(allModels.Select(x => Task.Run(() =>
            {
                var resource = ModelRegistry.GetResource(x);
                Cache.Update(resource.Id, x);
            })));

            return((TModel)model);
        }