# Adición de Umami Tracking Client Follow Up

<!--category-- ASP.NET, Umami -->
<datetime class="hidden">2024-08-27T02:00</datetime>

# El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.

El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. [El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.](/blog/addingumamitrackingclient) He esbozado cómo podría funcionar un cliente de seguimiento para Umami en C#
No obstante, la mayoría de los países en desarrollo no han adoptado medidas concretas para combatir el VIH/SIDA. `IHostedService`).

[TOC]

# En la misma sesión, el Consejo aprobó el proyecto de resolución A/C.2/57/L.20 sin someterlo a votación (véase párr.

La API de seguimiento Umami es muy discreta y muy sencilla. Así que tuve que actualizar el código del cliente para manejar los siguientes:

1. La API espera una 'realM SK1 que sea User-Agent stringMSC3 Así que tuve que actualizar el cliente para usar una real User -Agented string (o, para ser más exactos, he capturado una verdadera User\ -\ Agent string de un navegador y he utilizado esa
2. La API lo espera'la entrada de JSON en un formato muy específico;las cadenas vacías no son permitidasM SK2 Así que tuve que actualizar el cliente para manejar esto .
3. El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. [Node API cliente](https://github.com/umami-software/node) tiene un poco de una superficie estrancha. Es' no está claro inmediatamente lo que espera la APIM SK2 Así que he tenido que hacer un poco del error y la prueba para conseguir que funcione .

## El cliente API de Node

El cliente API de Node en total es inferior, él' su superflexible pero REALmente no bien documentadoM SK2

```javascript
export interface UmamiOptions {
  hostUrl?: string;
  websiteId?: string;
  sessionId?: string;
  userAgent?: string;
}

export interface UmamiPayload {
  website: string;
  session?: string;
  hostname?: string;
  language?: string;
  referrer?: string;
  screen?: string;
  title?: string;
  url?: string;
  name?: string;
  data?: {
    [key: string]: string | number | Date;
  };
}

export interface UmamiEventData {
  [key: string]: string | number | Date;
}

export class Umami {
  options: UmamiOptions;
  properties: object;

  constructor(options: UmamiOptions = {}) {
    this.options = options;
    this.properties = {};
  }

  init(options: UmamiOptions) {
    this.options = { ...this.options, ...options };
  }

  send(payload: UmamiPayload, type: 'event' | 'identify' = 'event') {
    const { hostUrl, userAgent } = this.options;

    return fetch(`${hostUrl}/api/send`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'User-Agent': userAgent || `Mozilla/5.0 Umami/${process.version}`,
      },
      body: JSON.stringify({ type, payload }),
    });
  }

  track(event: object | string, eventData?: UmamiEventData) {
    const type = typeof event;
    const { websiteId } = this.options;

    switch (type) {
      case 'string':
        return this.send({
          website: websiteId,
          name: event as string,
          data: eventData,
        });
      case 'object':
        return this.send({ website: websiteId, ...(event as UmamiPayload) });
    }

    return Promise.reject('Invalid payload.');
  }

  identify(properties: object = {}) {
    this.properties = { ...this.properties, ...properties };
    const { websiteId, sessionId } = this.options;

    return this.send(
      { website: websiteId, session: sessionId, data: { ...this.properties } },
      'identify',
    );
  }

  reset() {
    this.properties = {};
  }
}

const umami = new Umami();

export default umami;
```

Como usted ve, expone los siguientes métodos:

1. `init` - Para configurar las opciones.
2. `send` El Comité recomienda que el Estado Parte adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre hombres y mujeres en materia de empleo, incluida la eliminación del trabajo forzoso.
3. `track` - Seguir un eventoM SK1
4. `identify` - Para identificar a un usuario.
5. `reset` - Para restablecer las propiedades.

La Comisión Consultiva en Asuntos Administrativos y de Presupuesto recomienda a la Asamblea General que apruebe el siguiente proyecto de resolución: `send` method que envía la carga de pago al API.

```javascript
  send(payload: UmamiPayload, type: 'event' | 'identify' = 'event') {
    const { hostUrl, userAgent } = this.options;

    return fetch(`${hostUrl}/api/send`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'User-Agent': userAgent || `Mozilla/5.0 Umami/${process.version}`,
      },
      body: JSON.stringify({ type, payload }),
    });
  }
```

# El cliente C#

Para empezar, he copiado bastante el cliente API de Node's `UmamiOptions` El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. `UmamiPayload` El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.

Así que ahora mi `Send` el método parece esto:

```csharp
     public async Task<HttpResponseMessage> Send(UmamiPayload? payload=null, UmamiEventData? eventData =null,  string type = "event")
        {
            var websiteId = settings.WebsiteId;
             payload = PopulateFromPayload(websiteId, payload, eventData);
            
            var jsonPayload = new { type, payload };
            logger.LogInformation("Sending data to Umami: {Payload}", JsonSerializer.Serialize(jsonPayload, options));

            var response = await client.PostAsJsonAsync("api/send", jsonPayload, options);

            if (!response.IsSuccessStatusCode)
            {
                logger.LogError("Failed to send data to Umami: {StatusCode}, {ReasonPhrase}", response.StatusCode, response.ReasonPhrase);
            }
            else
            {
                var content = await response.Content.ReadAsStringAsync();
                logger.LogInformation("Successfully sent data to Umami: {StatusCode}, {ReasonPhrase}, {Content}", response.StatusCode, response.ReasonPhrase, content);
            }

            return response;
        }

```

La Comisión Consultiva en Asuntos Administrativos y de Presupuesto examinó el proyecto de presupuesto por programas para el bienio 2002-2003 (A/60/6 (Sect.

1. El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. `PopulateFromPayload` método que llena la carga de pago con el websiteId y el eventData.
2. La serialización JSON de la carga de trabajo, necesita excluir valores nulos.

## El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. `PopulateFromPayload` El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre hombres y mujeres en materia de empleo, incluida la eliminación del trabajo forzoso.

```csharp
        public static UmamiPayload PopulateFromPayload(string webSite, UmamiPayload? payload, UmamiEventData? data)
        {
            var newPayload = GetPayload(webSite, data: data);
            if(payload==null) return newPayload;
            if(payload.Hostname != null)
                newPayload.Hostname = payload.Hostname;
            if(payload.Language != null)
                newPayload.Language = payload.Language;
            if(payload.Referrer != null)
                newPayload.Referrer = payload.Referrer;
            if(payload.Screen != null)
                newPayload.Screen = payload.Screen;
            if(payload.Title != null)
                newPayload.Title = payload.Title;
            if(payload.Url != null)
                newPayload.Url = payload.Url;
            if(payload.Name != null)
                newPayload.Name = payload.Name;
            if(payload.Data != null)
                newPayload.Data = payload.Data;
            return newPayload;          
        }
        
        private static UmamiPayload GetPayload(string websiteId, string? url = null, UmamiEventData? data = null)
        {
            var payload = new UmamiPayload
            {
            Website = websiteId,
                Data = data,
                Url = url ?? string.Empty
            };
            

            return payload;
        }

```

Usted puede ver que siempre garantizamos el `websiteId` se fija y sólo fijamos los demás valores si no son nulos. Esto nos da flexibilidad a costa de un poco de verbosidad.

## La configuración de HttpClient

Como se mencionó antes, necesitamos dar una cadena User-Agent algo real a la API. Esto se hace en el `HttpClient` El Comité recomienda que el Estado Parte adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre hombres y mujeres en materia de empleo, incluida la adopción de medidas legislativas, administrativas, judiciales y de otra índole.

```csharp
              services.AddHttpClient<UmamiClient>((serviceProvider, client) =>
            {
                 umamiSettings = serviceProvider.GetRequiredService<UmamiClientSettings>();
            client.DefaultRequestHeaders.Add("User-Agent", $"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36");
            client.BaseAddress = new Uri(umamiSettings.UmamiPath);
        }).SetHandlerLifetime(TimeSpan.FromMinutes(5))  //Set lifetime to five minutes
        .AddPolicyHandler(GetRetryPolicy())
       #if DEBUG 
        .AddLogger<HttpLogger>();
        #else
        ;
        #endif

```

## El Comité recomienda que el Estado Parte adopte todas las medidas necesarias para garantizar la igualdad de oportunidades entre los hombres y las mujeres en materia de empleo, incluida la eliminación del trabajo forzoso.

Esta es otra. `IHostedService`, ahí ' hay un montón de artículos sobre cómo configurar estos, así que ganó'no entrar en él aquí.

El único punto de dolor era el uso del injeto. `HttpClient` El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. `UmamiClient` class. Debido al alcance del cliente & el servicio utilizo un `IServiceScopeFactory` se introducirá en el constructor del HostedService y luego lo capturará para cada solicitud de envío.

```csharp
    

    private async Task SendRequest(CancellationToken token)
    {
        logger.LogInformation("Umami background delivery started");

        while (await _channel.Reader.WaitToReadAsync(token))
        {
            while (_channel.Reader.TryRead(out var payload))
            {
                try
                {
                   using  var scope = scopeFactory.CreateScope();
                    var client = scope.ServiceProvider.GetRequiredService<UmamiClient>();
                    // Send the event via the client
                    await client.Send(payload.Payload);

                    logger.LogInformation("Umami background event sent: {EventType}", payload.EventType);
                }
                catch (OperationCanceledException)
                {
                    logger.LogWarning("Umami background delivery canceled.");
                    return; // Exit the loop on cancellation
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, "Error sending Umami background event.");
                }
            }
        }
    }
   
```

### El Comité recomienda que el Estado Parte adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.

Ahora que tenemos este servicio hosted, podemos mejorar significativamente el rendimiento enviando los eventos en el fondo.

I'lo he utilizado en un par de lugares diferentes, en mi `Program.cs` Decidí experimentar con el seguimiento de la solicitud de feed RSS usando Middleware, sólo detecta cualquier ruta terminando en 'RSSM SK2 y envía un evento de fondoMSC3

```csharp
app.Use( async (context, next) =>
{
var path = context.Request.Path.Value;
if (path.EndsWith("RSS", StringComparison.OrdinalIgnoreCase))
{
var rss = context.RequestServices.GetRequiredService<UmamiBackgroundSender>();
// Send the event in the background
await rss.SendBackground(new UmamiPayload(){Url  = path, Name = "RSS Feed"});
}
await next();
});
```

I' también ha pasado más datos de mi `TranslateAPI` El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.
Que me permite ver cuánto tiempo tardan las traducciones; nota ningún de estos bloquea el hilo principal O sigue a los usuarios individuales.

```csharp
    
       await  umamiClient.SendBackground(new UmamiPayload(){  Name = "Get Translation"}, new UmamiEventData(){{"timetaken", translationTask.TotalMilliseconds}, {"language",translationTask.Language}});
        var result = new TranslateResultTask(translationTask, true);
```

# El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.

El API de Umami es un poco curioso pero es'es una gran manera de seguir los acontecimientos en sí mismo-como se ha pedidoM SK2 Espera que yo ' tenga la oportunidad de limpiarlo aún más y obtener un paquete de nuggets Umami ahí fueraMSC4
El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer. [El Comité recomienda al Estado Parte que adopte todas las medidas necesarias para garantizar la igualdad entre los géneros y el empoderamiento de la mujer.](/blog/addingascsharpclientforumamiapi) Quiero extraer datos de Umami para proporcionar características como la clasificación de popularidad.