Microsoft Bot - MemoryStorage - Error - Etag conflict - botframework

I am try to save data to the MemoryStorage in Microsoft Bot Frame Work (in .NET environment).
I am using this method for do it:
public static class StateManager
{
private static MemoryStorage _myStorage;
static StateManager()
{
_myStorage = new MemoryStorage();
}
public async static void Save(UserDetails userDetails)
{
var changes = new Dictionary<string, object>();
{
changes.Add("ud", userDetails);
}
await _myStorage.WriteAsync(changes, new CancellationToken());
}
}
until now it's always work fine. but suddenly i am getting this error:
System.Exception: Etag conflict. Original: 4 Current: 5
any idea how to solve this error? thanks!
edit - with solve
I got that the problem was that i push data to the memory twice in a row (without get the data between the tow pushes). it's mean that after i push data one time, i have to get the data from the storage before i push the data again.
My question now it's why? i cannot save data twice without get the data between the tow pushes?

Without more code, I wasn't able to replicate your issue. However, it sounds like you have a concurrency problem.
Your Save() method returns a void. You should instead use:
public async static Task Save(UserDetails userDetails)
Then, when saving, call with:
await StateManager.Save(userDetails).
However, you can save yourself the trouble of these kinds of things and use BotBuilder's built-in state storage. References:
Save User and Conversation Data
Core Bot Sample - This is an example of good user profile storage

Related

CMS Open Payments Data Limitation

