diff --git a/libraries/Client/Conversations.cs b/libraries/Client/Conversations.cs
index 9ff3962..3f02a35 100644
--- a/libraries/Client/Conversations.cs
+++ b/libraries/Client/Conversations.cs
@@ -20,7 +20,8 @@ namespace Microsoft.Bot.Connector.DirectLine
using Microsoft.Rest;
using Microsoft.Rest.Serialization;
using Newtonsoft.Json;
-
+ using System.Net.Http.Json;
+
///
/// Conversations operations.
@@ -59,7 +60,7 @@ public Conversations(DirectLineClient client)
///
/// A response object containing the response body and response headers.
///
- public async Task> StartConversationWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken))
+ public async Task> StartConversationWithHttpMessagesAsync(string siteId = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken))
{
// Tracing
bool _shouldTrace = ServiceClientTracing.IsEnabled;
@@ -92,6 +93,9 @@ public Conversations(DirectLineClient client)
}
}
+ // set request param
+ _httpRequest.Content = JsonContent.Create(new { SiteId = siteId });
+
// Serialize Request
string _requestContent = null;
// Set Credentials
diff --git a/libraries/Client/ConversationsExtensions.cs b/libraries/Client/ConversationsExtensions.cs
index df3c2c6..62bcdee 100644
--- a/libraries/Client/ConversationsExtensions.cs
+++ b/libraries/Client/ConversationsExtensions.cs
@@ -1,4 +1,5 @@
-// Copyright (c) Microsoft. All rights reserved.
+
+// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
// Code generated by Microsoft (R) AutoRest Code Generator 0.16.0.0
@@ -40,9 +41,9 @@ public static Conversation StartConversation(this IConversations operations)
///
/// The cancellation token.
///
- public static async Task StartConversationAsync(this IConversations operations, CancellationToken cancellationToken = default(CancellationToken))
+ public static async Task StartConversationAsync(this IConversations operations, string siteId = null, CancellationToken cancellationToken = default(CancellationToken))
{
- using (var _result = await operations.StartConversationWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false))
+ using (var _result = await operations.StartConversationWithHttpMessagesAsync(siteId, null, cancellationToken).ConfigureAwait(false))
{
return _result.Body;
}
diff --git a/libraries/Client/IConversations.cs b/libraries/Client/IConversations.cs
index f196973..69f0371 100644
--- a/libraries/Client/IConversations.cs
+++ b/libraries/Client/IConversations.cs
@@ -29,7 +29,7 @@ public partial interface IConversations
///
/// The cancellation token.
///
- Task> StartConversationWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken));
+ Task> StartConversationWithHttpMessagesAsync(string siteId = null, Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken));
///
/// Get information about an existing conversation
///
diff --git a/libraries/Client/ITokens.cs b/libraries/Client/ITokens.cs
index 8e11718..846b94c 100644
--- a/libraries/Client/ITokens.cs
+++ b/libraries/Client/ITokens.cs
@@ -29,7 +29,7 @@ public partial interface ITokens
///
/// The cancellation token.
///
- Task> RefreshTokenWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken));
+ Task> RefreshTokenWithHttpMessagesAsync(Dictionary> customHeaders = null, string conversationId = null, Func> tokenRefreshCallback = null, CancellationToken cancellationToken = default(CancellationToken));
///
/// Generate a token for a new conversation
///
diff --git a/libraries/Client/Tokens.cs b/libraries/Client/Tokens.cs
index afed274..faeb003 100644
--- a/libraries/Client/Tokens.cs
+++ b/libraries/Client/Tokens.cs
@@ -59,11 +59,14 @@ public Tokens(DirectLineClient client)
///
/// A response object containing the response body and response headers.
///
- public async Task> RefreshTokenWithHttpMessagesAsync(Dictionary> customHeaders = null, CancellationToken cancellationToken = default(CancellationToken))
+ public async Task> RefreshTokenWithHttpMessagesAsync(Dictionary> customHeaders = null, string conversationId = null, Func> tokenRefreshCallback = null, CancellationToken cancellationToken = default(CancellationToken))
{
+ var newToken = await tokenRefreshCallback();
+
// Tracing
bool _shouldTrace = ServiceClientTracing.IsEnabled;
string _invocationId = null;
+
if (_shouldTrace)
{
_invocationId = ServiceClientTracing.NextInvocationId.ToString();
@@ -73,7 +76,8 @@ public Tokens(DirectLineClient client)
}
// Construct URL
var _baseUrl = this.Client.BaseUri.AbsoluteUri;
- var _url = new Uri(new Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), "v3/directline/tokens/refresh").ToString();
+ var path = string .IsNullOrEmpty(newToken) || string.IsNullOrEmpty(conversationId) ? "v3/directline/tokens/refresh" : $"v3/directline/tokens/refresh/{conversationId}";
+ var _url = new Uri(new Uri(_baseUrl + (_baseUrl.EndsWith("/") ? "" : "/")), path).ToString();
// Create HTTP transport objects
HttpRequestMessage _httpRequest = new HttpRequestMessage();
HttpResponseMessage _httpResponse = null;
@@ -99,6 +103,7 @@ public Tokens(DirectLineClient client)
{
cancellationToken.ThrowIfCancellationRequested();
await this.Client.Credentials.ProcessHttpRequestAsync(_httpRequest, cancellationToken).ConfigureAwait(false);
+
}
// Send Request
if (_shouldTrace)
@@ -106,6 +111,12 @@ public Tokens(DirectLineClient client)
ServiceClientTracing.SendRequest(_invocationId, _httpRequest);
}
cancellationToken.ThrowIfCancellationRequested();
+
+ if (!(string.IsNullOrEmpty(newToken) || string.IsNullOrEmpty(conversationId)))
+ {
+ _httpRequest.Headers.TryAddWithoutValidation(TokensExtensions.Refresh_Token, newToken);
+ }
+
_httpResponse = await this.Client.HttpClient.SendAsync(_httpRequest, cancellationToken).ConfigureAwait(false);
if (_shouldTrace)
{
@@ -142,6 +153,15 @@ public Tokens(DirectLineClient client)
try
{
_result.Body = SafeJsonConvert.DeserializeObject(_responseContent, this.Client.DeserializationSettings);
+
+ var cc = this.Client.Credentials as DirectLineClientCredentials;
+
+ if(string.Equals(newToken, _result.Body.Token))
+ {
+ // Make the new token the new auth token from here on until next token refresh is called
+ cc.Authorization = _result.Body.Token;
+ }
+
}
catch (JsonException ex)
{
diff --git a/libraries/Client/TokensExtensions.cs b/libraries/Client/TokensExtensions.cs
index 59f8441..0e8455f 100644
--- a/libraries/Client/TokensExtensions.cs
+++ b/libraries/Client/TokensExtensions.cs
@@ -20,33 +20,61 @@ namespace Microsoft.Bot.Connector.DirectLine
///
public static partial class TokensExtensions
{
- ///
- /// Refresh a token
- ///
- ///
- /// The operations group for this extension method.
- ///
- public static Conversation RefreshToken(this ITokens operations)
+ public static readonly string Refresh_Token = "Refresh-Token";
+
+ ///
+ /// Refresh a token
+ ///
+ ///
+ /// The operations group for this extension method.
+ ///
+ public static Conversation RefreshToken(this ITokens operations)
+ {
+ return Task.Factory.StartNew(s => ((ITokens)s).RefreshTokenAsync(), operations, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap().GetAwaiter().GetResult();
+ }
+
+ ///
+ /// Refresh a token
+ ///
+ ///
+ /// The operations group for this extension method.
+ ///
+ ///
+ /// The cancellation token.
+ ///
+ public static async Task RefreshTokenAsync(this ITokens operations, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ using (var _result = await operations.RefreshTokenWithHttpMessagesAsync(null, null, null, cancellationToken).ConfigureAwait(false))
{
- return Task.Factory.StartNew(s => ((ITokens)s).RefreshTokenAsync(), operations, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default).Unwrap().GetAwaiter().GetResult();
+ return _result.Body;
}
+ }
- ///
- /// Refresh a token
- ///
- ///
- /// The operations group for this extension method.
- ///
- ///
- /// The cancellation token.
- ///
- public static async Task RefreshTokenAsync(this ITokens operations, CancellationToken cancellationToken = default(CancellationToken))
+ ///
+ /// Refresh a token
+ ///
+ ///
+ /// The operations group for this extension method.
+ ///
+ ///
+ /// The new AAD token used to continue a conversation.
+ ///
+ ///
+ /// The conversationId of the conversation to be continued.
+ ///
+ ///
+ /// A callback function to fetch an AAD token. Must return a token string.
+ ///
+ ///
+ /// The cancellation token.
+ ///
+ public static async Task RefreshTokenAsync(this ITokens operations, string conversationId, Func> tokenRefreshCallback = null, CancellationToken cancellationToken = default(CancellationToken))
+ {
+ using (var _result = await operations.RefreshTokenWithHttpMessagesAsync(null, conversationId, tokenRefreshCallback, cancellationToken).ConfigureAwait(false))
{
- using (var _result = await operations.RefreshTokenWithHttpMessagesAsync(null, cancellationToken).ConfigureAwait(false))
- {
- return _result.Body;
- }
+ return _result.Body;
}
+ }
///
/// Generate a token for a new conversation
diff --git a/libraries/DirectLineClientCredentials.cs b/libraries/DirectLineClientCredentials.cs
index eea7ce2..db1ae50 100644
--- a/libraries/DirectLineClientCredentials.cs
+++ b/libraries/DirectLineClientCredentials.cs
@@ -24,12 +24,15 @@ public class DirectLineClientCredentials : ServiceClientCredentials
#else
// .NET Core does not support System.Configuration API's.
private static Lazy _secret = new Lazy(() => null);
+ private static Lazy _token = new Lazy(() => null);
private static Lazy _endpoint = new Lazy(() => null);
#endif
public string Secret { get; private set; }
- public string Authorization { get; private set; }
+ public string Token { get; private set; }
+
+ public string Authorization { get; internal set; }
public string Endpoint { get; protected set; }
@@ -44,6 +47,19 @@ public DirectLineClientCredentials(string secret = null, string endpoint = null)
this.Endpoint = endpoint ?? _endpoint.Value ?? "https://directline.botframework.com/";
}
+ ///
+ /// Create a new instance of the DirectLineClientCredentials class
+ ///
+ /// default will come from Settings["DirectLineSecret"]
+ /// default will come from Settings["AadToken"]
+ public DirectLineClientCredentials(string secret, string token, string endpoint = null)
+ {
+ this.Secret = secret ?? _secret.Value;
+ this.Token = token ?? _token.Value;
+ this.Authorization = this.Secret ?? this.Token;
+ this.Endpoint = endpoint ?? _endpoint.Value ?? "https://directline.botframework.com/";
+ }
+
///
/// Apply the credentials to the HTTP request.
///
diff --git a/libraries/Microsoft.Bot.Connector.DirectLine.csproj b/libraries/Microsoft.Bot.Connector.DirectLine.csproj
index c214402..48db56d 100644
--- a/libraries/Microsoft.Bot.Connector.DirectLine.csproj
+++ b/libraries/Microsoft.Bot.Connector.DirectLine.csproj
@@ -27,5 +27,6 @@
+
\ No newline at end of file
diff --git a/samples/core-DirectLine/DirectLineBot.sln b/samples/core-DirectLine/DirectLineBot.sln
index 98de69d..37b74d6 100644
--- a/samples/core-DirectLine/DirectLineBot.sln
+++ b/samples/core-DirectLine/DirectLineBot.sln
@@ -1,9 +1,9 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25420.1
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31910.167
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DirectLineBot", "DirectLineBot\DirectLineBot.csproj", "{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DirectLineBot", "DirectLineBot\DirectLineBot.csproj", "{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DirectLineSampleClient", "DirectLineClient\DirectLineSampleClient.csproj", "{10935995-5C58-438B-B5F0-FA94BEA2667F}"
EndProject
@@ -12,6 +12,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "README", "README", "{24EE8F
README.md = README.md
EndProjectSection
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Bot.Connector.DirectLine", "..\..\libraries\Microsoft.Bot.Connector.DirectLine.csproj", "{222A7014-9EA6-4CCB-8F1E-8DBAF58668CA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DirectLineSampleAcuireTokenClient", "DirectLineClientAcquireToken\DirectLineSampleAcuireTokenClient.csproj", "{305A8431-1C17-4BF2-A0B6-8AC984D8F8AD}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -26,8 +30,19 @@ Global
{10935995-5C58-438B-B5F0-FA94BEA2667F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{10935995-5C58-438B-B5F0-FA94BEA2667F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{10935995-5C58-438B-B5F0-FA94BEA2667F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {222A7014-9EA6-4CCB-8F1E-8DBAF58668CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {222A7014-9EA6-4CCB-8F1E-8DBAF58668CA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {222A7014-9EA6-4CCB-8F1E-8DBAF58668CA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {222A7014-9EA6-4CCB-8F1E-8DBAF58668CA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {305A8431-1C17-4BF2-A0B6-8AC984D8F8AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {305A8431-1C17-4BF2-A0B6-8AC984D8F8AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {305A8431-1C17-4BF2-A0B6-8AC984D8F8AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {305A8431-1C17-4BF2-A0B6-8AC984D8F8AD}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {53F48480-F4AA-49AE-AE20-BB0564D0C452}
+ EndGlobalSection
EndGlobal
diff --git a/samples/core-DirectLine/DirectLineClientAcquireToken/App.config b/samples/core-DirectLine/DirectLineClientAcquireToken/App.config
new file mode 100644
index 0000000..7b97251
--- /dev/null
+++ b/samples/core-DirectLine/DirectLineClientAcquireToken/App.config
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/core-DirectLine/DirectLineClientAcquireToken/DirectLineSampleAcuireTokenClient.csproj b/samples/core-DirectLine/DirectLineClientAcquireToken/DirectLineSampleAcuireTokenClient.csproj
new file mode 100644
index 0000000..22e46c1
--- /dev/null
+++ b/samples/core-DirectLine/DirectLineClientAcquireToken/DirectLineSampleAcuireTokenClient.csproj
@@ -0,0 +1,125 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {305A8431-1C17-4BF2-A0B6-8AC984D8F8AD}
+ Exe
+ Properties
+ DirectLineSampleClient
+ DirectLineSampleClient
+ v4.6.1
+ 512
+ true
+
+
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+ ..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
+
+
+ ..\packages\Microsoft.Rest.ClientRuntime.2.3.4\lib\net45\Microsoft.Rest.ClientRuntime.dll
+ True
+
+
+ ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll
+
+
+
+ ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
+
+
+
+
+ ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
+
+
+
+ ..\packages\Microsoft.AspNet.WebApi.Client.5.2.7\lib\net45\System.Net.Http.Formatting.dll
+
+
+ ..\packages\System.Net.Http.Json.6.0.0\lib\net461\System.Net.Http.Json.dll
+
+
+
+
+ ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
+
+
+ ..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
+
+
+
+ ..\packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll
+
+
+ ..\packages\System.Text.Json.6.0.0\lib\net461\System.Text.Json.dll
+
+
+ ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
+
+
+ ..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {222a7014-9ea6-4ccb-8f1e-8dbaf58668ca}
+ Microsoft.Bot.Connector.DirectLine
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/core-DirectLine/DirectLineClientAcquireToken/Models/DirectLineCardContent.cs b/samples/core-DirectLine/DirectLineClientAcquireToken/Models/DirectLineCardContent.cs
new file mode 100644
index 0000000..e37e0d4
--- /dev/null
+++ b/samples/core-DirectLine/DirectLineClientAcquireToken/Models/DirectLineCardContent.cs
@@ -0,0 +1,9 @@
+namespace DirectLineSampleClient.Models
+{
+ public class DirectLineCardContent
+ {
+ public string Text { get; set; }
+
+ public string Title { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/samples/core-DirectLine/DirectLineClientAcquireToken/Models/Token.cs b/samples/core-DirectLine/DirectLineClientAcquireToken/Models/Token.cs
new file mode 100644
index 0000000..6513b3f
--- /dev/null
+++ b/samples/core-DirectLine/DirectLineClientAcquireToken/Models/Token.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DirectLineSampleClient.Models
+{
+ public class Token
+ {
+ // You can add more properties as in the token response object
+ public string accessToken { get; set; }
+ }
+}
diff --git a/samples/core-DirectLine/DirectLineClientAcquireToken/Models/TokenResponse.cs b/samples/core-DirectLine/DirectLineClientAcquireToken/Models/TokenResponse.cs
new file mode 100644
index 0000000..87c095a
--- /dev/null
+++ b/samples/core-DirectLine/DirectLineClientAcquireToken/Models/TokenResponse.cs
@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace DirectLineSampleClient.Models
+{
+ public class TokenResponse
+ {
+ public Token Token { get; set; }
+ }
+}
diff --git a/samples/core-DirectLine/DirectLineClientAcquireToken/Program.cs b/samples/core-DirectLine/DirectLineClientAcquireToken/Program.cs
new file mode 100644
index 0000000..fbf3bdd
--- /dev/null
+++ b/samples/core-DirectLine/DirectLineClientAcquireToken/Program.cs
@@ -0,0 +1,151 @@
+namespace DirectLineSampleClient
+{
+ using System;
+ using System.Configuration;
+ using System.Diagnostics;
+ using System.Linq;
+ using System.Net.Http;
+ using System.Net.Http.Headers;
+ using System.Threading.Tasks;
+ using Microsoft.Bot.Connector.DirectLine;
+ using Models;
+ using Newtonsoft.Json;
+
+ public class Program
+ {
+ private static string directLineSecret = null;
+ private static string token = null; // First initialized when a conversation is started.
+ private static string siteId = ""; // Add Site ID from Direct Line config channel here.
+ private static string botId = ""; // Add bot ID here
+ private static string fromUser = "DirectLineSampleClientUser";
+
+ public static void Main(string[] args)
+ {
+ StartBotConversation().Wait();
+ }
+
+ private static async Task StartBotConversation()
+ {
+ token = await TokenHelper.GetTokenAsync();
+
+ // if you are using a region-specific endpoint, change the uri and uncomment the code
+ var directLineUri = "https://directline.scratch.botframework.com/"; // endpoint in Azure Public Cloud
+ // If using token then first parameter of DirectLineClientCredentials must always be null
+ DirectLineClient client = new DirectLineClient(new Uri(directLineUri), new DirectLineClientCredentials(null, token, null));
+
+ var conversation = await client.Conversations.StartConversationAsync(siteId);
+
+ new System.Threading.Thread(async () => await ReadBotMessagesAsync(client, conversation.ConversationId)).Start();
+
+ // This is just to help validate that token refresh works by refreshing the conversion with a new AAD token.
+ // The next activity post will be sent with a new token.
+ // In an ideal project this should be in a token refresh loop that keeps on updating the AAD token token before it expires
+ var conv = await client.Tokens.RefreshTokenAsync(conversation.ConversationId, () => TokenHelper.GetTokenAsync());
+
+ if (!string.Equals(conversation?.ConversationId, conv?.ConversationId))
+ {
+ throw new Exception("Token not successfully refreshed. New conversation created.");
+ }
+
+ if (string.Equals(conversation?.Token, conv?.Token))
+ {
+ throw new Exception("Token not successfully refreshed. No new refresh token.");
+ }
+
+ // Update the token in case it is to be used in here and hereafter
+ if (!(string.IsNullOrEmpty(conv?.Token) && string.IsNullOrEmpty(conv?.ConversationId)))
+ {
+ token = conv.Token;
+ }
+
+ Console.Write("Command> ");
+
+ while (true)
+ {
+ string input = Console.ReadLine().Trim();
+
+ if (input.ToLower() == "exit")
+ {
+ break;
+ }
+ else
+ {
+ if (input.Length > 0)
+ {
+ Activity userMessage = new Activity
+ {
+ From = new ChannelAccount(fromUser),
+ Text = input,
+ Type = ActivityTypes.Message
+ };
+
+ await client.Conversations.PostActivityAsync(conversation.ConversationId, userMessage);
+ }
+ }
+ }
+ }
+
+ private static async Task ReadBotMessagesAsync(DirectLineClient client, string conversationId)
+ {
+ string watermark = null;
+
+ while (true)
+ {
+ var activitySet = await client.Conversations.GetActivitiesAsync(conversationId, watermark);
+ watermark = activitySet?.Watermark;
+
+ var activities = from x in activitySet.Activities
+ where x.From.Id == botId
+ select x;
+
+ foreach (Activity activity in activities)
+ {
+ Console.WriteLine(activity.Text);
+
+ if (activity.Attachments != null)
+ {
+ foreach (Attachment attachment in activity.Attachments)
+ {
+ switch (attachment.ContentType)
+ {
+ case "application/vnd.microsoft.card.hero":
+ RenderHeroCard(attachment);
+ break;
+
+ case "image/png":
+ Console.WriteLine($"Opening the requested image '{attachment.ContentUrl}'");
+
+ Process.Start(attachment.ContentUrl);
+ break;
+ }
+ }
+ } else
+ {
+ Console.WriteLine(activity?.AsMessageActivity());
+ }
+
+ Console.Write("Command> ");
+ }
+
+ await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
+ }
+ }
+
+ private static void RenderHeroCard(Attachment attachment)
+ {
+ const int Width = 70;
+ Func contentLine = (content) => string.Format($"{{0, -{Width}}}", string.Format("{0," + ((Width + content.Length) / 2).ToString() + "}", content));
+
+ var heroCard = JsonConvert.DeserializeObject(attachment.Content.ToString());
+
+ if (heroCard != null)
+ {
+ Console.WriteLine("/{0}", new string('*', Width + 1));
+ Console.WriteLine("*{0}*", contentLine(heroCard.Title));
+ Console.WriteLine("*{0}*", new string(' ', Width));
+ Console.WriteLine("*{0}*", contentLine(heroCard.Text));
+ Console.WriteLine("{0}/", new string('*', Width + 1));
+ }
+ }
+ }
+}
diff --git a/samples/core-DirectLine/DirectLineClientAcquireToken/Properties/AssemblyInfo.cs b/samples/core-DirectLine/DirectLineClientAcquireToken/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..41b3efe
--- /dev/null
+++ b/samples/core-DirectLine/DirectLineClientAcquireToken/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+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("DirectLineSampleClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("DirectLineSampleClient")]
+[assembly: AssemblyCopyright("Copyright © 2016")]
+[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("10935995-5c58-438b-b5f0-fa94bea2667f")]
+
+// 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.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/samples/core-DirectLine/DirectLineClientAcquireToken/TokenHelper.cs b/samples/core-DirectLine/DirectLineClientAcquireToken/TokenHelper.cs
new file mode 100644
index 0000000..781867b
--- /dev/null
+++ b/samples/core-DirectLine/DirectLineClientAcquireToken/TokenHelper.cs
@@ -0,0 +1,31 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using DirectLineSampleClient.Models;
+
+namespace DirectLineSampleClient
+{
+ public class TokenHelper
+ {
+ private static HttpClient client = new HttpClient();
+ // Your Token source service endpoint.
+ private static string tokenRefreshEndpoint = "http://localhost:3000/token/refresh";
+
+ public static async Task GetTokenAsync()
+ {
+ HttpResponseMessage response = await client.GetAsync(tokenRefreshEndpoint);
+ if (response.IsSuccessStatusCode)
+ {
+ var tokenResponse = await response.Content.ReadAsAsync();
+
+ return tokenResponse.Token.accessToken;
+ }
+
+ throw new Exception("Request Failed!");
+
+ }
+ }
+}
diff --git a/samples/core-DirectLine/DirectLineClientAcquireToken/packages.config b/samples/core-DirectLine/DirectLineClientAcquireToken/packages.config
new file mode 100644
index 0000000..f4dd23b
--- /dev/null
+++ b/samples/core-DirectLine/DirectLineClientAcquireToken/packages.config
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file