Implemented custom data storage, bot still calls state.botframework.com - c#

Summary:
We implemented TableBotDataStore in our C# Bot, but somehow the bot is still making calls to the deprecated State API.
Context:
In Application Insights I can see that our bot is making and a lot of calls to state.botframework.com. I also noticed that our production environment get's 200 responses on those requests, but our new Web App Bot is getting a 405 (Method Not Allowed) on all those request.
When we started developing the bot (May, 2018) we implemented the Azure Table Storage right away. So I was quite surprised to find that our bot is still calling state.botframework.com.
This blogpost by MS states:
Read options will continue to be available through July 31st 2018
My assumption is that MS still allows requests to the State API for bots that were registered before a certain date.
What I tried:
I have already followed Microsoft's guide on how to Manage custom state data with Azure Table Storage for .NET. I also read the related question Migrated bot state provider but calls to state.botframework.com are still being made but it doesn't help me.
My code:
Conversation.UpdateContainer(
builder =>
{
builder.RegisterModule(new AzureModule(Assembly.GetExecutingAssembly()));
var store = new
TableBotDataStore(ConfigurationManager.AppSettings["AzureWebJobsStorage"]);
builder.Register(c => store)
.Keyed<IBotDataStore<BotData>>(AzureModule.Key_DataStore)
.AsSelf()
.SingleInstance();
builder.Register(c => new CachingBotDataStore(store,
CachingBotDataStoreConsistencyPolicy
.ETagBasedConsistency))
.As<IBotDataStore<BotData>>()
.AsSelf()
.InstancePerLifetimeScope();
});
GlobalConfiguration.Configure(WebApiConfig.Register);
What I expect:
With this configuration, I expect that our bot only uses the TableBotDataStore and doesn't make any calls to the deprecated State API.

Related

Consume third party API with Blazor WebAssembly [duplicate]

