Untitled diff

Created Diff never expires
2 removals
Lines
Total
Removed
Words
Total
Removed
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
157 lines
16 additions
Lines
Total
Added
Words
Total
Added
To continue using this feature, upgrade to
Diffchecker logo
Diffchecker Pro
171 lines
// Copyright (c) Microsoft Corporation. All rights reserved.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Licensed under the MIT License.


using System;
using System;
using System.IO;
using System.IO;
using System.Linq;
using System.Linq;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Azure;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Dialogs;
using Microsoft.Bot.Builder.Integration;
using Microsoft.Bot.Builder.Integration;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Configuration;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Options;


namespace Microsoft.BotBuilderSamples
namespace Microsoft.BotBuilderSamples
{
{
/// <summary>
/// <summary>
/// The Startup class configures services and the app's request pipeline.
/// The Startup class configures services and the app's request pipeline.
/// </summary>
/// </summary>
public class Startup
public class Startup
{
{
private const string CosmosServiceEndpoint = "https://localhost:8081";
private const string CosmosDBKey = "C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
private const string CosmosDBDatabaseName = "bot-cosmos-sql-db";
private const string CosmosDBCollectionName = "bot-storage";

private static readonly CosmosDbStorage _myStorage = new CosmosDbStorage(new CosmosDbStorageOptions
{
AuthKey = CosmosDBKey,
CollectionId = CosmosDBCollectionName,
CosmosDBEndpoint = new Uri(CosmosServiceEndpoint),
DatabaseId = CosmosDBDatabaseName,
});

private ILoggerFactory _loggerFactory;
private ILoggerFactory _loggerFactory;
private bool _isProduction = false;
private bool _isProduction = false;


public Startup(IHostingEnvironment env)
public Startup(IHostingEnvironment env)
{
{
_isProduction = env.IsProduction();
_isProduction = env.IsProduction();


var builder = new ConfigurationBuilder()
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
.AddEnvironmentVariables();


Configuration = builder.Build();
Configuration = builder.Build();
}
}


/// <summary>
/// <summary>
/// Gets the configuration that represents a set of key/value application configuration properties.
/// Gets the configuration that represents a set of key/value application configuration properties.
/// </summary>
/// </summary>
/// <value>
/// <value>
/// The <see cref="IConfiguration"/> that represents a set of key/value application configuration properties.
/// The <see cref="IConfiguration"/> that represents a set of key/value application configuration properties.
/// </value>
/// </value>
public IConfiguration Configuration { get; }
public IConfiguration Configuration { get; }


/// <summary>
/// <summary>
/// This method gets called by the runtime. Use this method to add services to the container.
/// This method gets called by the runtime. Use this method to add services to the container.
/// </summary>
/// </summary>
/// <param name="services">The <see cref="IServiceCollection"/> specifies the contract for a collection of service descriptors.</param>
/// <param name="services">The <see cref="IServiceCollection"/> specifies the contract for a collection of service descriptors.</param>
/// <seealso cref="IStatePropertyAccessor{T}"/>
/// <seealso cref="IStatePropertyAccessor{T}"/>
/// <seealso cref="https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection"/>
/// <seealso cref="https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection"/>
/// <seealso cref="https://docs.microsoft.com/en-us/azure/bot-service/bot-service-manage-channels?view=azure-bot-service-4.0"/>
/// <seealso cref="https://docs.microsoft.com/en-us/azure/bot-service/bot-service-manage-channels?view=azure-bot-service-4.0"/>
public void ConfigureServices(IServiceCollection services)
public void ConfigureServices(IServiceCollection services)
{
{
services.AddBot<SimplePromptBot>(options =>
services.AddBot<SimplePromptBot>(options =>
{
{
var secretKey = Configuration.GetSection("botFileSecret")?.Value;
var secretKey = Configuration.GetSection("botFileSecret")?.Value;
var botFilePath = Configuration.GetSection("botFilePath")?.Value;
var botFilePath = Configuration.GetSection("botFilePath")?.Value;
if (!File.Exists(botFilePath))
if (!File.Exists(botFilePath))
{
{
throw new FileNotFoundException($"The .bot configuration file was not found. botFilePath: {botFilePath}");
throw new FileNotFoundException($"The .bot configuration file was not found. botFilePath: {botFilePath}");
}
}


// Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
// Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.
var botConfig = BotConfiguration.Load(botFilePath ?? @".\simple-prompt.bot", secretKey);
var botConfig = BotConfiguration.Load(botFilePath ?? @".\simple-prompt.bot", secretKey);
services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot configuration file could not be loaded. botFilePath: {botFilePath}"));
services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot configuration file could not be loaded. botFilePath: {botFilePath}"));


// Retrieve current endpoint.
// Retrieve current endpoint.
var environment = _isProduction ? "production" : "development";
var environment = _isProduction ? "production" : "development";
var service = botConfig.Services.FirstOrDefault(s => s.Type == "endpoint" && s.Name == environment);
var service = botConfig.Services.FirstOrDefault(s => s.Type == "endpoint" && s.Name == environment);
if (!(service is EndpointService endpointService))
if (!(service is EndpointService endpointService))
{
{
throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'.");
throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'.");
}
}


options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);


// Creates a logger for the application to use.
// Creates a logger for the application to use.
ILogger logger = _loggerFactory.CreateLogger<SimplePromptBot>();
ILogger logger = _loggerFactory.CreateLogger<SimplePromptBot>();


// Catches any errors that occur during a conversation turn and logs them.
// Catches any errors that occur during a conversation turn and logs them.
options.OnTurnError = async (context, exception) =>
options.OnTurnError = async (context, exception) =>
{
{
logger.LogError($"Exception caught : {exception}");
logger.LogError($"Exception caught : {exception}");
await context.SendActivityAsync("Sorry, it looks like something went wrong.");
await context.SendActivityAsync("Sorry, it looks like something went wrong.");
};
};


// Memory Storage is for local bot debugging only. When the bot
// Memory Storage is for local bot debugging only. When the bot
// is restarted, everything stored in memory will be gone.
// is restarted, everything stored in memory will be gone.
IStorage dataStore = new MemoryStorage();
//IStorage dataStore = new MemoryStorage();


// For production bots use the Azure Blob or
// For production bots use the Azure Blob or
// Azure CosmosDB storage providers. For the Azure
// Azure CosmosDB storage providers. For the Azure
// based storage providers, add the Microsoft.Bot.Builder.Azure
// based storage providers, add the Microsoft.Bot.Builder.Azure
// Nuget package to your solution. That package is found at:
// Nuget package to your solution. That package is found at:
// https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/
// https://www.nuget.org/packages/Microsoft.Bot.Builder.Azure/
// Uncomment the following lines to use Azure Blob Storage
// Uncomment the following lines to use Azure Blob Storage
// //Storage configuration name or ID from the .bot file.
// //Storage configuration name or ID from the .bot file.
// const string StorageConfigurationId = "<STORAGE-NAME-OR-ID-FROM-BOT-FILE>";
// const string StorageConfigurationId = "<STORAGE-NAME-OR-ID-FROM-BOT-FILE>";
// var blobConfig = botConfig.FindServiceByNameOrId(StorageConfigurationId);
// var blobConfig = botConfig.FindServiceByNameOrId(StorageConfigurationId);
// if (!(blobConfig is BlobStorageService blobStorageConfig))
// if (!(blobConfig is BlobStorageService blobStorageConfig))
// {
// {
// throw new InvalidOperationException($"The .bot file does not contain an blob storage with name '{StorageConfigurationId}'.");
// throw new InvalidOperationException($"The .bot file does not contain an blob storage with name '{StorageConfigurationId}'.");
// }
// }
// // Default container name.
// // Default container name.
// const string DefaultBotContainer = "<DEFAULT-CONTAINER>";
// const string DefaultBotContainer = "<DEFAULT-CONTAINER>";
// var storageContainer = string.IsNullOrWhiteSpace(blobStorageConfig.Container) ? DefaultBotContainer : blobStorageConfig.Container;
// var storageContainer = string.IsNullOrWhiteSpace(blobStorageConfig.Container) ? DefaultBotContainer : blobStorageConfig.Container;
// IStorage dataStore = new Microsoft.Bot.Builder.Azure.AzureBlobStorage(blobStorageConfig.ConnectionString, storageContainer);
// IStorage dataStore = new Microsoft.Bot.Builder.Azure.AzureBlobStorage(blobStorageConfig.ConnectionString, storageContainer);


// Create Conversation State object.
// Create Conversation State object.
// The Conversation State object is where we persist anything at the conversation-scope.
// The Conversation State object is where we persist anything at the conversation-scope.
var conversationState = new ConversationState(dataStore);
var conversationState = new ConversationState(_myStorage);


options.State.Add(conversationState);
options.State.Add(conversationState);
});
});


services.AddSingleton(sp =>
services.AddSingleton(sp =>
{
{
// We need to grab the conversationState we added on the options in the previous step.
// We need to grab the conversationState we added on the options in the previous step.
var options = sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value;
var options = sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value;
if (options == null)
if (options == null)
{
{
throw new InvalidOperationException("BotFrameworkOptions must be configured prior to setting up the State Accessors");
throw new InvalidOperationException("BotFrameworkOptions must be configured prior to setting up the State Accessors");
}
}


var conversationState = options.State.OfType<ConversationState>().FirstOrDefault();
var conversationState = options.State.OfType<ConversationState>().FirstOrDefault();
if (conversationState == null)
if (conversationState == null)
{
{
throw new InvalidOperationException("ConversationState must be defined and added before adding conversation-scoped state accessors.");
throw new InvalidOperationException("ConversationState must be defined and added before adding conversation-scoped state accessors.");
}
}


// The dialogs will need a state store accessor. Creating it here once (on-demand) allows the dependency injection
// The dialogs will need a state store accessor. Creating it here once (on-demand) allows the dependency injection
// to hand it to our IBot class that is create per-request.
// to hand it to our IBot class that is create per-request.
var accessors = new SimplePromptBotAccessors(conversationState)
var accessors = new SimplePromptBotAccessors(conversationState)
{
{
ConversationDialogState = conversationState.CreateProperty<DialogState>("DialogState"),
ConversationDialogState = conversationState.CreateProperty<DialogState>("DialogState"),
};
};


return accessors;
return accessors;
});
});
}
}


public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
{
_loggerFactory = loggerFactory;
_loggerFactory = loggerFactory;


app.UseDefaultFiles()
app.UseDefaultFiles()
.UseStaticFiles()
.UseStaticFiles()
.UseBotFramework();
.UseBotFramework();
}
}
}
}
}
}