Cannot post activity. Unauthorize. Bot emulator error

独自空忆成欢 提交于 2020-01-04 05:52:20

问题


I have added these line of codes to my bot's Startup.cs in order for it to work in Azure's WebChat:

var appid = Configuration.GetSection("microsoftappid").Value;
var apppassword = Configuration.GetSection("microsoftapppassword").Value;
options.CredentialProvider = new SimpleCredentialProvider(appid, apppassword);

However, when I have these lines my bot does not work in Bot emulator. How can I integrate it with my bot so that I don't need to comment/uncomment the line of codes when publishing and opening my bot in the emulator. I am not that good yet in reading code so sorry for asking this. Thanks!

public class Startup
{
    private ILoggerFactory _loggerFactory;
    private bool _isProduction = false;

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

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

        Configuration = builder.Build();
    }

    public IConfiguration Configuration { get; }


    public void ConfigureServices(IServiceCollection services)
    {
        var secretKey = Configuration.GetSection("botFileSecret")?.Value;
        var botFilePath = Configuration.GetSection("botFilePath")?.Value;
        if (!File.Exists(botFilePath))
        {
            throw new FileNotFoundException($"The .bot configuration file was not found. botFilePath: {botFilePath}");
        }

        BotConfiguration botConfig = null;
        try
        {
            botConfig = BotConfiguration.Load(botFilePath, secretKey);
        }
        catch
        {
            var msg = @"Error reading bot file. Please ensure you have valid botFilePath and botFileSecret set for your environment.
            - You can find the botFilePath and botFileSecret in the Azure App Service application settings.
            - If you are running this bot locally, consider adding a appsettings.json file with botFilePath and botFileSecret.
            - See https://aka.ms/about-bot-file to learn more about .bot file its use and bot configuration.
            ";
            throw new InvalidOperationException(msg);
        }

        services.AddSingleton(sp => botConfig ?? throw new InvalidOperationException($"The .bot configuration file could not be loaded. botFilePath: {botFilePath}"));

        var connectedServices = InitBotServices(botConfig);
        services.AddSingleton(sp => connectedServices);

        var environment = _isProduction ? "production" : "development";
        var service = botConfig.Services.FirstOrDefault(s => s.Type == "endpoint" && s.Name == environment);
        if (service == null && _isProduction)
        {

            service = botConfig.Services.Where(s => s.Type == "endpoint" && s.Name == "development").FirstOrDefault();
        }

        if (!(service is EndpointService endpointService))
        {
            throw new InvalidOperationException($"The .bot file does not contain an endpoint with name '{environment}'.");
        }

        services.AddBot<CoreBot>(options =>
        {
            options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
            options.ChannelProvider = new ConfigurationChannelProvider(Configuration);

            var appid = Configuration.GetSection("microsoftappid").Value;
            var apppassword = Configuration.GetSection("microsoftapppassword").Value;
            options.CredentialProvider = new SimpleCredentialProvider(appid, apppassword);

            ILogger logger = _loggerFactory.CreateLogger<CoreBot>();
            options.OnTurnError = async (context, exception) =>
            {
                logger.LogError($"Exception caught : {exception}");
                await context.SendActivityAsync($"Oops Sorry, it looks like something went wrong.");
            };

            IStorage dataStore = new MemoryStorage();

            var conversationState = new ConversationState(dataStore);
            options.State.Add(conversationState);

            var userState = new UserState(dataStore);
            options.State.Add(userState);

        });

        services.AddSingleton<BasicAccessors>(sp =>
        {
            var options = sp.GetRequiredService<IOptions<BotFrameworkOptions>>().Value;
            if (options == null)
            {
                throw new InvalidOperationException("BotFrameworkOptions must be configured prior to setting up the state accessors");
            }

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

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

            var accessors = new BasicAccessors(conversationState, userState)
            {
                DialogStateAccessor = conversationState.CreateProperty<DialogState>(BasicAccessors.DialogStateAccessorName),
                UserStateAccessor = userState.CreateProperty<UserProfile>(BasicAccessors.UserStateAccessorName),
                ComplaintTicketAccessor = conversationState.CreateProperty<ComplaintTicket>(BasicAccessors.ComplaintTicketName),
            };

            return accessors;
        });
    }

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

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

    private static BotServices InitBotServices(BotConfiguration config)
    {
        var qnaServices = new Dictionary<string, QnAMaker>();
        var luisServices = new Dictionary<string, LuisRecognizer>();

        foreach (var service in config.Services)
        {
            switch (service.Type)
            {
                case ServiceTypes.Luis:
                    {
                        if (!(service is LuisService luis))
                        {
                            throw new InvalidOperationException("The LUIS service is not configured correctly in your '.bot' file.");
                        }

                        var app = new LuisApplication(luis.AppId, luis.SubscriptionKey, luis.GetEndpoint());
                        var recognizer = new LuisRecognizer(app);
                        luisServices.Add(luis.Name, recognizer);
                        break;
                    }

                case ServiceTypes.Dispatch:

                    if (!(service is DispatchService dispatch))
                    {
                        throw new InvalidOperationException("The Dispatch service is not configured correctly in your '.bot' file.");
                    }        

                    var dispatchApp = new LuisApplication(dispatch.AppId, dispatch.AuthoringKey, dispatch.GetEndpoint());

                    var dispatchARecognizer = new LuisRecognizer(dispatchApp);
                    luisServices.Add(dispatch.Name, dispatchARecognizer);
                    break;

                case ServiceTypes.QnA:
                    {

                        if (!(service is QnAMakerService qna))
                        {
                            throw new InvalidOperationException("The QnA service is not configured correctly in your '.bot' file.");
                        }

                        var qnaEndpoint = new QnAMakerEndpoint()
                        {
                            KnowledgeBaseId = qna.KbId,
                            EndpointKey = qna.EndpointKey,
                            Host = qna.Hostname,
                        };

                        var qnaMaker = new QnAMaker(qnaEndpoint);
                        qnaServices.Add(qna.Name, qnaMaker);

                        break;
                    }
            }
        }

        return new BotServices(qnaServices, luisServices);
    }
}

}


