diff --git a/.nuget/AlexaSkillsKit.Lib.nuspec b/.nuget/AlexaSkillsKit.Lib.nuspec
deleted file mode 100644
index 8249581..0000000
--- a/.nuget/AlexaSkillsKit.Lib.nuspec
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
- AlexaSkillsKit.NET
- 1.5.2
- AlexaSkillsKit.NET
- Stefan Negritoiu (FreeBusy)
- Stefan Negritoiu (FreeBusy)
- https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET
- http://opensource.org/licenses/MIT
- https://developer.amazon.com/public/binaries/content/gallery/developerportalpublic/solutions/alexa/dp_image_kit_02.png
- false
-
-.NET library that simplifies Alexa skills development; same object model as Amazon's AlexaSkillsKit for Java
-
-
-1.3.0: Incorporated Sept 2015 ASK update for account linking and access tokens
-1.4.0: Ability to override request validation policy and support for SSML output speech type
-1.5.0: Fully implement certificate verification requirement and support for Standard cards
-1.5.2: reimplement request timestamp parsing to accept both ISO 8601 and Unix time formats
-
- Copyright 2017 Stefan Negritoiu (FreeBusy) and contributors
- amazon echo alexa speechlet
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.nuget/pack.cmd b/.nuget/pack.cmd
deleted file mode 100644
index 0c350f8..0000000
--- a/.nuget/pack.cmd
+++ /dev/null
@@ -1,2 +0,0 @@
-msbuild /property:Configuration=Release ..\AlexaSkillsKit.Lib\AlexaSkillsKit.Lib.csproj
-nuget pack AlexaSkillsKit.Lib.nuspec
\ No newline at end of file
diff --git a/AlexaSkillsKit.Interfaces.AudioPlayer/AlexaSkillsKit.Interfaces.AudioPlayer.csproj b/AlexaSkillsKit.Interfaces.AudioPlayer/AlexaSkillsKit.Interfaces.AudioPlayer.csproj
new file mode 100644
index 0000000..77aad13
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.AudioPlayer/AlexaSkillsKit.Interfaces.AudioPlayer.csproj
@@ -0,0 +1,32 @@
+
+
+
+ netstandard1.1
+ AlexaSkillsKit
+ Copyright © 2018 Stefan Negritoiu (FreeBusy) and contributors
+
+ Stefan Negritoiu (FreeBusy)
+ Stefan Negritoiu (FreeBusy)
+ 2.0.0
+ https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET.git
+ git
+ http://opensource.org/licenses/MIT
+ Amazon Alexa Skill Echo Show Speechlet .Net AudioPlayer PlaybackController
+ true
+ https://developer.amazon.com/public/binaries/content/gallery/developerportalpublic/solutions/alexa/dp_image_kit_02.png
+ https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET
+ AudioPlayer and PlaybackController interfaces support for AlexaSkillsKit
+
+ 2.0.0: Extract AudioPlayer and PlaybackController interfaces to separate library
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioItem.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioItem.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioItem.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/AudioItem.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioItemStream.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioItemStream.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioItemStream.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/AudioItemStream.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerInterface.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerInterface.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerInterface.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerInterface.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerPlaybackFailedRequest.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerPlaybackFailedRequest.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerPlaybackFailedRequest.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerPlaybackFailedRequest.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerRequest.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerRequest.cs
similarity index 87%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerRequest.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerRequest.cs
index 170e8a5..a40a6d2 100644
--- a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerRequest.cs
+++ b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerRequest.cs
@@ -8,9 +8,7 @@ namespace AlexaSkillsKit.Interfaces.AudioPlayer
///
public class AudioPlayerRequest : ExtendedSpeechletRequest
{
- public static readonly string TypeName = "AudioPlayer";
-
- public AudioPlayerRequest(string subtype, JObject json) : base(TypeName, subtype, json) {
+ public AudioPlayerRequest(string subtype, JObject json) : base(subtype, json) {
Token = json.Value("token");
OffsetInMilliseconds = json.Value("offsetInMilliseconds");
}
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerResponse.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerResponse.cs
similarity index 77%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerResponse.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerResponse.cs
index 30957bd..a849336 100644
--- a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerResponse.cs
+++ b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerResponse.cs
@@ -1,6 +1,4 @@
-// Copyright 2015 Stefan Negritoiu (FreeBusy). See LICENSE file for more information.
-
-using AlexaSkillsKit.Interfaces.AudioPlayer.Directives;
+using AlexaSkillsKit.Interfaces.AudioPlayer.Directives;
using AlexaSkillsKit.Speechlet;
using System.Collections.Generic;
diff --git a/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerSpeechletAsyncWrapper.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerSpeechletAsyncWrapper.cs
new file mode 100644
index 0000000..77ec572
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerSpeechletAsyncWrapper.cs
@@ -0,0 +1,22 @@
+using AlexaSkillsKit.Speechlet;
+using System.Threading.Tasks;
+
+namespace AlexaSkillsKit.Interfaces.AudioPlayer
+{
+ public class AudioPlayerSpeechletAsyncWrapper : IAudioPlayerSpeechletAsync
+ {
+ private readonly IAudioPlayerSpeechlet speechlet;
+
+ public AudioPlayerSpeechletAsyncWrapper(IAudioPlayerSpeechlet speechlet) {
+ this.speechlet = speechlet;
+ }
+
+ public async Task OnAudioPlayerAsync(AudioPlayerRequest audioRequest, Context context) {
+ return speechlet.OnAudioPlayer(audioRequest, context);
+ }
+
+ public async Task OnPlaybackControllerAsync(PlaybackControllerRequest playbackRequest, Context context) {
+ return speechlet.OnPlaybackController(playbackRequest, context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerSpeechletServiceExtensions.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerSpeechletServiceExtensions.cs
new file mode 100644
index 0000000..d6501ab
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.AudioPlayer/AudioPlayerSpeechletServiceExtensions.cs
@@ -0,0 +1,33 @@
+using AlexaSkillsKit.Json;
+using AlexaSkillsKit.Speechlet;
+
+namespace AlexaSkillsKit.Interfaces.AudioPlayer
+{
+ public static class AudioPlayerSpeechletServiceExtensions
+ {
+ public static void AddAudioPlayer(this SpeechletService service, IAudioPlayerSpeechlet speechlet) {
+ service.AddAudioPlayer(new AudioPlayerSpeechletAsyncWrapper(speechlet));
+ }
+
+ public static void AddAudioPlayer(this SpeechletService service, IAudioPlayerSpeechletAsync speechlet) {
+ Deserializer.RegisterDeserializer("AudioPlayer", AudioPlayerInterface.FromJson);
+
+ SpeechletRequestEnvelope.RequestParser.AddInterface("AudioPlayer", (subtype, json) => {
+ switch (subtype) {
+ case "PlaybackFailed":
+ return new AudioPlayerPlaybackFailedRequest(subtype, json);
+ default:
+ return new AudioPlayerRequest(subtype, json);
+ }
+ });
+
+ service.AddHandler(
+ async (request, context) => await speechlet.OnAudioPlayerAsync(request, context));
+
+ SpeechletRequestEnvelope.RequestParser.AddInterface("PlaybackController", (subtype, json) => new PlaybackControllerRequest(subtype, json));
+
+ service.AddHandler(
+ async (request, context) => await speechlet.OnPlaybackControllerAsync(request, context));
+ }
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/Directives/AudioPlayerClearQueueDirective.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/Directives/AudioPlayerClearQueueDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/Directives/AudioPlayerClearQueueDirective.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/Directives/AudioPlayerClearQueueDirective.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/Directives/AudioPlayerDirective.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/Directives/AudioPlayerDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/Directives/AudioPlayerDirective.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/Directives/AudioPlayerDirective.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/Directives/AudioPlayerPlayDirective.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/Directives/AudioPlayerPlayDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/Directives/AudioPlayerPlayDirective.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/Directives/AudioPlayerPlayDirective.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/Directives/AudioPlayerStopDirective.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/Directives/AudioPlayerStopDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/Directives/AudioPlayerStopDirective.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/Directives/AudioPlayerStopDirective.cs
diff --git a/AlexaSkillsKit.Interfaces.AudioPlayer/IAudioPlayerSpeechlet.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/IAudioPlayerSpeechlet.cs
new file mode 100644
index 0000000..60ce0b2
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.AudioPlayer/IAudioPlayerSpeechlet.cs
@@ -0,0 +1,10 @@
+using AlexaSkillsKit.Speechlet;
+
+namespace AlexaSkillsKit.Interfaces.AudioPlayer
+{
+ public interface IAudioPlayerSpeechlet
+ {
+ AudioPlayerResponse OnAudioPlayer(AudioPlayerRequest audioRequest, Context context);
+ AudioPlayerResponse OnPlaybackController(PlaybackControllerRequest playbackRequest, Context context);
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Interfaces.AudioPlayer/IAudioPlayerSpeechletAsync.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/IAudioPlayerSpeechletAsync.cs
new file mode 100644
index 0000000..774d5b5
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.AudioPlayer/IAudioPlayerSpeechletAsync.cs
@@ -0,0 +1,11 @@
+using AlexaSkillsKit.Speechlet;
+using System.Threading.Tasks;
+
+namespace AlexaSkillsKit.Interfaces.AudioPlayer
+{
+ public interface IAudioPlayerSpeechletAsync
+ {
+ Task OnAudioPlayerAsync(AudioPlayerRequest audioRequest, Context context);
+ Task OnPlaybackControllerAsync(PlaybackControllerRequest playbackRequest, Context context);
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/PlaybackControllerRequest.cs b/AlexaSkillsKit.Interfaces.AudioPlayer/PlaybackControllerRequest.cs
similarity index 78%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/PlaybackControllerRequest.cs
rename to AlexaSkillsKit.Interfaces.AudioPlayer/PlaybackControllerRequest.cs
index ceab4e9..8e0fdab 100644
--- a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/PlaybackControllerRequest.cs
+++ b/AlexaSkillsKit.Interfaces.AudioPlayer/PlaybackControllerRequest.cs
@@ -8,9 +8,7 @@ namespace AlexaSkillsKit.Interfaces.AudioPlayer
///
public class PlaybackControllerRequest : ExtendedSpeechletRequest
{
- public static readonly string TypeName = "PlaybackController";
-
- public PlaybackControllerRequest(string subtype, JObject json) : base(TypeName, subtype, json) {
+ public PlaybackControllerRequest(string subtype, JObject json) : base(subtype, json) {
}
}
}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Interfaces.Dialog/AlexaSkillsKit.Interfaces.Dialog.csproj b/AlexaSkillsKit.Interfaces.Dialog/AlexaSkillsKit.Interfaces.Dialog.csproj
new file mode 100644
index 0000000..e1f0188
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.Dialog/AlexaSkillsKit.Interfaces.Dialog.csproj
@@ -0,0 +1,32 @@
+
+
+
+ netstandard1.1
+ AlexaSkillsKit
+ Copyright © 2018 Stefan Negritoiu (FreeBusy) and contributors
+
+ Stefan Negritoiu (FreeBusy)
+ Stefan Negritoiu (FreeBusy)
+ 2.0.0
+ https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET.git
+ git
+ http://opensource.org/licenses/MIT
+ Amazon Alexa Skill Echo Show Speechlet .Net Dialog interface
+ true
+ https://developer.amazon.com/public/binaries/content/gallery/developerportalpublic/solutions/alexa/dp_image_kit_02.png
+ https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET
+ Dialog interface support for AlexaSkillsKit
+
+ 2.0.0: Extract Dialog interface to separate library
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AlexaSkillsKit.Lib/Interfaces/Dialog/Directives/DialogConfirmIntentDirective.cs b/AlexaSkillsKit.Interfaces.Dialog/Directives/DialogConfirmIntentDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Dialog/Directives/DialogConfirmIntentDirective.cs
rename to AlexaSkillsKit.Interfaces.Dialog/Directives/DialogConfirmIntentDirective.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Dialog/Directives/DialogConfirmSlotDirective.cs b/AlexaSkillsKit.Interfaces.Dialog/Directives/DialogConfirmSlotDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Dialog/Directives/DialogConfirmSlotDirective.cs
rename to AlexaSkillsKit.Interfaces.Dialog/Directives/DialogConfirmSlotDirective.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Dialog/Directives/DialogDelegateDirective.cs b/AlexaSkillsKit.Interfaces.Dialog/Directives/DialogDelegateDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Dialog/Directives/DialogDelegateDirective.cs
rename to AlexaSkillsKit.Interfaces.Dialog/Directives/DialogDelegateDirective.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Dialog/Directives/DialogDirective.cs b/AlexaSkillsKit.Interfaces.Dialog/Directives/DialogDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Dialog/Directives/DialogDirective.cs
rename to AlexaSkillsKit.Interfaces.Dialog/Directives/DialogDirective.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Dialog/Directives/DialogElicitSlotDirective.cs b/AlexaSkillsKit.Interfaces.Dialog/Directives/DialogElicitSlotDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Dialog/Directives/DialogElicitSlotDirective.cs
rename to AlexaSkillsKit.Interfaces.Dialog/Directives/DialogElicitSlotDirective.cs
diff --git a/AlexaSkillsKit.Interfaces.Display/AlexaSkillsKit.Interfaces.Display.csproj b/AlexaSkillsKit.Interfaces.Display/AlexaSkillsKit.Interfaces.Display.csproj
new file mode 100644
index 0000000..61d3b24
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.Display/AlexaSkillsKit.Interfaces.Display.csproj
@@ -0,0 +1,32 @@
+
+
+
+ netstandard1.1
+ AlexaSkillsKit
+ Copyright © 2018 Stefan Negritoiu (FreeBusy) and contributors
+
+ Stefan Negritoiu (FreeBusy)
+ Stefan Negritoiu (FreeBusy)
+ 2.0.0
+ https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET.git
+ git
+ http://opensource.org/licenses/MIT
+ Amazon Alexa Skill Echo Show Speechlet .Net Display interface
+ true
+ https://developer.amazon.com/public/binaries/content/gallery/developerportalpublic/solutions/alexa/dp_image_kit_02.png
+ https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET
+ Display interface support for AlexaSkillsKit
+
+ 2.0.0: Extract Display interface to separate library
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AlexaSkillsKit.Lib/Interfaces/Display/Directives/DisplayRenderTemplateDirective.cs b/AlexaSkillsKit.Interfaces.Display/Directives/DisplayRenderTemplateDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Display/Directives/DisplayRenderTemplateDirective.cs
rename to AlexaSkillsKit.Interfaces.Display/Directives/DisplayRenderTemplateDirective.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Display/Directives/HintDirective.cs b/AlexaSkillsKit.Interfaces.Display/Directives/HintDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Display/Directives/HintDirective.cs
rename to AlexaSkillsKit.Interfaces.Display/Directives/HintDirective.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Display/DisplayImage.cs b/AlexaSkillsKit.Interfaces.Display/DisplayImage.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Display/DisplayImage.cs
rename to AlexaSkillsKit.Interfaces.Display/DisplayImage.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Display/DisplayImageSource.cs b/AlexaSkillsKit.Interfaces.Display/DisplayImageSource.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Display/DisplayImageSource.cs
rename to AlexaSkillsKit.Interfaces.Display/DisplayImageSource.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Display/DisplayInterface.cs b/AlexaSkillsKit.Interfaces.Display/DisplayInterface.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Display/DisplayInterface.cs
rename to AlexaSkillsKit.Interfaces.Display/DisplayInterface.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Display/DisplayRequest.cs b/AlexaSkillsKit.Interfaces.Display/DisplayRequest.cs
similarity index 85%
rename from AlexaSkillsKit.Lib/Interfaces/Display/DisplayRequest.cs
rename to AlexaSkillsKit.Interfaces.Display/DisplayRequest.cs
index 5810585..f3d001d 100644
--- a/AlexaSkillsKit.Lib/Interfaces/Display/DisplayRequest.cs
+++ b/AlexaSkillsKit.Interfaces.Display/DisplayRequest.cs
@@ -8,9 +8,7 @@ namespace AlexaSkillsKit.Interfaces.Display
///
public class DisplayRequest : ExtendedSpeechletRequest
{
- public static readonly string TypeName = "Display";
-
- public DisplayRequest(string subtype, JObject json) : base(TypeName, subtype, json) {
+ public DisplayRequest(string subtype, JObject json) : base(subtype, json) {
Token = json.Value("token");
}
diff --git a/AlexaSkillsKit.Interfaces.Display/DisplaySpeechletAsyncWrapper.cs b/AlexaSkillsKit.Interfaces.Display/DisplaySpeechletAsyncWrapper.cs
new file mode 100644
index 0000000..50b0c7a
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.Display/DisplaySpeechletAsyncWrapper.cs
@@ -0,0 +1,18 @@
+using AlexaSkillsKit.Speechlet;
+using System.Threading.Tasks;
+
+namespace AlexaSkillsKit.Interfaces.Display
+{
+ public class DisplaySpeechletAsyncWrapper : IDisplaySpeechletAsync
+ {
+ private readonly IDisplaySpeechlet speechlet;
+
+ public DisplaySpeechletAsyncWrapper(IDisplaySpeechlet speechlet) {
+ this.speechlet = speechlet;
+ }
+
+ public async Task OnDisplayAsync(DisplayRequest displayRequest, Context context) {
+ return speechlet.OnDisplay(displayRequest, context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Interfaces.Display/DisplaySpeechletServiceExtensions.cs b/AlexaSkillsKit.Interfaces.Display/DisplaySpeechletServiceExtensions.cs
new file mode 100644
index 0000000..b97a43d
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.Display/DisplaySpeechletServiceExtensions.cs
@@ -0,0 +1,20 @@
+using AlexaSkillsKit.Json;
+using AlexaSkillsKit.Speechlet;
+
+namespace AlexaSkillsKit.Interfaces.Display
+{
+ public static class DisplaySpeechletServiceExtensions
+ {
+ public static void AddDisplay(this SpeechletService service, IDisplaySpeechlet speechlet) {
+ service.AddDisplay(new DisplaySpeechletAsyncWrapper(speechlet));
+ }
+
+ public static void AddDisplay(this SpeechletService service, IDisplaySpeechletAsync speechlet) {
+ Deserializer.RegisterDeserializer("Display", DisplayInterface.FromJson);
+
+ SpeechletRequestEnvelope.RequestParser.AddInterface("Display", (subtype, json) => new DisplayRequest(subtype, json));
+
+ service.AddHandler(async (request, context) => await speechlet.OnDisplayAsync(request, context));
+ }
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/Interfaces/Display/DisplayTemplate.cs b/AlexaSkillsKit.Interfaces.Display/DisplayTemplate.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Display/DisplayTemplate.cs
rename to AlexaSkillsKit.Interfaces.Display/DisplayTemplate.cs
diff --git a/AlexaSkillsKit.Interfaces.Display/IDisplaySpeechlet.cs b/AlexaSkillsKit.Interfaces.Display/IDisplaySpeechlet.cs
new file mode 100644
index 0000000..13ce303
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.Display/IDisplaySpeechlet.cs
@@ -0,0 +1,9 @@
+using AlexaSkillsKit.Speechlet;
+
+namespace AlexaSkillsKit.Interfaces.Display
+{
+ public interface IDisplaySpeechlet
+ {
+ SpeechletResponse OnDisplay(DisplayRequest displayRequest, Context context);
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Interfaces.Display/IDisplaySpeechletAsync.cs b/AlexaSkillsKit.Interfaces.Display/IDisplaySpeechletAsync.cs
new file mode 100644
index 0000000..2e61cd5
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.Display/IDisplaySpeechletAsync.cs
@@ -0,0 +1,10 @@
+using AlexaSkillsKit.Speechlet;
+using System.Threading.Tasks;
+
+namespace AlexaSkillsKit.Interfaces.Display
+{
+ public interface IDisplaySpeechletAsync
+ {
+ Task OnDisplayAsync(DisplayRequest displayRequest, Context context);
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/Interfaces/Display/ListItem.cs b/AlexaSkillsKit.Interfaces.Display/ListItem.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Display/ListItem.cs
rename to AlexaSkillsKit.Interfaces.Display/ListItem.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Display/TextContent.cs b/AlexaSkillsKit.Interfaces.Display/TextContent.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Display/TextContent.cs
rename to AlexaSkillsKit.Interfaces.Display/TextContent.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/Display/TextField.cs b/AlexaSkillsKit.Interfaces.Display/TextField.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/Display/TextField.cs
rename to AlexaSkillsKit.Interfaces.Display/TextField.cs
diff --git a/AlexaSkillsKit.Interfaces.VideoApp/AlexaSkillsKit.Interfaces.VideoApp.csproj b/AlexaSkillsKit.Interfaces.VideoApp/AlexaSkillsKit.Interfaces.VideoApp.csproj
new file mode 100644
index 0000000..7d9f4ac
--- /dev/null
+++ b/AlexaSkillsKit.Interfaces.VideoApp/AlexaSkillsKit.Interfaces.VideoApp.csproj
@@ -0,0 +1,32 @@
+
+
+
+ netstandard1.1
+ AlexaSkillsKit
+ Copyright © 2018 Stefan Negritoiu (FreeBusy) and contributors
+
+ Stefan Negritoiu (FreeBusy)
+ Stefan Negritoiu (FreeBusy)
+ 2.0.0
+ https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET.git
+ git
+ http://opensource.org/licenses/MIT
+ Amazon Alexa Skill Echo Show Speechlet .Net VideoApp interface
+ true
+ https://developer.amazon.com/public/binaries/content/gallery/developerportalpublic/solutions/alexa/dp_image_kit_02.png
+ https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET
+ VideoApp interface support for AlexaSkillsKit
+
+ 2.0.0: Extract VideoApp interface to separate library
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AlexaSkillsKit.Lib/Interfaces/VideoApp/Directives/VideoAppLaunchDirective.cs b/AlexaSkillsKit.Interfaces.VideoApp/Directives/VideoAppLaunchDirective.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/VideoApp/Directives/VideoAppLaunchDirective.cs
rename to AlexaSkillsKit.Interfaces.VideoApp/Directives/VideoAppLaunchDirective.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/VideoApp/VideoItem.cs b/AlexaSkillsKit.Interfaces.VideoApp/VideoItem.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/VideoApp/VideoItem.cs
rename to AlexaSkillsKit.Interfaces.VideoApp/VideoItem.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/VideoApp/VideoItemMetadata.cs b/AlexaSkillsKit.Interfaces.VideoApp/VideoItemMetadata.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/VideoApp/VideoItemMetadata.cs
rename to AlexaSkillsKit.Interfaces.VideoApp/VideoItemMetadata.cs
diff --git a/AlexaSkillsKit.Lib/AlexaSkillsKit.Lib.csproj b/AlexaSkillsKit.Lib/AlexaSkillsKit.Lib.csproj
deleted file mode 100644
index 4b2396a..0000000
--- a/AlexaSkillsKit.Lib/AlexaSkillsKit.Lib.csproj
+++ /dev/null
@@ -1,167 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {0EC882A8-AACA-4BD5-B449-72F20FDB8586}
- Library
- Properties
- AlexaSkillsKit
- AlexaSkillsKit
- v4.5
- 512
- ..\
- true
-
-
- true
- full
- false
- bin\Debug\
- DEBUG;TRACE
- prompt
- 4
-
-
- pdbonly
- true
- bin\Release\
- TRACE
- prompt
- 4
-
-
-
- ..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll
- True
-
-
- ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
- True
-
-
-
-
-
-
- ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
- True
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/AlexaSkillsKit.csproj b/AlexaSkillsKit.Lib/AlexaSkillsKit.csproj
new file mode 100644
index 0000000..eba9e2d
--- /dev/null
+++ b/AlexaSkillsKit.Lib/AlexaSkillsKit.csproj
@@ -0,0 +1,40 @@
+
+
+
+ netstandard1.1
+ AlexaSkillsKit
+ Copyright © 2018 Stefan Negritoiu (FreeBusy) and contributors
+
+ Stefan Negritoiu (FreeBusy)
+ Stefan Negritoiu (FreeBusy)
+ 2.0.0
+ https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET.git
+ git
+ http://opensource.org/licenses/MIT
+ Amazon Alexa Skill Echo Show Speechlet .Net
+ true
+ https://developer.amazon.com/public/binaries/content/gallery/developerportalpublic/solutions/alexa/dp_image_kit_02.png
+ https://github.com/AreYouFreeBusy/AlexaSkillsKit.NET
+ .NET library that simplifies Alexa skills development; same object model as Amazon's AlexaSkillsKit for Java
+
+1.3.0: Incorporated Sept 2015 ASK update for account linking and access tokens
+1.4.0: Ability to override request validation policy and support for SSML output speech type
+1.5.0: Fully implement certificate verification requirement and support for Standard cards
+1.5.2: reimplement request timestamp parsing to accept both ISO 8601 and Unix time formats
+1.6.0: Support external interfaces, .Net Standard support
+2.0.0: Separate core, API Provider libraries and External interface libraries. Allow providing support for new interfaces and network APIs without intrusion into Core library.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AlexaSkillsKit.Lib/Authentication/SpeechletRequestSignatureVerifier.cs b/AlexaSkillsKit.Lib/Authentication/SpeechletRequestSignatureVerifier.cs
index d5dbc6e..9f25230 100644
--- a/AlexaSkillsKit.Lib/Authentication/SpeechletRequestSignatureVerifier.cs
+++ b/AlexaSkillsKit.Lib/Authentication/SpeechletRequestSignatureVerifier.cs
@@ -1,30 +1,23 @@
// Copyright 2015 Stefan Negritoiu (FreeBusy). See LICENSE file for more information.
+using Org.BouncyCastle.Security.Certificates;
+using Org.BouncyCastle.X509;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
-using System.Net;
using System.Net.Http;
-using System.Runtime.Caching;
-using System.Text;
-using System.Text.RegularExpressions;
using System.Threading.Tasks;
-using Org.BouncyCastle.X509;
-using Org.BouncyCastle.Security.Certificates;
namespace AlexaSkillsKit.Authentication
{
public class SpeechletRequestSignatureVerifier
{
- private static Func _getCertCacheKey = (string url) => string.Format("{0}_{1}", Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER, url);
-
- private static CacheItemPolicy _policy = new CacheItemPolicy {
- Priority = CacheItemPriority.Default,
- AbsoluteExpiration = DateTimeOffset.UtcNow.AddHours(24)
- };
+ private const string HttpsUriScheme = "https";
+ private static Func _getCertCacheKey = (string url) => string.Format("{0}_{1}", Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER, url);
+ private static Dictionary _certCache = new Dictionary();
+ private static DateTimeOffset _certCacheAbsoluteExpiration = DateTimeOffset.UtcNow.AddHours(24);
///
/// Verifying the Signature Certificate URL per requirements documented at
@@ -43,36 +36,10 @@ public static bool VerifyCertificateUrl(string certChainUrl) {
return
certChainUri.Host.Equals(Sdk.SIGNATURE_CERT_URL_HOST, StringComparison.OrdinalIgnoreCase) &&
certChainUri.PathAndQuery.StartsWith(Sdk.SIGNATURE_CERT_URL_PATH) &&
- certChainUri.Scheme == Uri.UriSchemeHttps &&
+ certChainUri.Scheme.ToLowerInvariant() == HttpsUriScheme &&
certChainUri.Port == 443;
}
-
- ///
- /// Verifies request signature and manages the caching of the signature certificate
- ///
- public static bool VerifyRequestSignature(
- byte[] serializedSpeechletRequest, string expectedSignature, string certChainUrl) {
-
- string certCacheKey = _getCertCacheKey(certChainUrl);
- X509Certificate cert = MemoryCache.Default.Get(certCacheKey) as X509Certificate;
- if (cert == null ||
- !CheckRequestSignature(serializedSpeechletRequest, expectedSignature, cert)) {
-
- // download the cert
- // if we don't have it in cache or
- // if we have it but it's stale because the current request was signed with a newer cert
- // (signaled by signature check fail with cached cert)
- cert = RetrieveAndVerifyCertificate(certChainUrl);
- if (cert == null) return false;
-
- MemoryCache.Default.Set(certCacheKey, cert, _policy);
- }
-
- return CheckRequestSignature(serializedSpeechletRequest, expectedSignature, cert);
- }
-
-
///
/// Verifies request signature and manages the caching of the signature certificate
///
@@ -80,7 +47,7 @@ public async static Task VerifyRequestSignatureAsync(
byte[] serializedSpeechletRequest, string expectedSignature, string certChainUrl) {
string certCacheKey = _getCertCacheKey(certChainUrl);
- X509Certificate cert = MemoryCache.Default.Get(certCacheKey) as X509Certificate;
+ X509Certificate cert = GetCachedCertificate(certCacheKey) as X509Certificate;
if (cert == null ||
!CheckRequestSignature(serializedSpeechletRequest, expectedSignature, cert)) {
@@ -91,41 +58,12 @@ public async static Task VerifyRequestSignatureAsync(
cert = await RetrieveAndVerifyCertificateAsync(certChainUrl);
if (cert == null) return false;
- MemoryCache.Default.Set(certCacheKey, cert, _policy);
+ SetCachedCertificate(certCacheKey, cert);
}
return CheckRequestSignature(serializedSpeechletRequest, expectedSignature, cert);
}
-
- ///
- ///
- ///
- public static X509Certificate RetrieveAndVerifyCertificate(string certChainUrl) {
- // making requests to externally-supplied URLs is an open invitation to DoS
- // so restrict host to an Alexa controlled subdomain/path
- if (!VerifyCertificateUrl(certChainUrl)) return null;
-
- var webClient = new WebClient();
- var content = webClient.DownloadString(certChainUrl);
-
- var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(new StringReader(content));
- var cert = (X509Certificate)pemReader.ReadObject();
- try {
- cert.CheckValidity();
- if (!CheckCertSubjectNames(cert)) return null;
- }
- catch (CertificateExpiredException) {
- return null;
- }
- catch (CertificateNotYetValidException) {
- return null;
- }
-
- return cert;
- }
-
-
///
///
///
@@ -184,9 +122,9 @@ public static bool CheckRequestSignature(
///
private static bool CheckCertSubjectNames(X509Certificate cert) {
bool found = false;
- ArrayList subjectNamesList = (ArrayList)cert.GetSubjectAlternativeNames();
+ var subjectNamesList = (IList)cert.GetSubjectAlternativeNames();
for (int i=0; i < subjectNamesList.Count; i++) {
- ArrayList subjectNames = (ArrayList)subjectNamesList[i];
+ var subjectNames = (IList)subjectNamesList[i];
for (int j = 0; j < subjectNames.Count; j++) {
if (subjectNames[j] is String && subjectNames[j].Equals(Sdk.ECHO_API_DOMAIN_NAME)) {
found = true;
@@ -197,5 +135,25 @@ private static bool CheckCertSubjectNames(X509Certificate cert) {
return found;
}
+
+ ///
+ ///
+ ///
+ private static X509Certificate GetCachedCertificate(string url) {
+ var key = _getCertCacheKey(url);
+ if (_certCacheAbsoluteExpiration < DateTimeOffset.UtcNow) {
+ _certCache[key] = null;
+ }
+
+ return _certCache[key];
+ }
+
+ ///
+ ///
+ ///
+ private static void SetCachedCertificate(string url, X509Certificate certificate) {
+ var key = _getCertCacheKey(url);
+ _certCache[key] = certificate;
+ }
}
}
diff --git a/AlexaSkillsKit.Lib/Helpers/DateTimeHelpers.cs b/AlexaSkillsKit.Lib/Helpers/DateTimeHelpers.cs
index e01f4cc..d4f7d60 100644
--- a/AlexaSkillsKit.Lib/Helpers/DateTimeHelpers.cs
+++ b/AlexaSkillsKit.Lib/Helpers/DateTimeHelpers.cs
@@ -1,7 +1,6 @@
// Copyright 2015 Stefan Negritoiu (FreeBusy) and contributors. See LICENSE file for more information.
using System;
-using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace AlexaSkillsKit.Helpers
diff --git a/AlexaSkillsKit.Lib/Json/Deserializer.cs b/AlexaSkillsKit.Lib/Json/Deserializer.cs
index 9c5cc2f..631ae17 100644
--- a/AlexaSkillsKit.Lib/Json/Deserializer.cs
+++ b/AlexaSkillsKit.Lib/Json/Deserializer.cs
@@ -17,5 +17,11 @@ public static T FromJson(JProperty json) {
return deserializers[json.Name](json.Value as JObject);
}
+
+ public static T FromJson(string name, JObject json) {
+ if (json == null || !deserializers.ContainsKey(name)) return default(T);
+
+ return deserializers[name](json);
+ }
}
-}
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/Json/SpeechletRequestEnvelope.cs b/AlexaSkillsKit.Lib/Json/SpeechletRequestEnvelope.cs
index 30e3c81..72e2a1e 100644
--- a/AlexaSkillsKit.Lib/Json/SpeechletRequestEnvelope.cs
+++ b/AlexaSkillsKit.Lib/Json/SpeechletRequestEnvelope.cs
@@ -12,14 +12,6 @@ public class SpeechletRequestEnvelope
{
public static SpeechletRequestParser RequestParser { get; } = new SpeechletRequestParser();
- static SpeechletRequestEnvelope() {
- RequestParser.AddStandard();
- RequestParser.AddSystem();
- RequestParser.AddAudioPlayer();
- RequestParser.AddPlaybackController();
- RequestParser.AddDisplay();
- }
-
///
///
///
@@ -34,12 +26,6 @@ public static SpeechletRequestEnvelope FromJson(string content) {
return FromJson(json);
}
-
- ///
- ///
- ///
- ///
- ///
public static SpeechletRequestEnvelope FromJson(JObject json) {
var version = json.Value("version");
if (version != null && version != Sdk.VERSION) {
diff --git a/AlexaSkillsKit.Lib/Json/SpeechletRequestParserExtensions.cs b/AlexaSkillsKit.Lib/Json/SpeechletRequestParserExtensions.cs
index ceb45cb..c0b9da6 100644
--- a/AlexaSkillsKit.Lib/Json/SpeechletRequestParserExtensions.cs
+++ b/AlexaSkillsKit.Lib/Json/SpeechletRequestParserExtensions.cs
@@ -29,24 +29,5 @@ public static void AddSystem(this SpeechletRequestParser parser) {
return null;
});
}
-
- public static void AddAudioPlayer(this SpeechletRequestParser parser) {
- parser.AddInterface(AudioPlayerRequest.TypeName, (subtype, json) => {
- switch (subtype) {
- case "PlaybackFailed":
- return new AudioPlayerPlaybackFailedRequest(subtype, json);
- default:
- return new AudioPlayerRequest(subtype, json);
- }
- });
- }
-
- public static void AddPlaybackController(this SpeechletRequestParser parser) {
- parser.AddInterface(PlaybackControllerRequest.TypeName, (subtype, json) => new PlaybackControllerRequest(subtype, json));
- }
-
- public static void AddDisplay(this SpeechletRequestParser parser) {
- parser.AddInterface(DisplayRequest.TypeName, (subtype, json) => new DisplayRequest(subtype, json));
- }
}
}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/Properties/AssemblyInfo.cs b/AlexaSkillsKit.Lib/Properties/AssemblyInfo.cs
deleted file mode 100644
index d23afea..0000000
--- a/AlexaSkillsKit.Lib/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("AlexaSkillsKit")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("AlexaSkillsKit")]
-[assembly: AssemblyCopyright("Copyright © 2015 Stefan Negritoiu (FreeBusy)")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("5471ba5b-32c1-486c-851b-dbb8d9c53f13")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Build and Revision Numbers
-// by using the '*' as shown below:
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.5.0")]
-[assembly: AssemblyFileVersion("1.5.0")]
diff --git a/AlexaSkillsKit.Lib/Speechlet/ExtendedSpeechletRequest.cs b/AlexaSkillsKit.Lib/Requests/ExtendedSpeechletRequest.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Speechlet/ExtendedSpeechletRequest.cs
rename to AlexaSkillsKit.Lib/Requests/ExtendedSpeechletRequest.cs
diff --git a/AlexaSkillsKit.Lib/Speechlet/IntentRequest.cs b/AlexaSkillsKit.Lib/Requests/IntentRequest.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Speechlet/IntentRequest.cs
rename to AlexaSkillsKit.Lib/Requests/IntentRequest.cs
diff --git a/AlexaSkillsKit.Lib/Speechlet/LaunchRequest.cs b/AlexaSkillsKit.Lib/Requests/LaunchRequest.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Speechlet/LaunchRequest.cs
rename to AlexaSkillsKit.Lib/Requests/LaunchRequest.cs
diff --git a/AlexaSkillsKit.Lib/Speechlet/SessionEndedRequest.cs b/AlexaSkillsKit.Lib/Requests/SessionEndedRequest.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Speechlet/SessionEndedRequest.cs
rename to AlexaSkillsKit.Lib/Requests/SessionEndedRequest.cs
diff --git a/AlexaSkillsKit.Lib/Speechlet/SessionStartedRequest.cs b/AlexaSkillsKit.Lib/Requests/SessionStartedRequest.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Speechlet/SessionStartedRequest.cs
rename to AlexaSkillsKit.Lib/Requests/SessionStartedRequest.cs
diff --git a/AlexaSkillsKit.Lib/Speechlet/SpeechletRequest.cs b/AlexaSkillsKit.Lib/Requests/SpeechletRequest.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Speechlet/SpeechletRequest.cs
rename to AlexaSkillsKit.Lib/Requests/SpeechletRequest.cs
diff --git a/AlexaSkillsKit.Lib/Speechlet/SystemExceptionEncounteredRequest.cs b/AlexaSkillsKit.Lib/Requests/SystemExceptionEncounteredRequest.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Speechlet/SystemExceptionEncounteredRequest.cs
rename to AlexaSkillsKit.Lib/Requests/SystemExceptionEncounteredRequest.cs
diff --git a/AlexaSkillsKit.Lib/Sdk.cs b/AlexaSkillsKit.Lib/Sdk.cs
index c8df4fd..e30314e 100644
--- a/AlexaSkillsKit.Lib/Sdk.cs
+++ b/AlexaSkillsKit.Lib/Sdk.cs
@@ -1,6 +1,5 @@
// Copyright 2015 Stefan Negritoiu (FreeBusy). See LICENSE file for more information.
-using System;
using Newtonsoft.Json;
namespace AlexaSkillsKit
diff --git a/AlexaSkillsKit.Lib/Speechlet/Application.cs b/AlexaSkillsKit.Lib/Speechlet/Application.cs
index 40b17fa..11e35dd 100644
--- a/AlexaSkillsKit.Lib/Speechlet/Application.cs
+++ b/AlexaSkillsKit.Lib/Speechlet/Application.cs
@@ -1,6 +1,5 @@
// Copyright 2015 Stefan Negritoiu (FreeBusy). See LICENSE file for more information.
-using System;
using Newtonsoft.Json.Linq;
namespace AlexaSkillsKit.Speechlet
diff --git a/AlexaSkillsKit.Lib/AsyncHelpers.cs b/AlexaSkillsKit.Lib/Speechlet/AsyncHelpers.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/AsyncHelpers.cs
rename to AlexaSkillsKit.Lib/Speechlet/AsyncHelpers.cs
diff --git a/AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerState.cs b/AlexaSkillsKit.Lib/Speechlet/AudioPlayerState.cs
similarity index 100%
rename from AlexaSkillsKit.Lib/Interfaces/AudioPlayer/AudioPlayerState.cs
rename to AlexaSkillsKit.Lib/Speechlet/AudioPlayerState.cs
diff --git a/AlexaSkillsKit.Lib/Speechlet/ISpeechletAsync.cs b/AlexaSkillsKit.Lib/Speechlet/ISpeechletAsync.cs
index 7694d01..8aeb447 100644
--- a/AlexaSkillsKit.Lib/Speechlet/ISpeechletAsync.cs
+++ b/AlexaSkillsKit.Lib/Speechlet/ISpeechletAsync.cs
@@ -1,6 +1,5 @@
// Copyright 2015 Stefan Negritoiu (FreeBusy). See LICENSE file for more information.
-using System;
using System.Threading.Tasks;
namespace AlexaSkillsKit.Speechlet
diff --git a/AlexaSkillsKit.Lib/Speechlet/ISystemSpeechlet.cs b/AlexaSkillsKit.Lib/Speechlet/ISystemSpeechlet.cs
new file mode 100644
index 0000000..3f1d1e5
--- /dev/null
+++ b/AlexaSkillsKit.Lib/Speechlet/ISystemSpeechlet.cs
@@ -0,0 +1,7 @@
+namespace AlexaSkillsKit.Speechlet
+{
+ public interface ISystemSpeechlet
+ {
+ void OnSystemExceptionEncountered(SystemExceptionEncounteredRequest systemRequest, Context context);
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/Speechlet/ISystemSpeechletAsync.cs b/AlexaSkillsKit.Lib/Speechlet/ISystemSpeechletAsync.cs
new file mode 100644
index 0000000..d458c06
--- /dev/null
+++ b/AlexaSkillsKit.Lib/Speechlet/ISystemSpeechletAsync.cs
@@ -0,0 +1,9 @@
+using System.Threading.Tasks;
+
+namespace AlexaSkillsKit.Speechlet
+{
+ public interface ISystemSpeechletAsync
+ {
+ Task OnSystemExceptionEncounteredAsync(SystemExceptionEncounteredRequest systemRequest, Context context);
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/Speechlet/Speechlet.cs b/AlexaSkillsKit.Lib/Speechlet/Speechlet.cs
index e51cecf..f9275df 100644
--- a/AlexaSkillsKit.Lib/Speechlet/Speechlet.cs
+++ b/AlexaSkillsKit.Lib/Speechlet/Speechlet.cs
@@ -7,6 +7,10 @@ namespace AlexaSkillsKit.Speechlet
[Obsolete("Does not support context object. Derive from SpeechletBase instead and implement ISpeechletWithContext")]
public abstract class Speechlet : SpeechletBase, ISpeechlet
{
+ protected Speechlet() {
+ Service.AddStandard(this);
+ }
+
public abstract SpeechletResponse OnIntent(IntentRequest intentRequest, Session session);
public abstract SpeechletResponse OnLaunch(LaunchRequest launchRequest, Session session);
public abstract void OnSessionStarted(SessionStartedRequest sessionStartedRequest, Session session);
diff --git a/AlexaSkillsKit.Lib/Speechlet/SpeechletAsync.cs b/AlexaSkillsKit.Lib/Speechlet/SpeechletAsync.cs
index 5b46856..23835f3 100644
--- a/AlexaSkillsKit.Lib/Speechlet/SpeechletAsync.cs
+++ b/AlexaSkillsKit.Lib/Speechlet/SpeechletAsync.cs
@@ -8,6 +8,10 @@ namespace AlexaSkillsKit.Speechlet
[Obsolete("Does not support context object. Derive from SpeechletBase instead and implement ISpeechletWithContextAsync")]
public abstract class SpeechletAsync : SpeechletBase, ISpeechletAsync
{
+ protected SpeechletAsync() {
+ Service.AddStandard(this);
+ }
+
public abstract Task OnIntentAsync(IntentRequest intentRequest, Session session);
public abstract Task OnLaunchAsync(LaunchRequest launchRequest, Session session);
public abstract Task OnSessionEndedAsync(SessionEndedRequest sessionEndedRequest, Session session);
diff --git a/AlexaSkillsKit.Lib/Speechlet/SpeechletBase.cs b/AlexaSkillsKit.Lib/Speechlet/SpeechletBase.cs
index d372690..418ff4e 100644
--- a/AlexaSkillsKit.Lib/Speechlet/SpeechletBase.cs
+++ b/AlexaSkillsKit.Lib/Speechlet/SpeechletBase.cs
@@ -31,6 +31,10 @@ public async Task GetResponseAsync(HttpRequestMessage httpR
return await Service.GetResponseAsync(httpRequest);
}
+ public SpeechletBase() {
+ Service.ValidationHandler = OnRequestValidation;
+ }
+
///
/// Processes Alexa request but does NOT validate request signature
diff --git a/AlexaSkillsKit.Lib/Speechlet/SpeechletService.cs b/AlexaSkillsKit.Lib/Speechlet/SpeechletService.cs
index 9395ace..1d5ae48 100644
--- a/AlexaSkillsKit.Lib/Speechlet/SpeechletService.cs
+++ b/AlexaSkillsKit.Lib/Speechlet/SpeechletService.cs
@@ -1,15 +1,9 @@
-// Copyright 2015 Stefan Negritoiu (FreeBusy). See LICENSE file for more information.
-
-using AlexaSkillsKit.Authentication;
-using AlexaSkillsKit.Interfaces.AudioPlayer;
-using AlexaSkillsKit.Interfaces.Display;
+using AlexaSkillsKit.Authentication;
using AlexaSkillsKit.Json;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
+using System.Reflection;
using System.Text;
using System.Threading.Tasks;
@@ -17,86 +11,21 @@ namespace AlexaSkillsKit.Speechlet
{
public class SpeechletService
{
- private ISpeechletBase speechlet;
-
- private IDictionary>> handlers
- = new Dictionary>>();
+ private IDictionary>> handlers
+ = new Dictionary>>();
public string ApplicationId { get; set; }
+ public Func ValidationHandler { get; set; }
- public void AddHandler(string type, Func> handler) where T : SpeechletRequest {
- handlers[type] = (request, context) => handler(request as T, context);
+ public void AddHandler(Func> handler) where T : SpeechletRequest {
+ handlers[typeof(T)] = async (request, session, context) => await handler(request as T, session, context);
}
-
- public SpeechletService(ISpeechletBase speechlet) {
- this.speechlet = speechlet;
-
- if (speechlet is IAudioPlayerSpeechletAsync || speechlet is IAudioPlayerSpeechlet) {
- AddHandler(AudioPlayerRequest.TypeName, async (request, context) => {
- return (speechlet as IAudioPlayerSpeechlet)?.OnAudioPlayer(request, context) ??
- await (speechlet as IAudioPlayerSpeechletAsync)?.OnAudioPlayerAsync(request, context);
- });
-
- AddHandler(PlaybackControllerRequest.TypeName, async (request, context) => {
- return (speechlet as IAudioPlayerSpeechlet)?.OnPlaybackController(request, context) ??
- await (speechlet as IAudioPlayerSpeechletAsync)?.OnPlaybackControllerAsync(request, context);
- });
-
- AddHandler(SystemRequest.TypeName, async (request, context) => {
- (speechlet as IAudioPlayerSpeechlet)?.OnSystemExceptionEncountered(request, context);
- await (speechlet as IAudioPlayerSpeechletAsync).OnSystemExceptionEncounteredAsync(request, context);
- return null;
- });
- }
-
- if (speechlet is IDisplaySpeechletAsync) {
- AddHandler(DisplayRequest.TypeName, async (request, context) => {
- return (speechlet as IDisplaySpeechlet).OnDisplay(request, context) ??
- await (speechlet as IDisplaySpeechletAsync).OnDisplayAsync(request, context);
- });
- }
- }
-
-
- ///
- /// Processes Alexa request AND validates request signature
- ///
- ///
- ///
- public async Task GetResponseAsync(HttpRequestMessage httpRequest) {
- string chainUrl = null;
- if (httpRequest.Headers.Contains(Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER)) {
- chainUrl = httpRequest.Headers.GetValues(Sdk.SIGNATURE_CERT_URL_REQUEST_HEADER).FirstOrDefault(x => !string.IsNullOrEmpty(x));
- }
-
- string signature = null;
- if (httpRequest.Headers.Contains(Sdk.SIGNATURE_REQUEST_HEADER)) {
- signature = httpRequest.Headers.GetValues(Sdk.SIGNATURE_REQUEST_HEADER).FirstOrDefault(x => !string.IsNullOrEmpty(x));
- }
-
- var content = await httpRequest.Content.ReadAsStringAsync();
-
- try {
- var alexaRequest = await GetRequestAsync(content, chainUrl, signature);
- var alexaResponse = await ProcessRequestAsync(alexaRequest);
- var json = alexaResponse?.ToJson();
-
- return (json == null) ?
- new HttpResponseMessage(HttpStatusCode.InternalServerError) :
- new HttpResponseMessage(HttpStatusCode.OK) {
- Content = new StringContent(json, Encoding.UTF8, "application/json")
- };
- }
- catch (SpeechletValidationException ex) {
- return new HttpResponseMessage(HttpStatusCode.BadRequest) {
- ReasonPhrase = ex.ValidationResult.ToString()
- };
- }
+ public void AddHandler(Func> handler) where T : SpeechletRequest {
+ handlers[typeof(T)] = async (request, session, context) => await handler(request as T, context);
}
-
public async Task GetRequestAsync(string content, string chainUrl, string signature) {
var validationResult = SpeechletRequestValidationResult.OK;
@@ -143,7 +72,7 @@ public async Task GetRequestAsync(string content, stri
validationResult |= SpeechletRequestValidationResult.InvalidApplicationId;
}
- success = speechlet?.OnRequestValidation(validationResult, now, result) ?? (validationResult == SpeechletRequestValidationResult.OK);
+ success = ValidationHandler?.Invoke(validationResult, now, result) ?? (validationResult == SpeechletRequestValidationResult.OK);
}
if (!success) {
@@ -163,70 +92,32 @@ public async Task ProcessRequestAsync(SpeechletReques
var session = requestEnvelope.Session;
var context = requestEnvelope.Context;
var request = requestEnvelope.Request;
+ ISpeechletResponse response = null;
- var response = (request is ExtendedSpeechletRequest) ?
- await HandleStandardRequestAsync(request, session, context) :
- await HandleExtendedRequestAsync(request as ExtendedSpeechletRequest, context);
-
- if (response == null) {
- response = new SpeechletResponse();
- }
-
- var responseEnvelope = new SpeechletResponseEnvelope {
- Version = requestEnvelope.Version,
- Response = response,
- SessionAttributes = session?.Attributes
- };
-
- return responseEnvelope;
- }
-
-
- private async Task HandleStandardRequestAsync(SpeechletRequest request, Session session, Context context) {
if (session != null) {
// Do session management prior to calling OnSessionStarted and OnIntentAsync
// to allow dev to change session values if behavior is not desired
DoSessionManagement(request as IntentRequest, session);
- if (session.IsNew) {
- var sessionStartedRequest = new SessionStartedRequest(request);
- (speechlet as ISpeechletWithContext)?.OnSessionStarted(sessionStartedRequest, session, context);
- await (speechlet as ISpeechletWithContextAsync)?.OnSessionStartedAsync(sessionStartedRequest, session, context);
- (speechlet as ISpeechlet)?.OnSessionStarted(sessionStartedRequest, session);
- await (speechlet as ISpeechletAsync)?.OnSessionStartedAsync(sessionStartedRequest, session);
+ if (session.IsNew && handlers.ContainsKey(typeof(SessionStartedRequest))) {
+ await handlers[typeof(SessionStartedRequest)].Invoke(new SessionStartedRequest(request), session, context);
}
}
- // process launch request
- if (request is LaunchRequest) {
- return (speechlet as ISpeechletWithContext)?.OnLaunch(request as LaunchRequest, session, context) ??
- await (speechlet as ISpeechletWithContextAsync)?.OnLaunchAsync(request as LaunchRequest, session, context) ??
- (speechlet as ISpeechlet)?.OnLaunch(request as LaunchRequest, session) ??
- await (speechlet as ISpeechletAsync)?.OnLaunchAsync(request as LaunchRequest, session);
- }
-
- // process intent request
- else if (request is IntentRequest) {
- return (speechlet as ISpeechletWithContext)?.OnIntent(request as IntentRequest, session, context) ??
- await (speechlet as ISpeechletWithContextAsync)?.OnIntentAsync(request as IntentRequest, session, context) ??
- (speechlet as ISpeechlet)?.OnIntent(request as IntentRequest, session) ??
- await (speechlet as ISpeechletAsync)?.OnIntentAsync(request as IntentRequest, session);
- }
-
- // process session ended request
- else if (request is SessionEndedRequest) {
- (speechlet as ISpeechletWithContext)?.OnSessionEnded(request as SessionEndedRequest, session, context);
- await (speechlet as ISpeechletWithContextAsync)?.OnSessionEndedAsync(request as SessionEndedRequest, session, context);
- (speechlet as ISpeechlet)?.OnSessionEnded(request as SessionEndedRequest, session);
- await (speechlet as ISpeechletAsync)?.OnSessionEndedAsync(request as SessionEndedRequest, session);
+ foreach (var pair in handlers) {
+ if (pair.Key.GetTypeInfo().IsAssignableFrom(request.GetType().GetTypeInfo())) {
+ response = await pair.Value(request, session, context);
+ break;
+ }
}
- return null;
- }
-
+ var responseEnvelope = new SpeechletResponseEnvelope {
+ Version = requestEnvelope.Version,
+ Response = response,
+ SessionAttributes = session?.Attributes
+ };
- private async Task HandleExtendedRequestAsync(ExtendedSpeechletRequest request, Context context) {
- return handlers.ContainsKey(request.Type) ? (await handlers[request.Type]?.Invoke(request, context)) : null;
+ return responseEnvelope;
}
@@ -256,7 +147,7 @@ private void DoSessionManagement(IntentRequest request, Session session) {
// Auto-session management: copy all slot values from current intent into session
foreach (var slot in request.Intent.Slots.Values) {
- session.Attributes[slot.Name] = slot.Value;
+ if (!String.IsNullOrEmpty(slot.Value)) session.Attributes[slot.Name] = slot.Value;
}
}
}
diff --git a/AlexaSkillsKit.Lib/Speechlet/SpeechletServiceExtensions.cs b/AlexaSkillsKit.Lib/Speechlet/SpeechletServiceExtensions.cs
new file mode 100644
index 0000000..a088188
--- /dev/null
+++ b/AlexaSkillsKit.Lib/Speechlet/SpeechletServiceExtensions.cs
@@ -0,0 +1,39 @@
+using AlexaSkillsKit.Json;
+
+namespace AlexaSkillsKit.Speechlet
+{
+ public static class SpeechletServiceExtensions
+ {
+ public static void AddStandard(this SpeechletService service, ISpeechletAsync speechlet) {
+ service.AddHandler(async (request, session, context) =>
+ await speechlet.OnLaunchAsync(request, session));
+
+ service.AddHandler(async (request, session, context) =>
+ await speechlet.OnIntentAsync(request, session, context));
+
+ service.AddHandler(async (request, session, context) => {
+ await speechlet.OnSessionEndedAsync(request, session);
+ return null;
+ });
+
+ SpeechletRequestEnvelope.RequestParser.AddStandard();
+ }
+
+ public static void AddStandard(this SpeechletService service, ISpeechlet speechlet) {
+ service.AddStandard(new SpeechletAsyncWrapper(speechlet));
+ }
+
+ public static void AddSystem(this SpeechletService service, ISystemSpeechletAsync speechlet) {
+ service.AddHandler(async (request, session, context) => {
+ await speechlet.OnSystemExceptionEncounteredAsync(request, context);
+ return null;
+ });
+
+ SpeechletRequestEnvelope.RequestParser.AddSystem();
+ }
+
+ public static void AddSystem(this SpeechletService service, ISystemSpeechlet speechlet) {
+ service.AddSystem(new SystemSpeechletAsyncWrapper(speechlet));
+ }
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/Speechlet/SupportedInterfaces.cs b/AlexaSkillsKit.Lib/Speechlet/SupportedInterfaces.cs
index 6bac209..74fc8ac 100644
--- a/AlexaSkillsKit.Lib/Speechlet/SupportedInterfaces.cs
+++ b/AlexaSkillsKit.Lib/Speechlet/SupportedInterfaces.cs
@@ -1,8 +1,6 @@
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using System.Linq;
-using AlexaSkillsKit.Interfaces.Display;
-using AlexaSkillsKit.Interfaces.AudioPlayer;
using AlexaSkillsKit.Json;
namespace AlexaSkillsKit.Speechlet
@@ -12,14 +10,6 @@ namespace AlexaSkillsKit.Speechlet
///
public class SupportedInterfaces : Dictionary
{
- ///
- /// Register supported interfaces for deserialization
- ///
- static SupportedInterfaces() {
- Deserializer.RegisterDeserializer("Display", DisplayInterface.FromJson);
- Deserializer.RegisterDeserializer("AudioPlayer", AudioPlayerInterface.FromJson);
- }
-
public static SupportedInterfaces FromJson(JObject json) {
if (json == null) return null;
diff --git a/AlexaSkillsKit.Lib/Speechlet/SystemSpeechletAsyncWrapper.cs b/AlexaSkillsKit.Lib/Speechlet/SystemSpeechletAsyncWrapper.cs
new file mode 100644
index 0000000..5d0291a
--- /dev/null
+++ b/AlexaSkillsKit.Lib/Speechlet/SystemSpeechletAsyncWrapper.cs
@@ -0,0 +1,17 @@
+using System.Threading.Tasks;
+
+namespace AlexaSkillsKit.Speechlet
+{
+ public class SystemSpeechletAsyncWrapper: ISystemSpeechletAsync
+ {
+ private readonly ISystemSpeechlet speechlet;
+
+ public SystemSpeechletAsyncWrapper(ISystemSpeechlet speechlet) {
+ this.speechlet = speechlet;
+ }
+
+ public async Task OnSystemExceptionEncounteredAsync(SystemExceptionEncounteredRequest systemRequest, Context context) {
+ speechlet.OnSystemExceptionEncountered(systemRequest, context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/app.config b/AlexaSkillsKit.Lib/app.config
deleted file mode 100644
index 195db1f..0000000
--- a/AlexaSkillsKit.Lib/app.config
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/AlexaSkillsKit.Lib/packages.config b/AlexaSkillsKit.Lib/packages.config
deleted file mode 100644
index 284ea23..0000000
--- a/AlexaSkillsKit.Lib/packages.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/AlexaSkillsKit.Sample/AlexaSkillsKit.Sample.csproj b/AlexaSkillsKit.Sample/AlexaSkillsKit.Sample.csproj
index 254d2e0..7ab70d9 100644
--- a/AlexaSkillsKit.Sample/AlexaSkillsKit.Sample.csproj
+++ b/AlexaSkillsKit.Sample/AlexaSkillsKit.Sample.csproj
@@ -23,6 +23,8 @@
..\
true
+
+
true
@@ -107,9 +109,8 @@
False
..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll
-
- ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
- True
+
+ ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
..\packages\NLog.3.2.1\lib\net45\NLog.dll
@@ -120,10 +121,9 @@
+
-
-
..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
True
@@ -131,6 +131,9 @@
+
+
+
..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll
True
@@ -170,7 +173,6 @@
..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll
True
-
@@ -179,6 +181,7 @@
+
..\packages\WebGrease.1.6.0\lib\WebGrease.dll
True
@@ -312,9 +315,17 @@
-
- {0ec882a8-aaca-4bd5-b449-72f20fdb8586}
- AlexaSkillsKit.Lib
+
+ {6224BE94-2A4B-4AB2-BA8A-4BD3DF47FC4F}
+ AlexaSkillsKit.Interfaces.Display
+
+
+ {1517FE44-37AF-4585-AF54-0A20F222CFCB}
+ AlexaSkillsKit.Interfaces.VideoApp
+
+
+ {01b7fa9f-5f29-46fa-8e27-b731a2a95876}
+ AlexaSkillsKit
diff --git a/AlexaSkillsKit.Sample/Speechlet/AlexaController.cs b/AlexaSkillsKit.Sample/Speechlet/AlexaController.cs
index 507328a..cca826e 100644
--- a/AlexaSkillsKit.Sample/Speechlet/AlexaController.cs
+++ b/AlexaSkillsKit.Sample/Speechlet/AlexaController.cs
@@ -14,4 +14,4 @@ public HttpResponseMessage SampleSession() {
return speechlet.GetResponse(Request);
}
}
-}
+}
\ No newline at end of file
diff --git a/AlexaSkillsKit.Sample/Speechlet/SampleSessionSpeechlet.cs b/AlexaSkillsKit.Sample/Speechlet/SampleSessionSpeechlet.cs
index a8a98b1..345c692 100644
--- a/AlexaSkillsKit.Sample/Speechlet/SampleSessionSpeechlet.cs
+++ b/AlexaSkillsKit.Sample/Speechlet/SampleSessionSpeechlet.cs
@@ -1,15 +1,15 @@
// Copyright 2015 Stefan Negritoiu (FreeBusy). See LICENSE file for more information.
-using System;
-using System.Collections.Generic;
-using NLog;
-using AlexaSkillsKit.Speechlet;
-using AlexaSkillsKit.Slu;
-using AlexaSkillsKit.UI;
using AlexaSkillsKit.Interfaces.Display;
-using AlexaSkillsKit.Interfaces.VideoApp;
using AlexaSkillsKit.Interfaces.Display.Directives;
+using AlexaSkillsKit.Interfaces.VideoApp;
using AlexaSkillsKit.Interfaces.VideoApp.Directives;
+using AlexaSkillsKit.Slu;
+using AlexaSkillsKit.Speechlet;
+using AlexaSkillsKit.UI;
+using NLog;
+using System;
+using System.Collections.Generic;
namespace Sample.Controllers
{
@@ -21,7 +21,6 @@ public class SampleSessionSpeechlet : Speechlet
private const string NAME_KEY = "name";
private const string NAME_SLOT = "Name";
-
public override void OnSessionStarted(SessionStartedRequest request, Session session) {
Log.Info("OnSessionStarted requestId={0}, sessionId={1}", request.RequestId, session.SessionId);
}
diff --git a/AlexaSkillsKit.Sample/Web.config b/AlexaSkillsKit.Sample/Web.config
index 8f0df6e..5d6d1b0 100644
--- a/AlexaSkillsKit.Sample/Web.config
+++ b/AlexaSkillsKit.Sample/Web.config
@@ -5,13 +5,21 @@
-->
-
-
+
+
-
+
+
@@ -21,19 +29,19 @@
-
-
+
-
+
+
-
-
-
-
+
+
+
+
@@ -52,7 +60,7 @@
-
+
@@ -98,4 +106,4 @@
-
+
\ No newline at end of file
diff --git a/AlexaSkillsKit.Sample/packages.config b/AlexaSkillsKit.Sample/packages.config
index abdc168..eea55aa 100644
--- a/AlexaSkillsKit.Sample/packages.config
+++ b/AlexaSkillsKit.Sample/packages.config
@@ -30,7 +30,7 @@
-
+
diff --git a/AlexaSkillsKit.Tests/AlexaSkillsKit.Tests.csproj b/AlexaSkillsKit.Tests/AlexaSkillsKit.Tests.csproj
index 98fd3e9..9fa45e0 100644
--- a/AlexaSkillsKit.Tests/AlexaSkillsKit.Tests.csproj
+++ b/AlexaSkillsKit.Tests/AlexaSkillsKit.Tests.csproj
@@ -39,9 +39,8 @@
4
-
- ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
- True
+
+ ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
@@ -88,9 +87,9 @@
-
- {0ec882a8-aaca-4bd5-b449-72f20fdb8586}
- AlexaSkillsKit.Lib
+
+ {01b7fa9f-5f29-46fa-8e27-b731a2a95876}
+ AlexaSkillsKit
diff --git a/AlexaSkillsKit.Tests/Authentication/SignatureVerifierTests.cs b/AlexaSkillsKit.Tests/Authentication/SignatureVerifierTests.cs
index 19eb3ea..8a89316 100644
--- a/AlexaSkillsKit.Tests/Authentication/SignatureVerifierTests.cs
+++ b/AlexaSkillsKit.Tests/Authentication/SignatureVerifierTests.cs
@@ -1,7 +1,5 @@
-using System;
+using AlexaSkillsKit.Authentication;
using Xunit;
-using AlexaSkillsKit;
-using AlexaSkillsKit.Authentication;
namespace AlexaSkillsKit.Tests
{
diff --git a/AlexaSkillsKit.Tests/packages.config b/AlexaSkillsKit.Tests/packages.config
index 9219867..42f9093 100644
--- a/AlexaSkillsKit.Tests/packages.config
+++ b/AlexaSkillsKit.Tests/packages.config
@@ -1,6 +1,6 @@
-
+
diff --git a/AlexaSkillsKit.sln b/AlexaSkillsKit.sln
index 3d68899..bc8fe4f 100644
--- a/AlexaSkillsKit.sln
+++ b/AlexaSkillsKit.sln
@@ -1,31 +1,28 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.31101.0
+# Visual Studio 15
+VisualStudioVersion = 15.0.27004.2010
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlexaSkillsKit.Lib", "AlexaSkillsKit.Lib\AlexaSkillsKit.Lib.csproj", "{0EC882A8-AACA-4BD5-B449-72F20FDB8586}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlexaSkillsKit.Sample", "AlexaSkillsKit.Sample\AlexaSkillsKit.Sample.csproj", "{9FDEF793-5832-4D37-B0D5-62C55AB1C12E}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{D35AD75F-7926-41CB-8C8D-BB36370F3E76}"
- ProjectSection(SolutionItems) = preProject
- .nuget\AlexaSkillsKit.Lib.nuspec = .nuget\AlexaSkillsKit.Lib.nuspec
- .nuget\NuGet.Config = .nuget\NuGet.Config
- .nuget\NuGet.targets = .nuget\NuGet.targets
- EndProjectSection
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlexaSkillsKit.Tests", "AlexaSkillsKit.Tests\AlexaSkillsKit.Tests.csproj", "{D0125A95-FD63-4A33-9220-206D4A1A14F0}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlexaSkillsKit", "AlexaSkillsKit.Lib\AlexaSkillsKit.csproj", "{01B7FA9F-5F29-46FA-8E27-B731A2A95876}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlexaSkillsKit.Interfaces.AudioPlayer", "AlexaSkillsKit.Interfaces.AudioPlayer\AlexaSkillsKit.Interfaces.AudioPlayer.csproj", "{2D25EE87-D293-4A62-BCEC-AACB4099ED9E}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlexaSkillsKit.Interfaces.Display", "AlexaSkillsKit.Interfaces.Display\AlexaSkillsKit.Interfaces.Display.csproj", "{6224BE94-2A4B-4AB2-BA8A-4BD3DF47FC4F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlexaSkillsKit.Interfaces.Dialog", "AlexaSkillsKit.Interfaces.Dialog\AlexaSkillsKit.Interfaces.Dialog.csproj", "{39F798E3-70FE-419A-AF58-E0A181A42A40}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AlexaSkillsKit.Interfaces.VideoApp", "AlexaSkillsKit.Interfaces.VideoApp\AlexaSkillsKit.Interfaces.VideoApp.csproj", "{1517FE44-37AF-4585-AF54-0A20F222CFCB}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {0EC882A8-AACA-4BD5-B449-72F20FDB8586}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0EC882A8-AACA-4BD5-B449-72F20FDB8586}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0EC882A8-AACA-4BD5-B449-72F20FDB8586}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0EC882A8-AACA-4BD5-B449-72F20FDB8586}.Release|Any CPU.Build.0 = Release|Any CPU
{9FDEF793-5832-4D37-B0D5-62C55AB1C12E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9FDEF793-5832-4D37-B0D5-62C55AB1C12E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9FDEF793-5832-4D37-B0D5-62C55AB1C12E}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -34,8 +31,31 @@ Global
{D0125A95-FD63-4A33-9220-206D4A1A14F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D0125A95-FD63-4A33-9220-206D4A1A14F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D0125A95-FD63-4A33-9220-206D4A1A14F0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {01B7FA9F-5F29-46FA-8E27-B731A2A95876}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {01B7FA9F-5F29-46FA-8E27-B731A2A95876}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {01B7FA9F-5F29-46FA-8E27-B731A2A95876}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {01B7FA9F-5F29-46FA-8E27-B731A2A95876}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2D25EE87-D293-4A62-BCEC-AACB4099ED9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2D25EE87-D293-4A62-BCEC-AACB4099ED9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2D25EE87-D293-4A62-BCEC-AACB4099ED9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2D25EE87-D293-4A62-BCEC-AACB4099ED9E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6224BE94-2A4B-4AB2-BA8A-4BD3DF47FC4F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6224BE94-2A4B-4AB2-BA8A-4BD3DF47FC4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6224BE94-2A4B-4AB2-BA8A-4BD3DF47FC4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6224BE94-2A4B-4AB2-BA8A-4BD3DF47FC4F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {39F798E3-70FE-419A-AF58-E0A181A42A40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {39F798E3-70FE-419A-AF58-E0A181A42A40}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {39F798E3-70FE-419A-AF58-E0A181A42A40}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {39F798E3-70FE-419A-AF58-E0A181A42A40}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1517FE44-37AF-4585-AF54-0A20F222CFCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1517FE44-37AF-4585-AF54-0A20F222CFCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1517FE44-37AF-4585-AF54-0A20F222CFCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1517FE44-37AF-4585-AF54-0A20F222CFCB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {802C7A13-5ADB-4355-91E6-AEF17F26AB36}
+ EndGlobalSection
EndGlobal
diff --git a/README.md b/README.md
index 8871334..7e21a03 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,6 @@
* [Display](https://developer.amazon.com/docs/custom-skills/display-interface-reference.html)
* [Dialog](https://developer.amazon.com/docs/custom-skills/dialog-interface-reference.html)
* [VideoApp](https://developer.amazon.com/docs/custom-skills/videoapp-interface-reference.html)
-
Beyond the functionality in Amazon's AlexaSkillsKit for Java, AlexaSkillsKit.NET:
* performs automatic session management so you can easily [build conversational Alexa apps](https://freebusy.io/blog/building-conversational-alexa-apps-for-amazon-echo)
@@ -20,13 +19,24 @@ Beyond the functionality in Amazon's AlexaSkillsKit for Java, AlexaSkillsKit.NET
This library was originally developed for and is in use at https://freebusy.io
-This library is available as a NuGet package at https://www.nuget.org/packages/AlexaSkillsKit.NET/
+Library is currently available as a single NuGet package: https://www.nuget.org/packages/AlexaSkillsKit.Net/
+
+Extensible version will be available as following NuGet packages:
+* https://www.nuget.org/packages/AlexaSkillsKit/ - core library
+* https://www.nuget.org/packages/AlexaSkillsKit.Http/ - System.Net.Http provider extentions
+* https://www.nuget.org/packages/AlexaSkillsKit.AspNetCore/ - ASP.Net Core Web API provider extentions
+* https://www.nuget.org/packages/AlexaSkillsKit.Interfaces.AudioPlayer/ - adds support of AudioPlayer and PlaybackController interfaces
+* https://www.nuget.org/packages/AlexaSkillsKit.Interfaces.Dialog/ - adds support of Dialog interface
+* https://www.nuget.org/packages/AlexaSkillsKit.Interfaces.Display/ - adds support of Display interface
+* https://www.nuget.org/packages/AlexaSkillsKit.Interfaces.VideoApp/ - adds support of VideoApp interface
+
# How To Use
### 1. Set up your development environment
Read [Getting started with Alexa App development for Amazon Echo using .NET on Windows](https://freebusy.io/blog/getting-started-with-alexa-app-development-for-amazon-echo-using-dot-net)
+for information on how you can setup you local certificate.
Note, that if you are hosting your API in Amazon Lambda, Azure Function, Azure Web App or other well-known cloud service, you can use parent domain certificate instead of providing your own.
@@ -71,7 +81,63 @@ The Sample app is using ASP.NET 4.5 WebApi 2 so wiring-up requests & responses f
*Note: sample project is generated from the ASP.NET 4.5 WebApi 2 template so it includes a lot of functionality that's not directly related to Alexa Speechlets, but it does make make for a complete Web API project.*
-Alternatively you can host your app and the AlexaSkillsKit.NET library in any other web service framework like ServiceStack.
+Alternatively you can host your app and the AlexaSkillsKit.NET library in any other web service framework like ServiceStack, ASP.NET Core Web API, Azure Function App, etc.
+
+# How it works
+
+Starting from version 2.0 AlexaSkillKit provides framework agnostic way to handle incoming Alexa requests.
+More over it is refactored, so that Skill authors can now extend library with newly coming not yet natively supported external interfaces and register them in the core library the same way as all existing interfaces are implemented.
+
+Here is detailed explanation of how requests are handled by the library.
+
+### SpeechletService class
+To handle Alexa requests an instance of `SpeechletService` has to be created. This is the main entry point for all operations involved in handling incoming requests.
+For convenience and backward compatibility with earlier library versions both `Speechlet` and `SpeechletAsync` now have built-in `SpeechletService` instance and wrap all most common operations with it.
+Skill authors can access their internal `SpeechletService` through `Service` property.
+
+### Parsing request
+
+When new request is recieved, it first needs to be parced from json string into object model represented by `SpeechletRequestEnvelope` class.
+`Task SpeechletService.GetRequestAsync(string content, string chainUrl, string signature)` method is used for this.
+Request headers and body validation also takes place during this step. The `SpeechletValidationException` is produced in case of any validation error.
+
+Skill authors can set SpeechletService.ValidationHandler property to have better control on when exception should be thrown, or to throw custom exceptions instead.
+For backward compatibility, the `Speechlet` and `SpeechletAsync` helper abstract classes set `ValidationHandler` property of their internal service to virtual `OnRequestValidation` method.
+Setting `ValidationHandler` property will override this behavior. See [Override request validation policy](#override-request-validation-policy) for more details on request validation.
+Request validation can be omitted by directly calling one of `SpeechletRequestEnvelope.FromJson` static methods.
+
+`SpeechletRequestEnvelope` consists of `Version`, `Session`, `Context` and `Request` fields. See [Context](#context-object) for more details on parsing context.
+
+Only version "1.0" of Alexa Skill API is supported. Otherwise `SpeechletValidationException` with `SpeechletRequestValidationResult.InvalidVersion` is thrown.
+Same is true, when calling `SpeechletRequestEnvelope.FromJson` methods directly.
+
+There are a lot of different request types available for Alexa Skills.
+Standard requests have simple type names: "LaunchRequest", "IntentRequest", "SessionEndedRequest".
+All other requests are related to specific interfaces and their request type name consists of interface name and request subtype name separated by "." sign: "System.ExceptionEncountered", "Dialog.Delegate" and so on.
+
+`SpeechletRequestResolver` static class is used to deserialize `request` json field to appropriate subclass of `SpeechletRequest` base class.
+By default, it has no knowledge to which class each request type should be deserialized.
+`SpeechletRequestResolver` has `AddInterface` method to bind interface name, with specific `InterfaceResolver`.
+`SpeechletRequestResolver` provides `AddStandard` method to register all standard requests and `AddSystem` to register `System.ExceptionEncountered` request.
+Both `Speechlet` and `SpeechletAsync` are calling `SpeechletRequestResolver.AddStandard` during initialization.
+
+Each interface library that provide own requests is intended to provide method to register those requests in `SpeechletRequestResolver`.
+So do `AlexaSkillsKit.Interfaces.Display` in its `void AddDisplay(this SpeechletService service, IDisplaySpeechletAsync speechlet)` extention method
+and `AlexaSkillsKit.Interfaces.AudioPlayer` in `void AddAudioPlayer(this SpeechletService service, IAudioPlayerSpeechletAsync speechlet)`.
+For more information on using external interfaces see [Use external interfaces](#use-external-interfaces).
+For more information on registering custom interfaces see [Implement external interface](#implement-external-interface).
+
+### Processing request
+
+//TODO
+
+# Advanced
+
+### Use external interfaces
+
+//TODO
+
+### Implement external interface
# How it works
@@ -118,6 +184,8 @@ unsupported API version (only API v"1.0" is supported), are rejected.
For Application Id to be validated, your skill needs to set value for `SpeechletService.ApplicationId` property.
You can override the request validation policy if you'd like not to reject the request in certain conditions and/or to log validation failures.
+If you are deriving from SpeechletAsync or Speechlet, simply override `OnRequestValidation` method as follows:
+
```csharp
///
/// return true if you want request to be processed, otherwise false
@@ -162,3 +230,13 @@ public override bool OnRequestValidation(
}
}
```
+
+### Use Speechlet Service directly
+
+Internally both SpeechletAsync and Speechlet abstract classes are derived from SpeechletBase class. SpeechletBase creates and exposes SpeechletService object used for request handling.
+
+SpeechletService
+
+To have better control over request handling you can use SpeechletService directly or even derive from it.
+
+In this case you need
\ No newline at end of file