Proceso de certificación de Skill para Alexa con Alexa .NET

Una vez tengamos nuestro skill terminado tendremos que pasar por un proceso de certificación para mandarlo a revisión y finalmente tenerlo público para todos los usuarios. Aquí te cuento como es el proceso y los errores comunes:

Lo primero es llenar toda la información en la sección distribution, por cada uno de los lenguajes que estemos soportando para nuestra skill. Podemos llenar uno de los lenguajes y utiliza la opción Copy From an existing locale y de esta manera replicar la misma información, esto es super útil cuando tenemos idiomas similares como en la imagen donde se ven los 3 tipos de español soportado por alexa (Spanish US, Spanish MX, Spanish):

En los ejemplos de las frases de como usar nuestra skill, debemos tener en cuenta que estos se van a usar directamente en la prueba de nuestro skill, deben ser funcionales y por otro lado tener buena ortografía.

Una vez llenada toda la información de distribución de nuestro skill pasamos al modulo de validación, debemos usarlo cada vez que hagamos un cambio en nuestra skill para validar que todo este OK para el usuario final que la va usar:

Un error común que nos puede aparecer al principio es relacionado con el certificado de la URL, básicamente debemos tener en cuenta validar el formato correcto del request que estamos recibiendo.

Si agregamos el siguiente código podemos cumplir con esta validación:

private static async Task ValidateRequest(HttpRequest request, ILogger log, SkillRequest skillRequest)
{
    request.Headers.TryGetValue("SignatureCertChainUrl", out var           signatureChainUrl);
    if (string.IsNullOrWhiteSpace(signatureChainUrl))
    {
      log.LogError("Validation failed. Empty SignatureCertChainUrl header");
      return false;
     } 
    Uri certUrl;
        try
        {
            certUrl = new Uri(signatureChainUrl);
        }
        catch
        {
            log.LogError($"Validation failed. SignatureChainUrl not valid: {signatureChainUrl}");
            return false;
        }

        request.Headers.TryGetValue("Signature", out var signature);
        if (string.IsNullOrWhiteSpace(signature))
        {
            log.LogError("Validation failed - Empty Signature header");
            return false;
        }

        request.Body.Position = 0;
        var body = await request.ReadAsStringAsync();
        request.Body.Position = 0;

        if (string.IsNullOrWhiteSpace(body))
        {
            log.LogError("Validation failed - the JSON is empty");
            return false;
        }

        bool isTimestampValid = RequestVerification.RequestTimestampWithinTolerance(skillRequest);
        bool valid = await RequestVerification.Verify(signature, certUrl, body);

        if (!valid || !isTimestampValid)
        {
            log.LogError("Validation failed - RequestVerification failed");
            return false;
        }
        else
        {
            return true;
        }
    }

    [FunctionName("Alexa")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");

        string json = await req.ReadAsStringAsync();
        var skillRequest = JsonConvert.DeserializeObject<SkillRequest>(json);
        var requestType = skillRequest.GetRequestType();

        SkillResponse response = null;

        bool isValid = await ValidateRequest(req, log, skillRequest);

        if (!isValid)   return new BadRequestResult();

Otro error bastante común es relacionado con las opciones de salir o cancelar en el momento que nuestro skill este procesando algo.

                    case "amazon.stopintent":
                        response = ResponseBuilder.Empty();
                        response.Response.ShouldEndSession = true;
                        break;
                    case "amazon.cancelintent":
                        response = ResponseBuilder.Tell("cancelado.");
                        response.Response.ShouldEndSession = true;
                        break;

Es importante que siempre devolvamos una respuesta aunque sea vacía y que terminemos la sesión en ese momento. También nos podemos fijar si en otros comandos que estemos usando que no sean de cancelación, también lo tenemos implementado (response.Response.ShouldEndSession = true;). Si estamos usando un Switch para identificar el intent, es importante que retornemos algo en el default:

  default:
     response = ResponseBuilder.Tell("No seleccionaste ninguna acción válida");
     response.Response.ShouldEndSession = true;
  break;

Por otro lado también podemos obtener un error por no escribir la ayuda que es requerida para poder certificar el skill. El intent “amazon.helpintent” debe tener una implementación. Y es importante que utilices el metodo Ask y no termines la sesión al terminar el request de ayuda.

Este es un ejemplo de implementación para la ayuda de nuestri skill:

case "amazon.helpintent":
   var stringBuilderHelp = new StringBuilder();
   stringBuilderHelp.Append("Con este skill puedes consultar información");
   stringBuilderHelp.AppendLine("Prueba: dime las noticias, para escuchar noticias");
   stringBuilderHelp.AppendLine("Prueba: dime las noticias económicas, para escuchar las noticias económicas ");
   stringBuilderHelp.AppendLine("Que acción deseas realizar? ");

response = ResponseBuilder.Ask(stringBuilderHelp.ToString(), null);
response.Response.ShouldEndSession = false;
break;

Puedes contactarme si tienes mas errores o alguno problema, pero básicamente este el proceso para publicar tu skill.

Los mismos errores pueden suceder con otras plataformas o tecnologías como Node.js.

Mas info:

https://techcommunity.microsoft.com/t5/windows-dev-appconsult/build-your-first-alexa-skill-with-alexa-net-and-azure-functions/ba-p/317947