@@ -14,12 +14,14 @@ This library is one of Segment’s most popular Flagship libraries. It is active
1414 - [ Plugin Architecture] ( #plugin-architecture )
1515 - [ Adding a plugin] ( #adding-a-plugin )
1616 - [ Utility Methods] ( #utility-methods )
17+ - [ Enrichment Closure] ( #enrichment-closure )
1718 - [ Controlling Upload With Flush Policies] ( #controlling-upload-with-flush-policies )
1819 - [ Handling Errors] ( #handling-errors )
1920 - [ Customize HTTP Client] ( #customize-http-client )
2021 - [ Customize Storage] ( #customize-storage )
2122 - [ Json Library] ( #json-library )
2223 - [ Samples] ( #samples )
24+ - [ FAQs] ( #faqs )
2325 - [ Compatibility] ( #compatibility )
2426 - [ Changelog] ( #changelog )
2527 - [ Contributing] ( #contributing )
@@ -90,6 +92,7 @@ To get started with the Analytics-CSharp library:
9092 | `storageProvider ` | Default set to `DefaultStorageProvider `. < br > This set how you want your data to be stored . < br > `DefaultStorageProvider ` is used by default which stores data to local storage . `InMemoryStorageProvider ` is also provided in the library . <br >You can also write your own storage solution by implementing `IStorageProvider ` and `IStorage ` |
9193| `httpClientProvider ` | Default set to `DefaultHTTPClientProvider `. < br > This set a http client provider for analytics use to do network activities. The default provider uses System.Net.Http for network activities. |
9294| `flushPolicies` | Default set to `null`. <br>This set custom flush policies to tell analytics when and how to flush. By default, it converts `flushAt` and `flushInterval` to `CountFlushPolicy` and `FrequencyFlushPolicy`. If a value is given, it overwrites `flushAt` and `flushInterval`. |
95+ | `eventPipelineProvider` | The default is `EventPipelineProvider`. <br>This sets a custom event pipeline to define how Analytics handles events. The default `EventPipelineProvider` processes events asynchronously. Use `SyncEventPipelineProvider` to make manual flush operations synchronous. |
9396
9497## Tracking Methods
9598
@@ -361,6 +364,22 @@ The `reset` method clears the SDK’s internal stores for the current user and g
361364analytics .Reset ()
362365```
363366
367+ ## Enrichment Closure
368+ To modify the properties of an event , you can either write an enrichment plugin that applies changes to all events , or pass an enrichment closure to the analytics call to apply changes to a specific event .
369+
370+ ```c #
371+ analytics .Track (" MyEvent" , properties , @event =>
372+ {
373+ if (@event is TrackEvent trackEvent )
374+ {
375+ // update properties of this event
376+ trackEvent .UserId = " foo" ;
377+ }
378+
379+ return @event ;
380+ });
381+ ```
382+
364383## Controlling Upload With Flush Policies
365384To more granularly control when events are uploaded you can use `FlushPolicies `. ** This will override any setting on `flushAt ` and `flushInterval `, but you can use `CountFlushPolicy ` and `FrequencyFlushPolicy ` to have the same behaviour respectively .**
366385
@@ -584,6 +603,92 @@ For sample usages of the SDK in specific platforms, checkout the following:
584603| | [Custom Logger ](https :// github.com/segmentio/Analytics-CSharp/tree/main/Samples/ConsoleSample/SegmentLogger.cs) |
585604| | [Custom Error Handler ](https :// github.com/segmentio/Analytics-CSharp/tree/main/Samples/ConsoleSample/NetworkErrorHandler.cs) |
586605
606+ ## FAQs
607+
608+ ### Should I make Analytics a singleton or scoped in .NET?
609+
610+ The SDK supports both , but be aware of the implications of choosing one over the other :
611+
612+ | Feature | Singleton | Scoped |
613+ | -- | -- | -- |
614+ | ** Fetch Settings ** | Settings are fetched only once at application startup . | Settings are fetched on every request . |
615+ | ** Flush ** | Supports both async and sync flush . | Requires sync flush . Should flush per event or on page redirect / close to avoid data loss . |
616+ | ** Internal State ** | The internal state (`userId `, `anonId `, etc .) is shared across sessions and cannot be used . (* This is an overhead we are working to minimize *.) | The internal state is safe to use since a new instance is created per request . |
617+ | ** UserId for Events ** | Requires adding `UserIdPlugin ` and calling analytics APIs with `userId ` to associate the correct `userId ` with events . | No need for `UserIdPlugin ` or passing `userId ` in API calls . Instead , call `analytics .Identify ()` to update the internal state with the `userId `. Successive events are auto - stamped with that `userId `. |
618+ | ** Storage ** | Supports both local storage and in - memory storage . | Requires in - memory storage . (* Support for local storage is in progress *.) |
619+
620+
621+ In a nutshell , to register Analytics as singleton :
622+
623+ ```c #
624+ var configuration = new Configuration (
625+ writeKey : " YOUR_WRITE_KEY" ,
626+ // Use in-memory storage to keep the SDK stateless.
627+ // The default storage also works if you want to persist events.
628+ storageProvider : new InMemoryStorageProvider (),
629+ // Use a synchronous pipeline to make manual flush operations synchronized.
630+ eventPipelineProvider : new SyncEventPipelineProvider ()
631+ );
632+
633+ var analytics = new Analytics (configuration );
634+
635+ // Add UserIdPlugin to associate events with the provided userId.
636+ analytics .Add (new UserIdPlugin ());
637+
638+ // Call analytics APIs with a userId. The UserIdPlugin will update the event with the provided userId.
639+ analytics .Track (" user123" , " foo" , properties );
640+
641+ // This is a blocking call due to SyncEventPipelineProvider.
642+ // Use the default EventPipelineProvider for asynchronous flush.
643+ analytics .Flush ();
644+
645+ // Register Analytics as a singleton.
646+ ```
647+
648+ To register Analytics as scoped :
649+
650+ ```c #
651+ var configuration = new Configuration (
652+ writeKey : " YOUR_WRITE_KEY" ,
653+ // Requires in-memory storage.
654+ storageProvider : new InMemoryStorageProvider (),
655+ // Flush per event to prevent data loss in case of a page close.
656+ // Alternatively, manually flush on page close.
657+ flushAt : 1 ,
658+ // Requires a synchronous flush.
659+ eventPipelineProvider : new SyncEventPipelineProvider ()
660+ );
661+
662+ var analytics = new Analytics (configuration );
663+
664+ // Update the internal state with a userId.
665+ analytics .Identify (" user123" );
666+
667+ // Subsequent events are auto-stamped with the userId from the internal state.
668+ analytics .Track (" foo" , properties );
669+
670+ // This is a blocking call due to SyncEventPipelineProvider.
671+ analytics .Flush ();
672+
673+ // Register Analytics as scoped.
674+ ```
675+
676+ ### Which JSON library does this SDK use?
677+
678+ The SDK supports `.netstandard 1 . 3 ` and `.netstandard 2 . 0 ` and automatically selects the internal JSON library based on the target framework :
679+
680+ * In `.netstandard 1 . 3 `, the SDK uses `Newtonsoft Json .NET `
681+ * In `.netstandard 2 . 0 `, the SDK uses `System .Text .Json `
682+
683+ Be ware that both Analytics .NET and Analytics .Xamarin use `Newtonsoft Json .NET `. If you encounter issues where JSON dictionary values are turned into empty arrays , it is likely that :
684+
685+ 1 . You are targeting `.netstandard 2 . 0 `.
686+ 2 . Your properties use `Newtonsoft Json .NET ` objects or arrays .
687+
688+ To resolve this , you can :
689+ * Option 1 : Target `.netstandard 1 . 3 `
690+ * Option 2 : Upgrade your JSON library to `System .Text .Json `
691+
587692## Compatibility
588693This library targets `.NET Standard 1 . 3 ` and `.NET Standard 2 . 0 `. Checkout [here ](https :// www.nuget.org/packages/Segment.Analytics.CSharp/#supportedframeworks-body-tab) for compatible platforms.
589694
0 commit comments