I get into to a problem last week where i want all my bots to be available in one single endpoint so i dont need to worry about domain names and SSL certificates for them.
I searched online and could not able to find an answer easily. So, i ended up writing what i have done. If you faced the same problem here it is.
Create MultiCredentialProvider class as below:
public class MultiCredentialProvider : ICredentialProvider
{
public Dictionary<string, string> Credentials = new Dictionary<string, string>
{
{ "AppId1", "AppPassword1" },
{ "AppId2", "AppPassword2" },
{ "AppId3", "AppPassword3" }
};
public Task<bool> IsValidAppIdAsync(string appId)
{
return Task.FromResult(this.Credentials.ContainsKey(appId));
}
public Task<string> GetAppPasswordAsync(string appId)
{
return Task.FromResult(this.Credentials.ContainsKey(appId) ? this.Credentials[appId] : null);
}
public Task<bool> IsAuthenticationDisabledAsync()
{
return Task.FromResult(!this.Credentials.Any());
}
}
Add this MultiCredentialProvider to your controller code:
[BotAuthentication(CredentialProviderType = typeof(MultiCredentialProvider))]
public class MessagesController : ApiController
{
static MessagesController()
{
// Update the container to use the right MicorosftAppCredentials based on
// Identity set by BotAuthentication
var builder = new ContainerBuilder();
builder.Register(c => ((ClaimsIdentity)HttpContext.Current.User.Identity).GetCredentialsFromClaims())
.AsSelf()
.InstancePerLifetimeScope();
builder.Update(Conversation.Container);
}
Add below to your ActivityTypes.ConversationUpdate:
IConversationUpdateActivity update = activity;
// resolve the connector client from the container to make sure that it is
// instantiated with the right MicrosoftAppCredentials
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
{
var client = scope.Resolve<IConnectorClient>();
if (update.MembersAdded.Any())
{
var reply = activity.CreateReply();
foreach (var newMember in update.MembersAdded)
{
if (newMember.Id != activity.Recipient.Id)
{
reply.Text = $"Welcome {newMember.Name}!";
await client.Conversations.ReplyToActivityAsync(reply);
}
}
}
}
That's it. It should now handle multiple appIds and passwords with in the same endpoint URL.
Here is the full code:
// Use the MultiCredentialProvider as credential provider for BotAuthentication
[BotAuthentication(CredentialProviderType = typeof(MultiCredentialProvider))]
//[BotAuthentication]
public class MessagesController : ApiController
{
static MessagesController()
{
// Update the container to use the right MicorosftAppCredentials based on
// Identity set by BotAuthentication
var builder = new ContainerBuilder();
builder.Register(c => ((ClaimsIdentity)HttpContext.Current.User.Identity).GetCredentialsFromClaims())
.AsSelf()
.InstancePerLifetimeScope();
builder.Update(Conversation.Container);
}
/// <summary>
/// POST: api/Messages
/// receive a message from a user and send replies
/// </summary>
/// <param name="activity"></param>
[ResponseType(typeof(void))]
public virtual async Task<HttpResponseMessage> Post([FromBody] Activity activity)
{
if (activity != null)
{
switch (activity.GetActivityType())
{
case ActivityTypes.Message:
await Conversation.SendAsync(activity, () => new RootDialog());
break;
case ActivityTypes.ConversationUpdate:
IConversationUpdateActivity update = activity;
// resolve the connector client from the container to make sure that it is
// instantiated with the right MicrosoftAppCredentials
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, activity))
{
var client = scope.Resolve<IConnectorClient>();
if (update.MembersAdded.Any())
{
var reply = activity.CreateReply();
foreach (var newMember in update.MembersAdded)
{
if (newMember.Id != activity.Recipient.Id)
{
reply.Text = $"Welcome {newMember.Name}!";
await client.Conversations.ReplyToActivityAsync(reply);
}
}
}
}
break;
case ActivityTypes.ContactRelationUpdate:
case ActivityTypes.Typing:
case ActivityTypes.DeleteUserData:
case ActivityTypes.Ping:
default:
Trace.TraceError($"Unknown activity type ignored: {activity.GetActivityType()}");
break;
}
}
return new HttpResponseMessage(System.Net.HttpStatusCode.Accepted);
}
Good luck!