The Keen IO .NET SDK can be used to do custom analytics and event tracking for .NET applications. Use this SDK to capture large volumes of event data such as user actions, errors, server interactions, or any arbitrary event you specify. The SDK posts your events to Keen IO, a highly available, scalable cloud datastore. See Keen IO docs for instructions on extracting, querying, and building custom analytics with your data.
The .NET SDK is currently comprised of a single project which produces two DLLs from which to choose based on the target platform.
This class library currently multi-targets .NET Standard 2.0 and .NET Framework 4.5. These two libraries should be able to cover most scenarios, including .NET Framework, .NET Standard in various environments/operating systems, UWP, Unity, Xamarin and other types of projects.
The easiest way to get started with the Keen IO .NET SDK is to use the KeenClient NuGet package.
Install the NuGet package by running the following command from the NuGet Package Manager Console:
PM> Install-Package KeenClient
...or if using the .NET Core SDK tools:
$ dotnet add package KeenClient
The most up-to-date code is available in the following repository:
https://github.com/keenlabs/keen-sdk-net
The core object you'll interact with to add events to a collection is the KeenClient
object. When creating a KeenClient
instance, you'll want to provide it with a ProjectSettingsProvider
instance that contains details about your project id, keys, and optionally a different root URL for Keen.IO's API.
using Keen.Core;
...
var projectSettings = new ProjectSettingsProvider("YourProjectID", writeKey: "YourWriteKey");
var keenClient = new KeenClient(projectSettings);
Event data is provided to the client as an object. A simple way to do this is with an anonymous object:
var purchase = new
{
category = "magical animals",
username = "hagrid",
price = 7.13,
payment_type = "information",
animal_type = "norwegian ridgeback dragon"
};
keenClient.AddEvent("purchases", purchase);
Sometimes you want to record events in a non-blocking manner. This is pretty simple:
keenClient.AddEventAsync("purchases", purchase);
Static global properties are added with the KeenClient
's AddGlobalProperty
method:
keenClient.AddGlobalProperty("client_type", "mobile");
Static global properties are added at the root level of all events just before they are sent or cached.
Dynamic global properties are an SDK concept that can be added in the same way, but rather than a static object, an object implementing IDynamicPropertyValue
is added. The class DynamicPropertyValue
implements this interface and may be used to provide dynamic properties with a Func<object>
delegate:
var dynProp = new DynamicPropertyValue(() => new Random().Next(9999));
keenClient.AddGlobalProperty("bonus_field", dynProp);
The delegate is executed each time event data is added as well as during the AddGlobalProperty
call.
Keen IO can enrich event data by parsing or joining it with other data sets. This is done through the concept of “add-ons”. See the Keen IO API documentation for more on this. The .NET SDK enables add-ons with the Keen.DataEnrichment.AddOn
class.
// Build an event object
var purchase = new
{
category = "magical animals",
username = "hagrid",
price = 7.13,
payment_type = "information",
animal_type = "norwegian ridgeback dragon",
user_ip = "8.8.8.8",
ua = "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; .NET CLR 1.0.3705)"
};
var addOns = new[]
{
AddOn.IpToGeo("user_ip", "user_geo"),
AddOn.UserAgentParser("ua", "user_agent")
};
// send the event
keenClient.AddEvent("purchases", purchase, addOns);
When the event is recorded the "user_geo" and "user_agent" fields will be populated automatically by the Keen IO API.
static void Main(string[] args)
{
// Set up the client
var projectSettings = new ProjectSettingsProvider("YourProjectID", writeKey: "YourWriteKey");
var keenClient = new KeenClient(projectSettings);
keenClient.AddGlobalProperty("client_type", "mobile");
var dynProp = new DynamicPropertyValue(() => new Random().Next(9999));
keenClient.AddGlobalProperty("bonus_field", dynProp );
// Build an event object
var purchase = new
{
category = "magical animals",
username = "hagrid",
price = 7.13,
payment_type = "information",
animal_type = "norwegian ridgeback dragon",
user_ip = "8.8.8.8",
ua = "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt; .NET CLR 1.0.3705)"
};
var addOns = new[]
{
AddOn.IpToGeo("user_ip", "user_geo"),
AddOn.UserAgentParser("ua", "user_agent")
};
// send the event
keenClient.AddEvent("purchases", purchase, addOns);
}
KeenClient supports an event data cache interface that allows transmission of event data to the Keen IO server to be deferred until you call SendCachedEvents(). You may implement your own cache by supporting the IEventCache interface or you may use one of the two cache classes included, EventCacheMemory and EventCachePortable which store event data in memory and in portable storage, respectively.
To enable caching provide an instance supporting IEventCache when constructing KeenClient:
var client = new KeenClient(new ProjectSettingsProviderEnv(), new EventCacheMemory());
Or:
var client = new KeenClient(new ProjectSettingsProviderEnv(), EventCachePortable.New());
Events are added as usual, and at any time you may transmit the cached events to the server:
client.SendCachedEvents();
The server may reject one or more events included in the cache. If this happens the item that was rejected will be recorded and transmission of the remaining cached events will continue. After all events in the cache have been transmitted, if any events were rejected they will be attached as instances of CachedEvent to an instance of KeenBulkException which will then be thrown. The KeenBulkException FailedEvents property may be accessed to review the failures.
Global properties are evaluated and added when AddEvent() is called, so dynamic properties will not be evaluated when SendCachedEvents() is called.
To run analyses on your data, use the provided KeenClient.Query
family of methods. For example:
var itemCount = keenClient.Query(QueryType.Count(), "target_collection", null);
An async
version of this analysis could be run as follows:
var itemCount = await keenClient.QueryAsync(QueryType.Count(), "target_collection", null);
Additional qualifiers can be added to the analysis, such as the target property to use for analyses that require it. A timeframe and/or list of filters to use for the analysis can also be provided. If you'd like to get results in a grouped or time interval format, the KeenClient.QueryGroup
, KeenClient.QueryInterval
, and KeenClient.QueryIntervalGroup
synchronous and asynchronous methods can be used. See the Grouped and Interval Query Results and Filters sections below for more detail.
Multi-analysis is a way to run multiple analyses over the same dataset. For more information about multi-analysis, see the API documentation.
To perform multi-analysis, use the KeenClient.QueryMultiAnalysis
family of methods.
IEnumerable<MultiAnalysisParam> analyses = new List<MultiAnalysisParam>()
{
new MultiAnalysisParam("purchases", MultiAnalysisParam.Metric.Count()),
new MultiAnalysisParam("max_price", MultiAnalysisParam.Metric.Maximum("price")),
new MultiAnalysisParam("min_price", MultiAnalysisParam.Metric.Minimum("price"))
};
var result = keenClient.QueryMultiAnalysis("purchases", analyses);
var purchases = int.Parse(result["purchases"]);
var maxPrice = float.Parse(result["max_price"]);
Returns the number of unique actors that successfully (or unsuccessfully) make it through a series of steps. “Actors” could mean users, devices, or any other identifiers that are meaningful to you. For more information about Funnels, see the Funnel API documentation.
To perform funnel analysis, KeenClient
exposes the methods QueryFunnel
and QueryFunnelAsync
, which are used as follows:
IEnumerable<FunnelStep> funnelSteps = new List<FunnelStep>
{
new FunnelStep
{
EventCollection = "registered_users",
ActorProperty = "id"
},
new FunnelStep
{
EventCollection = "subscribed_users",
ActorProperty = "user_id"
},
};
var result = keenClient.QueryFunnel(funnelSteps);
var registeredUsers = result.ElementAt(0);
var registeredAndSubscribedUserCount = result.ElementAt(1);
A timeframe can be specified for analysis using the QueryRelativeTimeframe
and QueryAbsoluteTimeframe
classes, along with an optional timezone
parameter passed to the KeenClient.Query
method when using QueryRelativeTimeframe
. The timezone
parameter must be one of the timezones supported by the Keen IO API as specified here.
For example:
var relativeTimeframe = QueryRelativeTimeframe.ThisWeek();
var timezone = "US/Pacific"; // If not specified, timezone defaults to "UTC"
var countUnique = keenClient.Query(QueryType.CountUnique(), "target_collection", "target_property", relativeTimeframe, timezone: timezone);
Here's an example using an absolute timeframe. Note that timezone information is included in the DateTime struct, and therefore shouldn't be provided as an additional parameter.
var absoluteTimeframe = new QueryAbsoluteTimeframe(DateTime.Now.AddMonths(-1), DateTime.Now));
var countUnique = keenClient.Query(QueryType.CountUnique(), "target_collection", "target_property", absoluteTimeframe);
Analyses, multi-analysis, and funnel steps all support using filters to be more specific about the dataset being worked on. For simple analyses and multi-analyses, provide an IEnumerable<QueryFilter>
to the KeenClient.Query
or KeenClient.QueryMultiAnalysis
method of choice. For funnel analysis, filters can be specified on each FunnelStep
through the FunnelStep.Filters
property.
var filters = new List<QueryFilter>()
{
new QueryFilter("field1", QueryFilter.FilterOperator.GreaterThan(), "1")
};
var result = keenClient.Query(QueryType.Count(), "user_registrations", null, filters: filters);
To perform analysis or multi-analysis with results grouped by a column value, separated by a timeframe, or a combination of both, there are versions of the KeenClient.Query
and KeenClient.QueryMultiAnalysis
methods available. These include KeenClient.QueryInterval
, KeenClient.QueryGroup
, KeenClient.QueryIntervalGroup
and their corresponding asynchronous methods for single-analysis. For multi-analysis, similar methods exist including KeenClient.QueryMultiAnalysisGroup
, KeenClient.QueryMultiAnalysisInterval
, KeenClient.QueryMultiAnalysisIntervalGroup
, and the asynchronous versions of those methods. See the Keen IO group by and interval API documentation for more about these types of analyses.
Scoped keys are customized API keys you can generate yourself. Each key has a defined scope of allowed operations (read/write), along with a set of predetermined filters that are applied to every request. See the Keen IO API reference for more information on scoped keys.
The .NET SDK includes methods for generating scoped keys. You'll find them under the Keen.Core
namespace as ScopedKey.Encrypt
, ScopedKey.EncryptString
, and ScopedKey.Decrypt
.
// Create a filter to apply when using the scoped key
IDictionary<string, object> filter = new ExpandoObject();
filter.Add("property_name", "account_id");
filter.Add("operator", "eq");
filter.Add("property_value", 123);
dynamic options = new ExpandoObject();
// Set filters for the key
options.filters = new List<object>() { filter };
// Set read/write permissions for the key
options.allowed_operations = new List<string>() { "read" };
// Generate the key using the given master key and options
var scopedKey = ScopedKey.Encrypt(masterKey, (object)options);
// Decrypt the key to get the key's filters and permissions
var decrypted = ScopedKey.Decrypt(masterKey, scopedKey);
var decryptedOptions = JObject.Parse(decrypted);