Documentation

Démarrage rapide .NET et Blazor

Le paquet WordsAreFlowing.Sdk cible .NET 10 et fournit un composant Blazor pour la demande privée. Son stockage par défaut est le localStorage du navigateur, par Blazor WebAssembly.

1. Installer

dotnet add package WordsAreFlowing.Sdk

Les paquets sont sur nuget.org. WordsAreFlowing.Sdk apporte WordsAreFlowing.Sdk.Core, le moteur que partagent toutes les têtes.

2. Inscrire

Dans Program.cs, appelez AddWordsAreFlowing avec la clé de votre produit. Les options sont un WordsAreFlowingOptions ; ApiKey est la seule obligatoire, et l'inscription lève une ArgumentException sans elle.

using WordsAreFlowing.Sdk;

builder.Services.AddWordsAreFlowing(o =>
{
    o.ApiKey = "waf_live_…";
    o.AppVersion = "1.4.0";
});

Cela inscrit un IFeedbackLoop, l'unique objet du SDK. Chaque pièce propre à l'hôte (stockage, horloge, invite, transport) est inscrite avec TryAdd, donc une inscription que vous faites avant cet appel l'emporte.

Pas sur Blazor WebAssembly ? Le stockage par défaut exige l'environnement JavaScript en cours de processus de WebAssembly et lève une exception ailleurs (Blazor Server, par exemple). Inscrivez votre propre IKeyValueStore avant d'appeler AddWordsAreFlowing. InMemoryKeyValueStore existe, mais il ne garde rien d'une exécution à l'autre, donc les occurrences et les délais repartent de zéro chaque fois.

3. Afficher la demande privée

Placez le composant FeedbackAsk une fois dans votre mise en page et donnez-lui la boucle.

@using WordsAreFlowing.Sdk.Components
@using WordsAreFlowing.Sdk.Core.Engine
@inject IFeedbackLoop Loop

<FeedbackAsk Loop="@Loop" />

Le composant écoute DecisionMade et ne s'ouvre que lorsqu'une décision le demande. Il envoie la note avec SubmitFeedbackAsync, et « Pas maintenant » appelle DismissAskAsync. Il n'appelle jamais TrackAsync, donc il ne peut jamais causer d'invite d'évaluation. Son texte est en anglais ou en français, selon la culture d'interface courante ; passez un FeedbackAskTexts comme Texts pour changer n'importe quelle chaîne.

À son premier rendu, le composant appelle aussi InitializeAsync, qui charge les règles en cache puis va chercher les nouvelles si le réseau le permet. Si vous mettez InitializeOnFirstRender="false", appelez-la vous-même ; on peut l'appeler plus d'une fois sans risque. Un changement de règles fait dans le portail atteint un appareil la prochaine fois qu'InitializeAsync s'y exécute.

4. Signaler les déclencheurs

Appelez TrackAsync là où un moment de comportement survient dans votre code — une fois la chose faite, pas depuis un bouton « Évaluez-nous ».

private async Task OnWorkoutSaved()
{
    // ... une fois l'enregistrement réussi
    var decision = await Loop.TrackAsync("workout_completed");
    if (decision.Kind == DecisionKind.None)
        Console.WriteLine($"Words Are Flowing: {decision.Reason}");
}

Il compte une occurrence sur l'appareil, interroge le moteur et retourne une Decision : son Kind est un DecisionKind (None, AskRequested ou StorePromptFired), et pour None, sa Reason nomme la règle qui a bloqué — la liste complète est dans la référence des règles. Il ne lève pas d'exception : une défaillance dans la boucle revient comme None avec la raison error.

Votre propre demande au lieu du composant

Loop.DecisionMade += d =>
{
    if (d.Kind == DecisionKind.AskRequested) ShowMyAsk(d.Trigger);
};

// quand la personne envoie (rating vaut de 1 à 5, ou null)
var result = await Loop.SubmitFeedbackAsync(trigger, message, rating);
if (!result.Ok) ShowError(result.Code);

// quand la personne ferme sans écrire
await Loop.DismissAskAsync(trigger);

DecisionMade est émis après chaque TrackAsync, y compris les décisions None. SubmitFeedbackAsync retourne un TransportResult ; une note qui échoue n'est pas renvoyée pour vous, alors gardez ce que la personne a écrit et laissez-la réessayer. Quand Ok est faux, Code porte le code du serveur s'il a refusé la note (par exemple feedback.empty pour un message vide, ou feedback.too_long au-delà de 2 000 caractères).

Pas d'invite d'évaluation sur le Web

Un navigateur n'a pas d'invite d'évaluation native. Sur le Web, une règle d'invite dont les conditions sont remplies se termine par None avec la raison prompter_unavailable. Pour diriger les gens du Web vers votre fiche en magasin, affichez un simple lien avec StoreLinks — jamais un bouton qui prétend ouvrir une invite d'évaluation.

var ids = Loop.CurrentRules?.StoreIds;
var play = StoreLinks.GooglePlay(ids?.AndroidPackage);  // null si non défini
var appStore = StoreLinks.AppStore(ids?.IosAppId);

Les identifiants de magasin viennent du produit dans le portail et voyagent dans les règles, accessibles par CurrentRules une fois InitializeAsync exécutée.

Options

OptionSens
ApiKeyObligatoire. La clé du produit.
AppVersionEnvoyée avec chaque note.
UserIdFacultatif. Votre propre identifiant pour la personne, envoyé avec chaque note pour que vous puissiez retrouver ou supprimer ses notes. Jusqu'à 128 caractères parmi A–Z a–z 0–9 _ . : @ -.
AttributesFacultatif. Des paires clé-valeur envoyées avec chaque note et comparées par les conditions des règles. Jusqu'à 20 clés ; une valeur est une chaîne (jusqu'à 200 caractères), un booléen ou un nombre.
MaxStorePromptsPerYearAbaisse le plafond d'invites d'évaluation pour cette application. Il ne peut jamais le monter au-delà de 3.
FlushThresholdLes compteurs sont envoyés quand ce nombre de compteurs distincts attend. Par défaut, 10. FlushAsync les envoie tout de suite, à moins qu'un envoi ait échoué dans les cinq dernières minutes.
BaseAddressL'API d'ingestion. Par défaut, le service hébergé.
PlatformIndiquée sur les notes. Par défaut, web.

Les compteurs qui n'atteignent pas le serveur restent en attente, et le SDK ne fait aucune nouvelle tentative pendant cinq minutes. Une note envoyée avec succès envoie la file avec elle, même pendant ces cinq minutes.