I've finally got around to getting the code needed to import web API into my SQL environment. However, when I ran the SSIS Script Component package (Script Language: Visual Studio C# 2017) I was only able to retrieve 1000 records out of of millions. A consultant mentioned that I may have to incorporate the App Token into my code in order to access additional records.
Would someone be able to confirm that this true? And if so, how should it be coded?
Here is the code prior to my "ForEach" loop code:
public override void CreateNewOutputRows()
{
//Set Webservice URL
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
string wUrl = "https://openpaymentsdata.cms.gov/resource/bqf5-h6wd.json";
string appt = "MyAppToken";
try
{
//Call getWebServiceResult to return our Article attributes
List<Payment> outPutResponse = GetWebServiceResult(wUrl);
If there's an alternative method to using the app token (like in the HTTP Connection for example) please let me know.
Figured it out...
https://openpaymentsdata.cms.gov/resource/bqf5-h6wd.json?$limit=10000&$$app_token="MyAppToken"

A interview bot using azurebot service with cosmos db for questions

I want to create an interview bot using azure bot service and want to use cosmos db for interview questions can it possible?Need help and suggestions for this.
It is unclear what is your architecture to actually get the bot working and if there is any limitation, but I assume you are using C# as your language and hosting the Bot in a C# Web application.
You can use this article as base Bot conversation history with Azure Cosmos DB.
It not only shows how to store UserData, but also how to store the State in Cosmos DB (this actually is better because you get the performance benefits of Cosmos DB and you also go over the 32Kb limit that the Bot Framework State has).
Following that article, you will be storing in Cosmos DB:
User Data Store: To store data specific to a user.
Conversation Store: To store data specific to a conversation.
Private Conversation Store: To store data specific to a user in a conversation
If you want to store the chat lines, it's not done by default by the Bot Framework. You have to create a class that implements IActivityLogger and let the user know that you are storing the chat.
public class CosmosDBActivityLogger : IActivityLogger
{
private readonly DocumentClient _client;
private readonly string _collectionUri;
public ServiceBusActivityLogger(DocumentClient client, string databaseName, string collectionName)
{
this._client = DocumentClient;
// This is the collection where you want to store the chat
this._collectionUri = UriFactory.CreateDocumentCollectionUri(databaseName, collectionName);
}
public async Task LogAsync(IActivity activity)
{
var message = activity.AsMessageActivity();
// At this point you might want to handle your own Activity schema or leave the default
// Not handling errors for simplicity's sake, but you should
this._client.CreateDocumentAsync(this._collectionUri, message);
}
}
Then you have to add the logger wherever you are declaring your Bot Container, for example, in Global.asax:
protected void Application_Start()
{
var builder = new ContainerBuilder();
builder.RegisterType<CosmosDBActivityLogger>().AsImplementedInterfaces().InstancePerDependency();
builder.Update(Conversation.Container);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
More info on how to register the middleware here.

Microsoft Bot Framework: Exception: The data is changed

I have a bot with the following conversation scenario:
Send text to LUIS
LUIS intent calls context.Call(...) to launch a Dialog
This dialog terminates, save some info in the userData:
private static async Task storeBotData(IDialogContext context, BotData userData)
{
Activity activity = (Activity)context.Activity;
StateClient sc = activity.GetStateClient();
await sc.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData);
}
And after it call another dialog, again with context.Call(...).
Then the last dialog runs and terminates.
My problem is that when updating the user data at the end of the first dialog (step 3), I have the following exception in the Bot Framework Channel Emulator:
`Exception: The data is changed [File of type 'text/plain']`...
What happens here ? I think that when a dialog terminates, it call setUserData by itself, but I don't understand why I can't update userData anywhere in the code...
I have tried to catch the exception, but nothing is catched.. But I know that the userData is updated, because when I try to retrieve it back, it is updated...
Any help is welcome :)
Thanks
Botframework restores/saves state of conversation after each act of activity, so under the covers typical flow looks like the following:
[23:15:40] <- GET 200 getUserData
[23:15:47] <- GET 200 getConversationData
[23:15:47] <- GET 200 getPrivateConversationData
...
[23:16:42] <- POST 200 setConversationData
[23:16:42] <- POST 200 setUserData
[23:16:42] <- POST 200 setPrivateConversationData
As it is mentioned here : These botData objects will fail to be stored if another instance of your bot has changed the object already. So in your case the exception occurs at the termination of dialog, when framework calls setUserData by himself and figures out that the BotData has been changed already (by your explicit call of BotState.SetUserDataAsync). I suppose that's why you were not able to catch the exception.
Solution:
I used the following code and it fixed the issue:
private static void storeBotData(IDialogContext context, BotData userData)
{
var data = context.UserData;
data.SetValue("field_name", false);
}
The reason it works is that we modify the object of UserData but allow botFramework to "commit" it himself, so there is no conflict
I agree with #Artem (this solved my issue too, thanks!). I would just add the following guideline.
Use
var data = context.UserData;
data.SetValue("field_name", false);
whenever you have a IDialogContext object available, so you let the Bot Framework commit changes.
Use instead
StateClient sc = activity.GetStateClient();
await sc.BotState.SetUserDataAsync(activity.ChannelId, activity.From.Id, userData);
when you don't have an IDialogContext object, e.g. in the MessageController class.

Get "time of upload started"

I'm developing a WebAPI service in which you can upload a file. The Action looks something like this:
[HttpPost]
public async Task<IHttpActionResult> PostAsync(byte[] content)
{
var now = DateTime.UtcNow;
}
The client which are using the WebAPI also provides a timestamp as header which is used together with some HMAC-stuff to authenticate. One part of the auth check is to validate the timestamp. We parse the timestamp and checks if it is +/- 5 minutes from now. If not then the auth fails.
It works great for all our API calls except this upload API (in some cases). The problem is that sometimes a user uploads a large file over a slow connection and therefore it takes more than 5 minutes to upload the file and the point in time where we check is AFTER the whole file has been uploaded.
Therefore:
Can we somehow do the HMAC check BEFORE the whole file is uploaded? (the file itself (HTTP Content) is not used in the HMAC check). Today we are using an ActionFilter.
Can I get the "time of request" (first byte arrived or whatever) in my Action code?
Thanks!
So, after some investigation I came up with a much better solution:
Use a HTTP Module to do the actual HMAC authentication.
After reading this blog post (http://blogs.msdn.com/b/tmarq/archive/2007/08/30/iis-7-0-asp-net-pipelines-modules-handlers-and-preconditions.aspx) I got a much better understanding of how IIS Works.
I decided to use a HTTP Module which is invoked before the MVC Action.
The code ended up like this:
public class HmacModule : IHttpModule
{
public void Init(HttpApplication context)
{
EventHandlerTaskAsyncHelper taskAsyncHelper = new EventHandlerTaskAsyncHelper(Authenticate);
context.AddOnBeginRequestAsync(taskAsyncHelper.BeginEventHandler, taskAsyncHelper.EndEventHandler);
}
private async Task Authenticate(object sender, EventArgs e)
{
var context = ((HttpApplication)sender).Context;
var request = context.Request;
var authResponse = await CheckAuthentication(request);
if (!authResponse.HasAccess)
{
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Response.StatusDescription = authResponse.ErrorMessage;
if (authResponse.Details != null)
context.Response.Write(authResponse.Details);
context.Response.End();
}
}
}
I hope this helps others in the same situation...

how to get jsonobject form volley onResponse library

I'm an android beginner and I want to make a login using volley library, but i don't
know how i can obtain the JSONObject response from my server and use it to check
login parameters and launch a specific activity if the user exist.
//assuming you are implementing this part from an activity.
//otherwise, replace “this” with relevant context
RequestQueue myQueue = queue = Volley.newRequestQueue(this);
//your server address
String url = "http://my-json-feed";
//Create your JSON object request
JsonObjectRequest jsObjRequest = new JsonObjectRequest
(Request.Method.GET, url, null, new Response.Listener() {
#Override
public void onResponse(JSONObject response) {
//process the server response here.
//use the “response” object for checking the login parameters, etc.
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//Handle errors such as network failures,etc here
}
});
//add the request object to the Volley queue
myQueue.add(jsObjRequest);
The "onResponse()" is the callback function which will give you the json object returned by the server. Inside that function, use that response to do whatever you want (for your case, to check login parameters, etc.)
For details, look here: Request JSON
Another note:
If you are to use the VolleyQueue only in one or two activities, it's okay to create separate volley queues for those couple of activities. But, if you have lots of activities and all of them needs to use Volley, then it would be a very bad choice to create volley queues for each activity. It can cause you OutOfMemory exception in the worst case. You can consider creating a singleton VolleyQueue which will be used by the whole application (Creating an ApplicationController class and including the Volley singleton queue in it can be one way to do that).

Resources