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



我正在尝试向 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);
}
}
}

您的构造函数正在请求具体类,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

最新更新