/// <summary> /// Get details of all schemas in the project. /// </summary> /// <returns></returns> public async Task <JArray> GetSchemas() { if (string.IsNullOrWhiteSpace(_readKey)) { throw new KeenException("An API ReadKey is required to get schemas."); } var responseMsg = await _keenHttpClient .GetAsync(_eventsRelativeUrl, _readKey) .ConfigureAwait(continueOnCapturedContext: false); var responseString = await responseMsg .Content .ReadAsStringAsync() .ConfigureAwait(continueOnCapturedContext: false); var response = JArray.Parse(responseString); // error checking, throw an exception with information from the json // response if available, then check the HTTP response. KeenUtil.CheckApiErrorCode(response); if (!responseMsg.IsSuccessStatusCode) { throw new KeenException("GetSchemas failed with status: " + responseMsg.StatusCode); } return(response); }
/// <summary> /// Get details of all schemas in the project. /// </summary> /// <returns></returns> public async Task <JArray> GetSchemas() { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("Authorization", _prjSettings.MasterKey); client.DefaultRequestHeaders.Add("Keen-Sdk", KeenUtil.GetSdkVersion()); var responseMsg = await client.GetAsync(_serverUrl) .ConfigureAwait(continueOnCapturedContext: false); var responseString = await responseMsg.Content.ReadAsStringAsync() .ConfigureAwait(continueOnCapturedContext: false); dynamic response = JArray.Parse(responseString); // error checking, throw an exception with information from the json // response if available, then check the HTTP response. KeenUtil.CheckApiErrorCode(response); if (!responseMsg.IsSuccessStatusCode) { throw new KeenException("GetSchemas failed with status: " + responseMsg.StatusCode); } return(response); } }
/// <summary> /// Add a single event to the specified collection. /// </summary> /// <param name="collection">Collection name</param> /// <param name="eventInfo">The event to add.</param> /// <param name="addOns">Optional collection of Data Enhancement Add-ons</param> public async Task AddEventAsync(string collection, object eventInfo, IEnumerable <AddOn> addOns = null) { // Preconditions KeenUtil.ValidateEventCollectionName(collection); if (null == eventInfo) { throw new KeenException("Event data is required."); } if (string.IsNullOrWhiteSpace(_prjSettings.WriteKey)) { throw new KeenException("Write API key is required for AddEvent"); } var jEvent = PrepareUserObject(eventInfo, addOns); // If an event cache has been provided, cache this event insead of sending it. if (null != EventCache) { await EventCache.Add(new CachedEvent(collection, jEvent)) .ConfigureAwait(false); } else { await EventCollection.AddEvent(collection, jEvent) .ConfigureAwait(false); } }
/// <summary> /// Add all events in a single request. /// </summary> /// <param name="events"></param> /// <returns></returns> public async Task <IEnumerable <CachedEvent> > AddEvents(JObject events) { var content = events.ToString(); using (var client = new HttpClient()) using (var contentStream = new StreamContent(new MemoryStream(Encoding.UTF8.GetBytes(content)))) { contentStream.Headers.Add("content-type", "application/json"); client.DefaultRequestHeaders.Add("Authorization", _prjSettings.WriteKey); client.DefaultRequestHeaders.Add("Keen-Sdk", KeenUtil.GetSdkVersion()); var httpResponse = await client.PostAsync(_serverUrl, contentStream) .ConfigureAwait(continueOnCapturedContext: false); var responseString = await httpResponse.Content.ReadAsStringAsync() .ConfigureAwait(continueOnCapturedContext: false); JObject jsonResponse = null; try { // Normally the response content should be parsable JSON, // but if the server returned a 404 error page or something // like that, this will throw. jsonResponse = JObject.Parse(responseString); } catch (Exception) { } if (!httpResponse.IsSuccessStatusCode) { throw new KeenException("AddEvents failed with status: " + httpResponse); } if (null == jsonResponse) { throw new KeenException("AddEvents failed with empty response from server."); } // error checking, return failed events in the list, // or if the HTTP response is a failure, throw. var failedItems = from respCols in jsonResponse.Properties() from eventsCols in events.Properties() where respCols.Name == eventsCols.Name let collection = respCols.Name let combined = eventsCols.Children().Children() .Zip(respCols.Children().Children(), (e, r) => new { eventObj = (JObject)e, result = (JObject)r }) from e in combined where !(bool)(e.result.Property("success").Value) select new CachedEvent(collection, e.eventObj, KeenUtil.GetBulkApiError(e.result)); return(failedItems); } }
/// <summary> /// Convert a user-supplied object to a JObject that can be sent to the Keen.IO API. /// /// This writes any global properties to the object and records the time. /// </summary> /// <param name="eventInfo"></param> /// <param name="addOns">Optional collection of Data Enhancement Add-ons</param> /// <returns></returns> private JObject PrepareUserObject(object eventInfo, IEnumerable <AddOn> addOns) { var jEvent = JObject.FromObject(eventInfo); // Add global properties to the event foreach (var p in _globalProperties) { // If the property value is an IDynamicPropertyValue, // exec the Value() to generate the property value. var dynProp = p.Value as IDynamicPropertyValue; if (dynProp == null) { KeenUtil.ValidatePropertyName(p.Key); jEvent.Add(p.Key, JToken.FromObject(p.Value)); } else { var val = dynProp.Value(); if (null == val) { throw new KeenException(string.Format("Dynamic property \"{0}\" returned a null value", p.Key)); } jEvent.Add(p.Key, JToken.FromObject(val)); } } // Ensure this event has a 'keen' object of the correct type if (null == jEvent.Property("keen")) { jEvent.Add("keen", new JObject()); } else if (jEvent.Property("keen").Value.GetType() != typeof(JObject)) { throw new KeenException(string.Format("Value of property \"keen\" must be an object, is {0}", jEvent.Property("keen").GetType())); } var keen = ((JObject)jEvent.Property("keen").Value); if (addOns != null && addOns.Any()) { keen.Add("addons", JArray.FromObject(addOns)); } // Set the keen.timestamp if it has not already been set if (null == keen.Property("timestamp")) { keen.Add("timestamp", DateTime.Now); } return(jEvent); }
/// <summary> /// Retrieve the schema for the specified collection. This requires /// a value for the project settings Master API key. /// </summary> /// <param name="collection"></param> public async Task <dynamic> GetSchemaAsync(string collection) { // Preconditions KeenUtil.ValidateEventCollectionName(collection); if (string.IsNullOrWhiteSpace(_prjSettings.MasterKey)) { throw new KeenException("Master API key is required for GetSchema"); } return(await EventCollection.GetSchema(collection) .ConfigureAwait(continueOnCapturedContext: false)); }
/// <summary> /// Delete the specified collection. Deletion may be denied for collections with many events. /// Master API key is required. /// </summary> /// <param name="collection">Name of collection to delete.</param> public async Task DeleteCollectionAsync(string collection) { // Preconditions KeenUtil.ValidateEventCollectionName(collection); if (string.IsNullOrWhiteSpace(_prjSettings.MasterKey)) { throw new KeenException("Master API key is required for DeleteCollection"); } await EventCollection.DeleteCollection(collection) .ConfigureAwait(continueOnCapturedContext: false); }
public async System.Threading.Tasks.Task DeleteCollection(string collection) { using (var client = new HttpClient()) { client.DefaultRequestHeaders.Add("Authorization", _prjSettings.MasterKey); client.DefaultRequestHeaders.Add("Keen-Sdk", KeenUtil.GetSdkVersion()); var responseMsg = await client.DeleteAsync(_serverUrl + collection) .ConfigureAwait(continueOnCapturedContext: false); if (!responseMsg.IsSuccessStatusCode) { throw new KeenException("DeleteCollection failed with status: " + responseMsg.StatusCode); } } }
/// <summary> /// Add a static global property. This property will be added to /// every event. /// </summary> /// <param name="property">Property name</param> /// <param name="value">Property value. This may be a simple value, array, or object, /// or an object that supports IDynamicPropertyValue returning one of those.</param> public void AddGlobalProperty(string property, object value) { // Verify that the property name is allowable, and that the value is populated. KeenUtil.ValidatePropertyName(property); if (value == null) { throw new KeenException("Global properties must have a non-null value."); } var dynProp = value as IDynamicPropertyValue; if (dynProp != null) { // Execute the property once before it is needed to check the value ExecDynamicPropertyValue(property, dynProp); } _globalProperties.Add(property, value); }
public async Task AddEvent(string collection, JObject anEvent) { if (string.IsNullOrWhiteSpace(_writeKey)) { throw new KeenException("An API WriteKey is required to add events."); } var content = anEvent.ToString(); var responseMsg = await _keenHttpClient .PostAsync(GetCollectionUrl(collection), _writeKey, content) .ConfigureAwait(continueOnCapturedContext: false); var responseString = await responseMsg .Content .ReadAsStringAsync() .ConfigureAwait(continueOnCapturedContext: false); JObject jsonResponse = null; try { // Normally the response content should be parsable JSON, // but if the server returned a 404 error page or something // like that, this will throw. jsonResponse = JObject.Parse(responseString); } catch (Exception) { } // error checking, throw an exception with information from the // json response if available, then check the HTTP response. KeenUtil.CheckApiErrorCode(jsonResponse); if (!responseMsg.IsSuccessStatusCode) { throw new KeenException("AddEvent failed with status: " + responseMsg.StatusCode); } }
public async System.Threading.Tasks.Task AddEvent(string collection, JObject anEvent) { var content = anEvent.ToString(); using (var client = new HttpClient()) using (var contentStream = new StreamContent(new MemoryStream(Encoding.UTF8.GetBytes(content)))) { contentStream.Headers.Add("content-type", "application/json"); client.DefaultRequestHeaders.Add("Authorization", _prjSettings.WriteKey); client.DefaultRequestHeaders.Add("Keen-Sdk", KeenUtil.GetSdkVersion()); var httpResponse = await client.PostAsync(_serverUrl + collection, contentStream) .ConfigureAwait(continueOnCapturedContext: false); var responseString = await httpResponse.Content.ReadAsStringAsync() .ConfigureAwait(continueOnCapturedContext: false); JObject jsonResponse = null; try { // Normally the response content should be parsable JSON, // but if the server returned a 404 error page or something // like that, this will throw. jsonResponse = JObject.Parse(responseString); } catch (Exception) { } // error checking, throw an exception with information from the // json response if available, then check the HTTP response. KeenUtil.CheckApiErrorCode(jsonResponse); if (!httpResponse.IsSuccessStatusCode) { throw new KeenException("AddEvent failed with status: " + httpResponse); } } }
public async Task <JObject> GetSchema(string collection) { // TODO : So much of this code, both in the constructor and in the actual message // dispatch, response parsing and error checking is copy/paste across Queries, Event // and EventCollection everywhere we use KeenHttpClient. We could shove some of that // into shared factory functionality (for the ctor stuff) and some of it into the // KeenHttpClient (for the dispatch/response portions). if (string.IsNullOrWhiteSpace(_readKey)) { throw new KeenException("An API ReadKey is required to get collection schema."); } var responseMsg = await _keenHttpClient .GetAsync(GetCollectionUrl(collection), _readKey) .ConfigureAwait(continueOnCapturedContext: false); var responseString = await responseMsg .Content .ReadAsStringAsync() .ConfigureAwait(continueOnCapturedContext: false); dynamic response = JObject.Parse(responseString); // error checking, throw an exception with information from the json // response if available, then check the HTTP response. KeenUtil.CheckApiErrorCode(response); if (!responseMsg.IsSuccessStatusCode) { throw new KeenException("GetSchema failed with status: " + responseMsg.StatusCode); } return(response); }
/// <summary> /// Add all events in a single request. /// </summary> /// <param name="events"></param> /// <returns></returns> public async Task <IEnumerable <CachedEvent> > AddEvents(JObject events) { if (string.IsNullOrWhiteSpace(_writeKey)) { throw new KeenException("An API WriteKey is required to add events."); } var content = events.ToString(); var responseMsg = await _keenHttpClient .PostAsync(_eventsRelativeUrl, _writeKey, content) .ConfigureAwait(continueOnCapturedContext: false); var responseString = await responseMsg .Content .ReadAsStringAsync() .ConfigureAwait(continueOnCapturedContext: false); JObject jsonResponse = null; try { // Normally the response content should be parsable JSON, // but if the server returned a 404 error page or something // like that, this will throw. jsonResponse = JObject.Parse(responseString); // TODO : Why do we not call KeenUtil.CheckApiErrorCode(jsonResponse); ?? } catch (Exception) { } if (!responseMsg.IsSuccessStatusCode) { throw new KeenException("AddEvents failed with status: " + responseMsg.StatusCode); } if (null == jsonResponse) { throw new KeenException("AddEvents failed with empty response from server."); } // error checking, return failed events in the list, // or if the HTTP response is a failure, throw. var failedItems = from respCols in jsonResponse.Properties() from eventsCols in events.Properties() where respCols.Name == eventsCols.Name let collection = respCols.Name let combined = eventsCols.Children().Children() .Zip(respCols.Children().Children(), (e, r) => new { eventObj = (JObject)e, result = (JObject)r }) from e in combined where !(bool)(e.result.Property("success").Value) select new CachedEvent(collection, e.eventObj, KeenUtil.GetBulkApiError(e.result)); return(failedItems); }