I have a blazor web assembly which fetches from an external API built on ASP.NET Core which I do not have access to. I can perform get requests, but cannot perform post requests. I get the following error when I do.
Access to fetch at 'http://external:9000/User/Create' from origin 'http://localhost:56138' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
The author of the api confirms he enabled cors to allow any header in his startup and also suggested I do the same but this did not fix the issue. I confirmed from the debugger I am sending the right data format the endpoint requires and I am also running on http scheme same as the web service.
This is the client configuration in program.cs
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("http://external:9000/") });
builder.Services.AddCors(policy =>
{
policy.AddPolicy("_myAllowSpecificOrigins", builder => builder.WithOrigins("http://external:9000/")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
This is how I post
var dataJson = JsonConvert.SerializeObject(application);
var stringContent = new StringContent(dataJson, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"User/Create", stringContent);
I have read this is a common problem with blazor assembly, I'm not entirely sure of what I read. I am currently trying to move the project to blazor server to see if it would work, but I would prefer it on web assembly.
builder.Services.AddCors(policy =>
{
policy.AddPolicy("_myAllowSpecificOrigins", builder => builder.WithOrigins("http://external:9000/")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
This configuration should be done on a Server, and not yours but the server of the external API. You do nothing in that regard, except call end points on that Web Api.
The author of the api confirms they enabled cors to allow any header in his startup
If so, ask them for the code for confirmation...
and also suggested I do the same but this did not fix the issue.
You do nothing of the sort.
Workaround solution:
AS CORS is a security feature of JavaScript enforced by the browser, you can circumvent it by calling your Server code from which you perform the call to this Web Api end point, and then returns it back to your WebAssembly front-end. Use asynchronous code as much as you can.
Update as per comment
Are you saying I should have two projects, the server and the client under one solution? The server calls the calls the external api, then passes it to the client. Is this what your last suggestion is?
If you're using WebAssembly Blazor App hosted wherein the hosting server contains Web Api controllers, then you should expose end points that can be called from your WebAssembly front-end. The code in these end points should perform the HTTP calls to the external Web Api, and pass back to the WebAssembly calling methods the data received from the external Web Api.
Note: If you don't have such controllers ( they are created by default by Visual Studio), you may add them yourself to the server project.
If you already have created a Web Api project instead of those controllers, then expose the necessary end points from your Web Api project. Note that it makes no difference whether your Web Api project resides in the same solution of the WebAssembly front-end, as long as you provide the correct Url.
If you're using WebAssembly Blazor App stand alone; that is, the default installation does not create a Server project, you'll need to create a Web Api project and use it, unless you've already created one.
You are working with localhost so you should use this configuration to your Server:
builder.Services.AddCors(policy =>
{
policy.AddPolicy("_myAllowSpecificOrigins", builder =>
builder.WithOrigins("http://localhost:56138/")
.SetIsOriginAllowed((host) => true) // this for using localhost address
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
//
app.UseCors("_myAllowSpecificOrigins");

What is the difference between graphql-dotnet/graphql-dotnet/ and graphql-dotnet/server/

Good morning.
I am a bit confused about these two repositories(graphql-dotnet/graphql-dotnet/ and graphql-dotnet/server/).
https://github.com/graphql-dotnet/graphql-dotnet/ and
https://github.com/graphql-dotnet/server
They are both under the same organization and there is some overlap of contributors, but I'm a bit lost about deciding which one to use.
I would like to build a dotnet 5 application that hosts a graphql endpoint. In a nutshell that is my goal.
I noticed that the graphql-dotnet/server/repository has inbuilt some helpers such as.
serviceCollection
.AddGraphQL((options, provider) =>
{
options.EnableMetrics = HostEnvironment.IsDevelopment();
var logger = provider.GetRequiredService<ILogger<Startup>>();
options.UnhandledExceptionDelegate = ctx => logger.LogError("{Error} occurred", ctx.OriginalException.Message);
})
.AddSystemTextJson()
.AddErrorInfoProvider(opt => opt.ExposeExceptionStackTrace = HostEnvironment.IsDevelopment())
.AddWebSockets()
.AddDataLoader()
.AddGraphTypes(typeof(ApplicationSchema))
Which allows my DI to be setup nice and easy. Its counterpart, the graphql-dotnet/graphql-dotnet/ does not.
So my question is "which one should I use exclusivly? Which one is recomended, by secondary goals are to add jwt authentication and finally federation support. But those two are far down the line.
One of my coworkers went ahead and used graphql-dotnet/graphql-dotnet/ and his server application has a lot more configuration than the documentation of graphql-dotnet/server/ so how do I know which one do I use?
Can any one recommend any documentation that highlights the difference between the two of them?
The main graphql-dotnet repo is the "core" library of GraphQL components. The server repo contains ASP.NET specific extensions. It uses the core library. If you use the server project, you are also using the core library.
GraphQL itself can be used with any protocol, it is not required to be used with HTTP or JSON. So the core library does not have any HTTP or ASP.NET dependencies.
If you are using ASP.NET, then the server project is the quickest way to get started. If you want to use Subscriptions, then the server project provides that functionality.
If you don't need subscriptions and if you want a bit more control over how the framework handles the HTTP request, then it would be easier to write your own controller or middleware.
Using JWT authentication is handled by ASP.NET and can be used in either scenario. Federation can also be used in either scenario.

Periodically reload credentials on SearchServiceClient and child ISearchIndexClient singletons

In our web app dependency injection, we configure the ISearchIndexClient instances returned by .NET Azure Search SDK's SearchServiceClient.Indexes.GetClient(...) as a singletons.
We did this because of the answer https://stackoverflow.com/a/43502662 mentions that these classes share a single HTTP client. To avoid port exhaustion we want a single shared HttpClient.
The problem with this, however, is that this means we need to restart the web app to cause the new query key (secret) to be reloaded from KeyVault. Consider a secret rotation flow: we need to restart/redeploy our web app after putting the new secret in KeyVault but before invalidating the old secret.
Is there a factory or another pattern the Azure Search .NET SDK recommends for periodically getting a new SearchServiceClient or ISearchIndexClient? I want a singleton most of the time for performance reasons but would like a new instance every couple of hours (for example).
Our code looks something like this right now. It uses Autofac but I think it gets the point across:
containerBuilder
.Register(c =>
{
var options = c.Resolve<IOptionsSnapshot<AzureSearchConfiguration>>();
return new SearchServiceClient(
options.Value.SearchServiceName,
new SearchCredentials(options.Value.SearchServiceApiKey));
});
containerBuilder
.Register(c =>
{
var serviceClient = c.Resolve<SearchServiceClient>();
var options = c.Resolve<IOptionsSnapshot<AzureSearchConfiguration>>();
return serviceClient.Indexes.GetClient(options.Value.SearchIndexName);
})
.SingleInstance();
I can build a time-based factory that spits out a new SearchServiceClient or ISearchIndexClient from time to time but I was hoping that something already existed.
Implementing your own factory/pool for SearchIndexClient instances is the way to go. Unfortunately this kind of functionality isn't included in the SDK, so you'll have to roll your own.

Getting 500 error from .net core WEB API for long running task

I am using .net core API for retrieving data from other services and passing the data to Angular application. I am facing 500 exception from the API for long running tasks after waiting sometime. I wanted to wait my .net core API for long time for getting the data from other services. I added the keep alive timeout in the Program class as below.
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConsole();
})
.UseStartup<Startup>()
.UseKestrel(o => { o.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(30);});
But still no changes. Also I tried with background services by implementing IHostedService as per the article here. But still facing the issue. I would appreciate someone please help me how to handle this issue.
The KeepAliveTimeout you're setting from code on the server is the timeout for handling incoming requests. Setting that will not help with outgoing requests that timeout.
If you're calling the external service using a HttpClient, have a look at setting its HttpClient.Timeout Property which
Gets or sets the timespan to wait before the request times out.
And
The default value is 100,000 milliseconds (100 seconds).
Slightly off-topic
It feels like this might not be the best structure in getting the information from the external service. An API, as far as I'm concerned, should be quick and light.
If the data of the external service isn't too volatile, you could take a look at other ways of getting the information from the external service like running a cron job/webjob/azure function and storing the result in some form of cache or storage.

ConnectorStore changes in Bot Builder SDK 3.5.5?

I’m upgrading Bot Builder SDK for our bot from 3.5.0 to 3.5.5 due to LUIS endpoint being deprecated in few weeks and it seems like latest SDK version has a way to specify ‘LuisApiVersion’.
During upgrade, I’m getting following error while modifying the behavior to use LastWriteWins policy for CachingBotDataStoreConsistencyPolicy:
Exception thrown:
'Autofac.Core.Registration.ComponentNotRegisteredException' in autofac.dll
Additional information: The requested service 'Microsoft.Bot.Builder.Dialogs.Internals.ConnectorStore' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
builder.Register(c => new CachingBotDataStore(c.Resolve<ConnectorStore>(),
CachingBotDataStoreConsistencyPolicy.LastWriteWins)
.As<IBotDataStore<BotData>>()
.AsSelf()
.InstancePerLifetimeScope();
This code has worked for 3.5.0, but I’m not sure what’s the best way to handle the Autofac error that we are getting with 3.5.5. Any pointers or idea about this?
The registration of ConnectorStore has changed as you can see here.
To solve the issue you should change the c.Resolve<ConnectorStore>() in the your code to c.ResolveKeyed<IBotDataStore<BotData>>(typeof(ConnectorStore))

Categories