如何在BOT v4中向MS团队发送主动消息

时间:2019-09-10 14:41:49

标签: c# botframework

我正在尝试向BOT V4中的MS团队发送一些主动消息,但是它不起作用。 可以在网络聊天和模拟器中使用,但不能在MS Teams中使用。

当我将下面的代码连接到MS团队时,主动消息现在也无法在Webchat和模拟器中使用。 我收到的错误消息是:

InvalidOperationException: Unable to resolve service for type 'Microsoft.Bot.Connector.Authentication.ICredentialProvider' while attempting to activate 'Intelbot.Controllers.NotifyController'.

能帮我吗? 谢谢

**Notify controller.cs**
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System;
using System.Collections.Concurrent;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Bot.Connector;
using Microsoft.Bot.Connector.Authentication;
using Microsoft.Bot.Connector.Teams;
using Microsoft.Bot.Schema;
using Microsoft.Bot.Schema.Teams;
using Microsoft.Extensions.Configuration;



namespace Intelbot.Controllers
{
    [Route("api/notify")]
    [ApiController]
    public class NotifyController : ControllerBase
    {
        public static bool notifWhenStateChanges = false;
        public static bool notifWhenAboutToKo = false;
        public static bool notifNewTickets = true;
        public static bool leaaccessrequest = false;
        public static bool notifyCommentsForm = false;
        private readonly IBotFrameworkHttpAdapter _adapter;
        private readonly string _appId;
        private readonly ConcurrentDictionary<string, ConversationReference> _conversationReferences;
        private readonly SimpleCredentialProvider _credentialProvider;
        public NotifyController(IBotFrameworkHttpAdapter adapter, IConfiguration configuration, ConcurrentDictionary<string, ConversationReference> conversationReferences, ICredentialProvider CredentialProvider)
        {
            _adapter = adapter;
            _conversationReferences = conversationReferences;
            _appId = configuration["MicrosoftAppId"];
            _credentialProvider = CredentialProvider as ConfigurationCredentialProvider;
            // If the channel is the Emulator, and authentication is not in use,
            // the AppId will be null.  We generate a random AppId for this case only.
            // This is not required for production, since the AppId will have a value.
            if (string.IsNullOrEmpty(_appId))
            {
                _appId = Guid.NewGuid().ToString(); //if no AppId, use a random Guid
            }
        }

        public async Task<IActionResult> Get()
        {
            foreach (var conversationReference in _conversationReferences.Values)
            {
                if (notifNewTickets == true)
                    await ((BotAdapter)_adapter).ContinueConversationAsync(_appId, conversationReference, BotCallback, default(CancellationToken));
            }
            // Let the caller know proactive messages have been sent
            return new ContentResult()
            {
                Content = "<html><body><h1>Proactive messages have been sent.</h1></body></html>",
                ContentType = "text/html",
                StatusCode = (int)HttpStatusCode.OK,
            };

        }


        private async Task BotCallback(ITurnContext turnContext, CancellationToken cancellationToken)
        {
            MicrosoftAppCredentials.TrustServiceUrl(turnContext.Activity.ServiceUrl);
            var teamConversationData = turnContext.Activity.GetChannelData<TeamsChannelData>();
            var connectorClient = new ConnectorClient(new Uri(turnContext.Activity.ServiceUrl), _credentialProvider.AppId, _credentialProvider.Password);

            var userId = "4534554654774412157657";
            var tenantId = teamConversationData.Tenant.Id;
            var parameters = new ConversationParameters
            {
                Members = new[] { new ChannelAccount(userId) },
                ChannelData = new TeamsChannelData
                {
                    Tenant = new TenantInfo(tenantId),
                },
            };

            var conversationResource = await connectorClient.Conversations.CreateConversationAsync(parameters);
            var message = Activity.CreateMessageActivity();
            message.Text = "This is a proactive message1.";
            await connectorClient.Conversations.SendToConversationAsync(conversationResource.Id, (Activity)message);
            await turnContext.SendActivityAsync("proactive hello");
            if (notifNewTickets)
            {
                // var splunkItem = await SplunkService.GetSplunkInfo("notification", "newTickets","");
                await turnContext.SendActivityAsync("**ALERT! New Tickets**" + Environment.NewLine);
            }


        }
    }
}

