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); }
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); }))); }
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); }
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); }
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); }
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); }
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); }
public IRemoteConfigurator Use(HttpResponseListener httpResponseListener) { HttpResponseListeners.Add(httpResponseListener); return(this); }
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); }