0 0
Read Time:5 Minute, 53 Second

Creating alexa skills with .NET – part 6 Basic Alexa rest service.

in Part 5 we setup the new skill for testing, via the developer portal, a real device or a simulated alexa.

While the skill now works, it’s not in a state where it would pass the testing the skill would undergo during certification. The actual skill we have done would also be too basic to be allowed anyway so we will not be submitting it for certification at all but in this section we will cover the basic changes needed.

One of the first things we need to change is the security on the rest service. The Alexa certification process will fail the skill unless some basic security measures are in place. One of these is that the request needs to come from the Alexa system and so this is the part which would affect you using the service for other purposes.

There are a number of nuget packages that are provided to work in conjunction with the Alexa.Net package we use, these are found on the project page here.

We will be using some of these in later articles but for the moment the one we need is not listed above, Alexa.Net.Security.Middleware.

To implement the security we need to make two changes to our startup.cs file in the visual studio solution.

We need to add a using statement to the start of the file and add in the alexa security to the service near the end of the file.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Alexa.NET.Security.Middleware;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;


namespace TestyMcTestfaceAPI
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseAlexaRequestValidation(); //This automates all the required alexa security checks
            app.UseMvc();
        }
    }
}

The app.UseAlexaRequestValidation() switches on the security needed as a minimum by Alexa and by using this module we lose the flexibility of choosing when to use it but gain the benefit of not having to keep up to date with changes in the requirements over time (we hopefully just need to update the package).

NOTE: It is possible to remove this check after certification and run without it being in place but this is generally not advised.

The next thing we should implement is the handling of the defat intents that Amazon requires to be supported. These have changed over time and so we need to be prepared to revise our code each time we try for a new certification, but once certified we will not be required to make changes until we next need to submit a skill change.

The changes we need to make are in the testycontroller.cs file, we add in processing to handle the required intents

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Alexa.NET;
using Alexa.NET.Request;
using Alexa.NET.Request.Type;
using Alexa.NET.Response;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;

namespace TestyMcTestfaceAPI.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class testyController : ControllerBase
    {


        [HttpPost("handler")]
        public async Task<SkillResponse> handler([FromBody] SkillRequest skillRequest)
        {

            var requestType = skillRequest.GetRequestType();

            SkillResponse response = null;

            if (requestType == typeof(LaunchRequest))
            {
                response = ResponseBuilder.Tell("Welcome to Testy McTestface. How can we help you?");
                response.Response.ShouldEndSession = false;
                return response;
            }
            if (requestType == typeof(SessionEndedRequest))
            {
                response = ResponseBuilder.Tell("Goodbye");
                response.Response.ShouldEndSession = true;
                return response;
            }

            if (requestType == typeof(IntentRequest) || requestType == typeof(BuiltInIntent))
            {
                var intentRequest = skillRequest.Request as IntentRequest;
                if (intentRequest.Intent.Name == "AMAZON.StopIntent")
                {
                    response = ResponseBuilder.Tell("Goodbye");
                    response.Response.ShouldEndSession = true;
                    return response;
                }
                if (intentRequest.Intent.Name == "AMAZON.CancelIntent")
                {
                    response = ResponseBuilder.Tell("Goodbye");
                    response.Response.ShouldEndSession = true;
                    return response;
                }
                if (intentRequest.Intent.Name == "AMAZON.NavigateHomeIntent")
                {
                    response = ResponseBuilder.Tell("Goodbye");
                    response.Response.ShouldEndSession = true;
                    return response;
                }
                if (intentRequest.Intent.Name == "AMAZON.HelpIntent")
                {
                    response = ResponseBuilder.Tell("You can ask me to say something. How may we help you now?");
                    response.Response.ShouldEndSession = false;
                    return response;
                }
            }

            return ResponseBuilder.Tell("Hi, I'm Testy McTestFace");
        }
    }
}

Basically the above code, for each builtin intent, gives some form of reply and either ends the users session of leaves it open.

Sessions should be left open when we expect the user to continue asking the skill something, it should be closed however when we have completed the skills use, so for example the cancel intent should always close the session but the open intent must never close the session.

If the code drops through to the last statement we assume it is the intent we added in specifically, for the current implementation that is actually ok, but in reality we would want to be checking that the intent is the correct one for the reply we are giving

                if (intentRequest.Intent.Name == "AMAZON.HelpIntent")
                {
                    response = ResponseBuilder.Tell("You can ask me to say something. How may we help you now?");
                    response.Response.ShouldEndSession = false;
                    return response;
                }

                if (intentRequest.Intent.Name == "IntentTalkToMe")
                {
                    return ResponseBuilder.Tell("Hi, I'm Testy McTestFace");
                }


            }


            return ResponseBuilder.Tell("Hi, something has went wrong");
        }
    }
}

The above would be a possible alternative, in this we have revised the last few parts of the controller method to handle our intent specifically and give a default message for anything not handled specifically.

We could use this method, or use a switch statement etc. to add in any number of basic intents and would just need to update and rebuild the interaction model to define these.

There really is not that much more to a basic, no parameter intent, it’s that simple, handle the intent, format your reply and reply.

One useful feature that can be used if your action may take some time is to give what its known as a progressive reply, these allow your skill to send back a reply while preparing the last reply

var progressiveResponse = new ProgressiveResponse(skillRequest);
await progressiveResponse.SendSpeech("Please wait...");

If the above was added before our final reply then we would have the alexa device saying ‘Please wait’ while the skill code continues to process the intent.

This basically completes this simple skill type where a specific intent runs with no ‘options’ and gives a reply.

The completed source code for this stage of the article can be found at https://github.com/raymondjstone/AlexaNetExampleStage02

In part 7 we will enhance the app but allowing it to have access to, and use some data specific to the user.

About Post Author

raymond

Been developing software for 40 plus years, started with Apple ]['s moved on to a variety of mainframes, PC's, Atari ST/Falcon, Psion's then onto more web related stuff (when there was an internet) and mobile apps (Xamarin.Forms) for IOS and Android.
Happy
Happy
0 %
Sad
Sad
0 %
Excited
Excited
0 %
Sleepy
Sleepy
0 %
Angry
Angry
0 %
Surprise
Surprise
0 %

Average Rating

5 Star
0%
4 Star
0%
3 Star
0%
2 Star
0%
1 Star
0%

Leave a Reply