diff --git a/AmplitudeSharp/AmplitudeService.cs b/AmplitudeSharp/AmplitudeService.cs index 87c2207..6735990 100644 --- a/AmplitudeSharp/AmplitudeService.cs +++ b/AmplitudeSharp/AmplitudeService.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -13,25 +13,30 @@ namespace AmplitudeSharp { public class AmplitudeService : IDisposable { - public static AmplitudeService s_instance; + private static AmplitudeService s_instance; internal static Action s_logger; - public static AmplitudeService Instance - { - get - { - return s_instance; - } - } + public static AmplitudeService Instance => s_instance; - private object lockObject; - private List eventQueue; - private CancellationTokenSource cancellationToken; + private readonly object lockObject; + private readonly List eventQueue; + private readonly CancellationTokenSource cancellationToken; private Thread sendThread; - private AmplitudeApi api; + private readonly AmplitudeApi api; private AmplitudeIdentify identification; - private SemaphoreSlim eventsReady; - private long sessionId; + private readonly SemaphoreSlim eventsReady; + private long sessionId = -1; + private readonly JsonSerializerSettings apiJsonSerializerSettings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None, + }; + private readonly JsonSerializerSettings persistenceJsonSerializerSettings = new JsonSerializerSettings + { + TypeNameHandling = TypeNameHandling.Objects, + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.None, + }; /// /// Sets Offline mode, which means the events are never sent to actual amplitude service @@ -39,49 +44,37 @@ public static AmplitudeService Instance /// public bool OfflineMode { - get - { - return api.OfflineMode; - } - set - { - api.OfflineMode = value; - } + get => api.OfflineMode; + set => api.OfflineMode = value; } /// /// Additional properties to send with every event /// - public Dictionary ExtraEventProperties { get; private set; } = new Dictionary(); + public Dictionary ExtraEventProperties { get; } = new Dictionary(); private AmplitudeService(string apiKey) { lockObject = new object(); - api = new AmplitudeApi(apiKey); + api = new AmplitudeApi(apiKey, apiJsonSerializerSettings); eventQueue = new List(); cancellationToken = new CancellationTokenSource(); eventsReady = new SemaphoreSlim(0); - - JsonConvert.DefaultSettings = () => new JsonSerializerSettings() - { - NullValueHandling = NullValueHandling.Ignore, - Formatting = Formatting.None - }; } public void Dispose() - { + { Uninitialize(); s_instance = null; } /// /// Initialize AmplitudeSharp - /// Takes an API key for the project and, optionally, + /// Takes an API key for the project and, optionally, /// a stream where offline/past events are stored /// /// api key for the project to stream data to - /// optinal, stream with saved event data + /// optional, stream with saved event data /// Action delegate for logging purposes, if none is specified is used /// public static AmplitudeService Initialize(string apiKey, Action logger = null, Stream persistenceStream = null) @@ -179,21 +172,13 @@ public void NewSession() sessionId = DateTime.UtcNow.ToUnixEpoch(); } - /// - /// Log an event without any parameters - /// - /// the name of the event - public void Track(string eventName) - { - Track(eventName, null); - } /// /// Log an event with parameters /// /// the name of the event /// parameters for the event (this can just be a dynamic class) - public void Track(string eventName, object properties) + public void Track(string eventName, object properties = null ) { var identification = this.identification; @@ -201,11 +186,11 @@ public void Track(string eventName, object properties) { AmplitudeEvent e = new AmplitudeEvent(eventName, properties, ExtraEventProperties) { - SessionId = sessionId + SessionId = sessionId, + UserId = identification.UserId, + DeviceId = identification.DeviceId, }; - e.UserId = identification.UserId; - e.DeviceId = identification.DeviceId; QueueEvent(e); } else @@ -233,7 +218,7 @@ private void SaveEvents(Stream persistenceStore) { try { - string persistedData = JsonConvert.SerializeObject(eventQueue, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Objects }); + string persistedData = JsonConvert.SerializeObject(eventQueue, persistenceJsonSerializerSettings); using (var writer = new StreamWriter(persistenceStore)) { writer.Write(persistedData); @@ -241,7 +226,7 @@ private void SaveEvents(Stream persistenceStore) } catch (Exception e) { - AmplitudeService.s_logger(LogLevel.Error, $"Failed to persist events: {e.ToString()}"); + AmplitudeService.s_logger(LogLevel.Error, $"Failed to persist events: {e}"); } } } @@ -253,7 +238,7 @@ private void LoadPastEvents(Stream persistenceStore) using (var reader = new StreamReader(persistenceStore)) { string persistedData = reader.ReadLine(); - var data = JsonConvert.DeserializeObject>(persistedData, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.Objects }); + var data = JsonConvert.DeserializeObject>(persistedData, persistenceJsonSerializerSettings); eventQueue.InsertRange(0, data); eventsReady.Release(); @@ -261,7 +246,7 @@ private void LoadPastEvents(Stream persistenceStore) } catch (Exception e) { - AmplitudeService.s_logger(LogLevel.Error, $"Failed to load persisted events: {e.ToString()}"); + s_logger(LogLevel.Error, $"Failed to load persisted events: {e}"); } } @@ -270,9 +255,11 @@ private void LoadPastEvents(Stream persistenceStore) /// private void StartSendThread() { - sendThread = new Thread(UploadThread); - sendThread.Name = $"{nameof(AmplitudeSharp)} Upload Thread"; - sendThread.Priority = ThreadPriority.BelowNormal; + sendThread = new Thread(UploadThread) + { + Name = $"{nameof(AmplitudeSharp)} Upload Thread", + Priority = ThreadPriority.BelowNormal, + }; sendThread.Start(); } @@ -357,7 +344,7 @@ private async void UploadThread() catch (Exception e) { // No matter what exception happens, we just quit - s_logger(LogLevel.Error, "Upload thread terminated with: " + e.ToString()); + s_logger(LogLevel.Error, "Upload thread terminated with: " + e); } } } diff --git a/AmplitudeSharp/AmplitudeSharp.csproj b/AmplitudeSharp/AmplitudeSharp.csproj index b0b6180..205a4cc 100644 --- a/AmplitudeSharp/AmplitudeSharp.csproj +++ b/AmplitudeSharp/AmplitudeSharp.csproj @@ -1,70 +1,12 @@ - - - - - Debug - AnyCPU - {D8A6ABA8-3B25-4D8E-9B29-D6BA8BF83DAB} - Library - Properties - AmplitudeSharp - AmplitudeSharp - v4.5 - 512 - - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - ..\packages\Newtonsoft.Json.11.0.2\lib\net45\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + net9.0 + + + + + + + + diff --git a/AmplitudeSharp/Api/AmplitudeApi.cs b/AmplitudeSharp/Api/AmplitudeApi.cs index ae5a6ff..6ae4109 100644 --- a/AmplitudeSharp/Api/AmplitudeApi.cs +++ b/AmplitudeSharp/Api/AmplitudeApi.cs @@ -4,6 +4,7 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; +using Newtonsoft.Json; namespace AmplitudeSharp.Api { @@ -29,16 +30,18 @@ class AmplitudeApi : IAmplitudeApi private string apiKey; private HttpClient httpClient; private HttpClientHandler httpHandler; + private readonly JsonSerializerSettings jsonSerializerSettings; - public AmplitudeApi(string apiKey) + public AmplitudeApi(string apiKey, JsonSerializerSettings jsonSerializerSettings) { this.apiKey = apiKey; + this.jsonSerializerSettings = jsonSerializerSettings; - httpHandler = new HttpClientHandler(); - httpHandler.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip; - httpHandler.Proxy = WebRequest.GetSystemWebProxy(); - httpHandler.UseProxy = true; - + httpHandler = new HttpClientHandler { + AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, + Proxy = WebRequest.GetSystemWebProxy(), + UseProxy = true, + }; httpClient = new HttpClient(httpHandler); } @@ -49,21 +52,21 @@ public void ConfigureProxy(string proxyUserName, string proxyPassword) httpHandler.Proxy = WebRequest.GetSystemWebProxy(); } else - { + { httpHandler.Proxy.Credentials = new NetworkCredential(proxyUserName, proxyPassword); - } + } } public override Task Identify(AmplitudeIdentify identification) { - string data = Newtonsoft.Json.JsonConvert.SerializeObject(identification); + string data = JsonConvert.SerializeObject(identification, jsonSerializerSettings); return DoApiCall("identify", "identification", data); } public override Task SendEvents(List events) { - string data = Newtonsoft.Json.JsonConvert.SerializeObject(events); + string data = JsonConvert.SerializeObject(events, jsonSerializerSettings); return DoApiCall("httpapi", "event", data); } @@ -117,7 +120,7 @@ private async Task DoApiCall(string endPoint, string paramName, stri catch (Exception e) { result = SendResult.ServerError; - AmplitudeService.s_logger(LogLevel.Warning, $"Failed to get device make/model: {e.ToString()}"); + AmplitudeService.s_logger(LogLevel.Warning, $"Failed to get device make/model: {e}"); } } diff --git a/AmplitudeSharp/DeviceHelper.cs b/AmplitudeSharp/DeviceHelper.cs index 6be26a3..c883c66 100644 --- a/AmplitudeSharp/DeviceHelper.cs +++ b/AmplitudeSharp/DeviceHelper.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; -using System.Management; +// TODO(revive): Revive this once .NET Core 3.0 is released +//using System.Management; using AmplitudeSharp.Utils; namespace AmplitudeSharp @@ -29,13 +30,14 @@ internal DeviceHelper() { try { - var mc = new ManagementClass("Win32_ComputerSystem"); - foreach (ManagementObject mo in mc.GetInstances()) - { - Manufacturer = mo["Manufacturer"].ToString(); - Model = mo["Model"].ToString(); - break; - } + // TODO(revive): Revive this once .NET Core 3.0 is released +// var mc = new ManagementClass("Win32_ComputerSystem"); +// foreach (ManagementObject mo in mc.GetInstances()) +// { +// Manufacturer = mo["Manufacturer"].ToString(); +// Model = mo["Model"].ToString(); +// break; +// } } catch (Exception ex) { @@ -44,12 +46,13 @@ internal DeviceHelper() try { - var mc = new ManagementClass("Win32_OperatingSystem"); - foreach (ManagementObject mo in mc.GetInstances()) - { - OSVersion = mo["Version"].ToString(); - break; - } + // TODO(revive): Revive this once .NET Core 3.0 is released +// var mc = new ManagementClass("Win32_OperatingSystem"); +// foreach (ManagementObject mo in mc.GetInstances()) +// { +// OSVersion = mo["Version"].ToString(); +// break; +// } } catch (Exception ex) { @@ -71,7 +74,7 @@ internal DeviceHelper() } catch (Exception ex) { - AmplitudeService.s_logger(LogLevel.Warning, $"Failed to get device RAM size: {ex.ToString()}"); + AmplitudeService.s_logger(LogLevel.Warning, $"Failed to get device RAM size: {ex}"); } Is64BitDevice = Environment.Is64BitOperatingSystem; diff --git a/AmplitudeSharp/DeviceProperties.cs b/AmplitudeSharp/DeviceProperties.cs index dbf3ac0..e7cf287 100644 --- a/AmplitudeSharp/DeviceProperties.cs +++ b/AmplitudeSharp/DeviceProperties.cs @@ -79,7 +79,8 @@ public DeviceProperties() OSVersion = deviceHelper.OSVersion; DeviceModel = deviceHelper.Model; DeviceManufacturer = deviceHelper.Manufacturer; - NetFrameworkVersion = NetFxHelper.GetNetFxVersion().ToString(); + // TODO(revive): Revive this once .NET Core 3.0 is released +// NetFrameworkVersion = NetFxHelper.GetNetFxVersion().ToString(); RamMbs = deviceHelper.RamMbs; Is64BitDevice = deviceHelper.Is64BitDevice; Language = Thread.CurrentThread.CurrentUICulture.EnglishName; diff --git a/AmplitudeSharp/NetFxHelper.cs b/AmplitudeSharp/NetFxHelper.cs index 1f50f29..48076df 100644 --- a/AmplitudeSharp/NetFxHelper.cs +++ b/AmplitudeSharp/NetFxHelper.cs @@ -1,31 +1,33 @@ using System; -using Microsoft.Win32; +// TODO(revive): Revive this once .NET Core 3.0 is released +//using Microsoft.Win32; namespace AmplitudeSharp { class NetFxHelper { + // TODO(revive): Revive this once .NET Core 3.0 is released /// /// Get the installed .net version as recommended here: /// https://msdn.microsoft.com/en-us/library/hh925568%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396 /// - public static Version GetNetFxVersion() - { - const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; - - using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey)) - { - if (ndpKey != null && ndpKey.GetValue("Release") != null) - { - Version installedVersion = GetNet45Version((int)ndpKey.GetValue("Release")); - - return installedVersion; - } - } - - // If we hit this we have .NET framework version < 4.5, return 4.0 for now - return new Version("4.0"); - } +// public static Version GetNetFxVersion() +// { +// const string subkey = @"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\"; +// +// using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32).OpenSubKey(subkey)) +// { +// if (ndpKey != null && ndpKey.GetValue("Release") != null) +// { +// Version installedVersion = GetNet45Version((int)ndpKey.GetValue("Release")); +// +// return installedVersion; +// } +// } +// +// // If we hit this we have .NET framework version < 4.5, return 4.0 for now +// return new Version("4.0"); +// } // Checking the version using >= will enable forward compatibility. private static Version GetNet45Version(int releaseKey) diff --git a/AmplitudeSharp/Properties/AssemblyInfo.cs b/AmplitudeSharp/Properties/AssemblyInfo.cs deleted file mode 100644 index a18ce02..0000000 --- a/AmplitudeSharp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("Amplitude")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Amplitude")] -[assembly: AssemblyCopyright("Copyright © 2018")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("d8a6aba8-3b25-4d8e-9b29-d6ba8bf83dab")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")]