回答1:


You can use this code to meet your needs. If you run the code in your local environment, the value of _isProduction is false. If you run the code in Azure, the value of _isProduction is true.

       var appid = Configuration.GetSection("microsoftappid").Value;
       var apppassword = Configuration.GetSection("microsoftapppassword").Value;
       if (_isProduction)
       {
           options.CredentialProvider = new SimpleCredentialProvider(appid, apppassword);
       }
       else
       {
           options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);
       }

Add botFileSecret and botFilePath which were in your local bot appsettings.json file to the new appsettings.json file.

Now the code will be both working on azure and the emulator. Besides, I noticed that you are using Memory Storage which is for local bot debugging only. When the bot is restarted, everything stored in memory will be gone.

IStorage dataStore = new MemoryStorage();

For production bots, you can use the Azure Blob or Azure CosmosDB storage providers.




回答2:


Use 2 .bot files (e.g. dev.bot & prod.bot)

In dev.bot, add endpoint for emulator like this:

{
  "type": "endpoint",
  "name": "dev",
  "endpoint": "http://localhost:3978/api/messages",
  "appId": "",
  "appPassword": "",
  "id": "1"
},

You would add the appId and appPassword in the prod.bot, along with a correct endpoint (e.g. hosted on Azure: ***.azurewebsites.net/api/messages).

Use appSettings.json + create appSettings.dev.json & appSettings.prod.json. Make sure .dev.json sets

"botFilePath": ".\\dev.bot"

Analoguously for appSettings.prod.json.

I found that you receive the unauthorized error in the emulator when the ASPNETCORE_ENVIRONMENT environment variable is not equal to the "name" endpoint parameter in the .bot file being used. So when debugging locally on emulator, set ASPNETCORE_ENVIRONMENT equal to (in this case) 'dev'.

You can set this by right-clicking the .NET core web project -> Properties -> Debug (tab) -> Environment variables.



来源:https://stackoverflow.com/questions/55646534/cannot-post-activity-unauthorize-bot-emulator-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!