startup.cs
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.5.0

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Collections.Concurrent;
using Microsoft.Bot.Schema;
using Microsoft.Bot.Builder.Teams;
using Intelbot.Bots;
using Microsoft.Bot.Builder.Teams.Middlewares;
using Proactive;
using Proactive.Bots;
using Microsoft.Bot.Connector.Authentication;
using Intelbot.Controllers;

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

        public IConfiguration Configuration { get; }

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

            // Create the Bot Framework Adapter with error handling enabled.
            services.AddSingleton<IBotFrameworkHttpAdapter, AdapterWithErrorHandler>();
            // Create the storage we'll be using for User and Conversation state. (Memory is great for testing purposes.)
            services.AddSingleton<IStorage, MemoryStorage>();

            // Create the User state.
            services.AddSingleton<UserState>();

            // Create the Conversation state.
            services.AddSingleton<ConversationState>();

            // Create a global hashset for our ConversationReferences
            services.AddSingleton<ConcurrentDictionary<string, ConversationReference>>();

            var credentials = new SimpleCredentialProvider(Configuration["MicrosoftAppId"], Configuration["MicrosoftAppPassword"]);

            services.AddSingleton(credentials);

            // Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
            services.AddBot<ProactiveBot>(options =>
            {
                options.CredentialProvider = credentials;

                options.Middleware.Add(
                    new TeamsMiddleware(
                        new ConfigurationCredentialProvider(this.Configuration)));

                // Create the bot as a transient. In this case the ASP Controller is expecting an IBot.
                services.AddTransient<IBot, EchoBot>();
            });

        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            app.UseDefaultFiles();
            app.UseStaticFiles();

            //app.UseHttpsRedirection();
            app.UseMvc();
        }
    }
}

proactivebot.cs

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
// Generated with Bot Builder V4 SDK Template for Visual Studio EchoBot v4.3.0

// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;

namespace Intelbot.Bots
{
    public class ProactiveBot : ActivityHandler
    {
        // Message to send to users when the bot receives a Conversation Update event
        private const string WelcomeMessage = "Welcome to the Proactive Bot sample.  Navigate to http://localhost:3978/api/notify to proactively message everyone who has previously messaged this bot.";

        // Dependency injected dictionary for storing ConversationReference objects used in NotifyController to proactively message users
        private ConcurrentDictionary<string, ConversationReference> _conversationReferences;

        public ProactiveBot(ConcurrentDictionary<string, ConversationReference> conversationReferences)
        {
            _conversationReferences = conversationReferences;
        }

        private void AddConversationReference(Activity activity)
        {
            var conversationReference = activity.GetConversationReference();
            _conversationReferences.AddOrUpdate(conversationReference.User.Id, conversationReference, (key, newValue) => conversationReference);
        }

        protected override Task OnConversationUpdateActivityAsync(ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            AddConversationReference(turnContext.Activity as Activity);

            return base.OnConversationUpdateActivityAsync(turnContext, cancellationToken);
        }

        protected override async Task OnMembersAddedAsync(IList<ChannelAccount> membersAdded, ITurnContext<IConversationUpdateActivity> turnContext, CancellationToken cancellationToken)
        {
            foreach (var member in membersAdded)
            {
                // Greet anyone that was not the target (recipient) of this message.
                if (member.Id != turnContext.Activity.Recipient.Id)
                {
                    await turnContext.SendActivityAsync(MessageFactory.Text(WelcomeMessage), cancellationToken);
                }
            }
        }

        protected override async Task OnMessageActivityAsync(ITurnContext<IMessageActivity> turnContext, CancellationToken cancellationToken)
        {
            AddConversationReference(turnContext.Activity as Activity);

            // Echo back what the user said
            await turnContext.SendActivityAsync(MessageFactory.Text($"You sent '{turnContext.Activity.Text}'"), cancellationToken);
        }
    }
}


1 个答案:

答案 0 :(得分:1)

您的构造函数在应询问接口SimpleCredentialProvider时会询问具体的类ICredentialProvider

更改:

public NotifyController(... SimpleCredentialProvider CredentialProvider)

收件人:

public NotifyController(... ICredentialProvider CredentialProvider)
[...]
_credentialProvider = CredentialProvider as ConfigurationCredentialProvider;

这假设您在Startup.cs中有此名称:

services.AddSingleton<ICredentialProvider, ConfigurationCredentialProvider>();

相反,如果您有更多类似这样的内容:

services.AddBot<LuisTranslatorBot>(options =>
{
    options.CredentialProvider = new SimpleCredentialProvider(endpointService.AppId, endpointService.AppPassword);

...您需要使用:

ICredentialProvider credentialProvider