[Question] How can I override Autofac configuration to provide my own custom ConnectorClient?
See original GitHub issueBot Info
- SDK Platform: .NET
- SDK Version: 3.11
- Active Channels: Direct Line
- Deployment Environment: Azure App Service
Issue Description
I would like to override the Bot Builder’s Autofac configuration so that I can provide my own custom ConnectorClient sub class, instead of the default one.
I want to do this so that I can pass a static HttpClient to the ConnectorClient. We’re getting socket exhaustion problems in the cloud, and I think HttpClient reuse would help a lot. This ticket is just a question about overriding ConnectorClient in Autofac though, not the socket exhaustion issue (that’s logged as another ticket)
Code Example
Global.asax.cs
/* Global.asax.cs configuration to inject my custom autofac module */
protected async void Application_Start()
{
var containerBuilder = new ContainerBuilder();
GlobalConfiguration.Configure(WebApiConfig.Register);
MicrosoftAppCredentials.TrustServiceUrl(@"https://facebook.botframework.com", DateTime.MaxValue);
MicrosoftAppCredentials.TrustServiceUrl(@"https://directline.botframework.com", DateTime.MaxValue);
MicrosoftAppCredentials.TrustServiceUrl(@"https://bc-directline-weurope.azurewebsites.net", DateTime.MaxValue);
ConfigureDependencyInjection(containerBuilder);
}
private static void ConfigureDependencyInjection(ContainerBuilder containerBuilder)
{
// register the Bot Builder module
containerBuilder.RegisterModule(new DialogModule());
// Override bot framework defaults.
containerBuilder.RegisterModule(new MyOwnDiModule());
var config = GlobalConfiguration.Configuration;
// Register your Web API controllers.
containerBuilder.RegisterApiControllers(Assembly.GetExecutingAssembly());
containerBuilder.RegisterWebApiFilterProvider(config);
// Set the dependency resolver to be Autofac.
var container = containerBuilder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
MyOwnDiModule - where I try to tell the bot framework to use my custom connectorclient
public class MyOwnDiModule: Module
{
static HttpClient _globalHttpClient = new HttpClient();
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
//ConnectorClient override that takes a global static HttpClientHandler.
builder
.Register(c => new MyCustomConnectorClient(_globalHttpClient, new Uri(c.Resolve<IAddress>().ServiceUrl), c.Resolve<MicrosoftAppCredentials>(), _globalHttpClientHandler))
.As<IConnectorClient>()
.InstancePerMatchingLifetimeScope(typeof(DialogModule));
}
}
I have not created the MyCustomConnectorClient yet, but setting a breakpoint on the Autofac IConnectorClient registration shows that my custom Register() delegate is never called.
A dialog that should use MyCustomConnectorClient internally when sending messages back to the user
Nothing fancy here. This is my root dialog, and when context.PostAsync is called, I would like MyCustomConnectorClient to be used internally.
[Serializable]
public class MyRootDialog: IDialog<string>
{
public async Task StartAsync(IDialogContext context)
{
await context.PostAsync($"Testing dialog started. Hit me.");
context.Wait(ResumeHere);
}
private async Task ResumeHere(IDialogContext context, IAwaitable<IMessageActivity> result)
{
await context.PostAsync($"Msg received thanks. time:{DateTime.Now.ToLongTimeString()}");
}
}
MessagesController
The messageController does not do anything special, except use Conversation to launch the root dialog:
/// <summary>
/// POST: api/Messages
/// </summary>
public async Task<HttpResponseMessage> Post([FromBody] Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new MyRootDialog());
}
return Request.CreateResponse(HttpStatusCode.OK);
}
How do I supply a custom sub class of ConnectorClient? (or alternatively, how do I use a static instance of HttpClient?)
Issue Analytics
- State:
- Created 6 years ago
- Reactions:3
- Comments:5 (2 by maintainers)
Here is what we did eventually, and it had a big positive impact on socket usage. Worth creating a PR for?
Global.asax.cs
Here we tell the bot framework to use our own custom stateClient and connectorClient (via our
BotFrameworkOverrideDefaultsModule
)Our custom Autofac module
Custom StateClient and ConnectorClient sub-classes that don’t dispose their HttpClient.
A static HttpClient is created per uri.
Hey @willemodendaal
There’s an alpha release of v4 here: https://github.com/Microsoft/botbuilder-dotnet
And, there’s already been some discussion about static http client here: https://github.com/Microsoft/botbuilder-dotnet/issues/106