IBotDataBag how to get all keys - c#

working with Microsoft Bot Framework I'm setting states and data for conversation and user management.
I used
var state = message.GetBotPerUserInConversationData<ConversationState>("State");
if( state == null)
{
message.SetBotPerUserInConversationData("State", new ConversationState());
}
and
var data = context.PerUserInConversationData;
ConversationState state;
var ret = data.TryGetValue("State", out state);
to get my state.
Said that I should know properties, states I created calling Count property I get more then key/value pairs I created.
How to get the full list? It seems there is no way and may be object already inside whose name is unknown has info I need making useless my custom states.
Thanks

When you call context.PerUserInConversationData, you get the object that implements IBotDataBag (typically an instance of JObjectBotData class), and there is no way to programmatically access fields inside it.
If you want to understand which fields are inserted into this DataBag originally, you can have a look at the Bot Framework Source Code, or build you own copy of the framework which allows you to access keys in the JObjectBotData.
If you want to track your the fields that you put inside the bag in your code, you can create a wrapper which tracks those fields explicitly and stores their list in the DataBag.

Related

C# Google SDK Update or Patch User

Having problem using update User with the google Admin SDK for C#.
https://developers.google.com/admin-sdk/directory/reference/rest/v1/users/update
This method supports patch semantics, meaning you only need to include the fields you wish to update. Fields that are not present in the request will be preserved, and fields set to null will be cleared.
This differs from the Patch as patch won't clear fields that are null but only update fields that have a value.
Problem is that I have to pass a full Google.Apis.Admin.Directory.directory_v1.Data.User class to the function which will contain null of even properties i do not want to clear.
example:
public User UpdateUser(Google.Apis.Admin.Directory.directory_v1.Data.User gUser)
{
UsersResource.UpdateRequest userUpdateRequest = _service.Users.Update(gUser, gUser.Id);
User updatedUser = userUpdateRequest.Execute();
return updatedUser;
}
Is there any way of modifying the Body in UpdateRequest before executing it?
Edit:
The UpdateRequest has a ModifyRequest Property that looks like this
I just have no Idea how to use it, any ideas?
public Action<HttpRequestMessage> ModifyRequest { get; set; }
As far as updating things to the concept of Null that is not something that can be done with PATCH. I recommend setting it to an empty string.
You should also not be sending the full user object if thats what you are currently doing. I am going to assume that you have done a users.list to find the user you want to update and change something in that user, say the name. Then you have simply submited the full user object to your method
UpdateUser(Google.Apis.Admin.Directory.directory_v1.Data.User gUser)
This wont work as some of the fields you have sent as part of the update/patch are not actually writeable.
What you should do instead would be to create a new user object change what ever it is you want
public User MakeUserAdmin(Google.Apis.Admin.Directory.directory_v1.Data.User gUserId)
{
var updateFields= new Google.Apis.Admin.Directory.directory_v1.Data.User();
change.IsAdmin = true;
change.Addresses = ""; // will set it to empty yes not null but the best you can do with this api.
UsersResource.UpdateRequest userUpdateRequest = _service.Users.Update(updateFields, gUserId);
User updatedUser = userUpdateRequest.Execute();
return updatedUser;
}
Notice how you just need to create a new object and update only the fields you need then send that.
Dont try to update every field, just update the ones that you know have changed. Dont include the id in the object that is not writeable either.

Passing data from my MainDialog to Middlewares

I am using the Virtual Assistant Template and using custom middelwares.
what I want is to pass custom data in the activity Properties to my middleware from my MainDialog
turnContext.Activity.Properties["dummy"] = "data";
But the activity I receive in the middleware never has the Properties property set, it is always empty.
I know that:
As each activity flows in and out of the bot, each piece of middleware can inspect or act upon the activity, both before and after the bot logic runs.
My case is needing to pass data to the middleware "after the bot logic runs" How can I do that?
Turn state is a TurnContextStateCollection which is a type that derives from Dictionary<string, object>. As such, you can use it like a dictionary. In the SDK, data is usually stored in turn state using Add because the SDK is written to only add the data once. If you try to use Add when the data is already present, it will throw an exception. If you want to ensure that data is present in the turn state and you don't know if it's already there or not, you can use Set. This is the same as using the indexer's set accessor:
turnContext.TurnState["dummy"] = "data";
You can access it from your middleware using Get or by using the indexer again:
var dummy = turnContext.TurnState["dummy"];
Note that the TurnContextStateCollection provides generic methods for convenience so that if you're only storing one object of a given type in your turn state then you don't need a key to get or set it. The key is generated automatically from the name of the type.
turnContext.TurnState.Set(new DummyData());
var dummy = turnContext.TurnState.Get<DummyData>();

Create a copy of an ObservableCollection that doesn't update

I am building a control in xamarin forms that binds to a list of objects. To get this binding to work I need to use observable collections (otherwise propertychanged methods don't fire).
I noticed a really frustrating interaction as a result of needing to use OC's as opposed to lists. Whenever the binded OC updates, the values in my controls are automatically updated, even if they are just references of the OC, Here is how i am copying the OC.
//Internal list of events
private List<EventItem> _events;
void OnEventsChanged(ObservableCollection<EventItem> eventsCollection)
{
//Error handle
List<EventItem> events = eventsCollection.ToList();
//Do something
_events = events;
}
The problem comes when the OC updates, I want to check for new/deleted AND altered objects. The issue is that when the OC updates, it is updating the internal list (_events) aswell. This means when I go to do comparisons between the old & new values, they are the same.
Honestly I don't really understand how c# handles copying references of objects around, I had a similar issue a while back with DateTime.Now being calculated as opposed to copying the value of the already initialised object.
var time = DateTime.Now;
await Task.Delay(1000);
var time2 = time; //This is 1 second later than time, not the value of time (which is what I wanted)
I have used Objective-C in the past and that has the concept of MutableCopy where you can assign a new list from an existing one, they have the same values but aren't linked.
How can I do this in C# so that my controls internal list is only updated by me and not the OC?
Thanks
That's perfectly normal. If I have enough time, I'll try to explain it to you.
In a nutshell, the observableList (or a List) is a list of reference to the objects and not a list of objects. The thing is that the objects are not copied inside a list but the list contains a reference to the different objects. That means that if you do something like ToList(), you get another list of references to the exact same objects.
Now to solve your problem. Just create a new list with new objects with something like
var newList = oldList.Select(x => new Model(x)).ToList();
And of course the Model class has a constructor that accept a Model as a parameter and copy the properties.
When you write _events = events;, you create not a new object, but a reference for the same object. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/index .
You should to clone (create a copy of object itself) as it mentioned in comment by #Matt.

Microsoft graph change tracking

I am using the Microsoft.Graph library which I got off of Nuget. I have a problem regarding change tracking using deltas. Suppose
I am getting changes to users using something like the code below:
var usersDeltaRequest = client
.Users
.Delta()
.Request(usersDeltaLink == null ? new Option[0] : new []
{
new QueryOption("$deltatoken", usersDeltaLink)
});
var users = await usersDeltaRequest.GetAsync();
foreach (var user in users)
{
//code that updates the user goes here
}
My problem is that in this case, what gets returned is a User object. However since this is a delta, not all the fields in the object get populated. Only the ones that have been changed are guaranteed to be populated.
Now were I to parse the JSON returned manually, it would be easy to see which fields have actually been included in the response, since only those will be included in the JSON.
However, the library returns a User object and leaves the fields which haven't been returned as null. In this case, it does not seem possible to disambiguate between a field which simply hasn't been returned in the delta vs a field that actually does contain a null value.
Is there something I'm missing in how the library should be used? Because as it stands, it appears as if the library does lose some critical information, because I can't rely on the returned User object to reliably update my database, because a changed field containing a null value and a field that hasn't changed both result in a null value in the returned .Net object.
This obviously also applies to other types of resources, I just chose Users for the example.
As I read the API docs at https://developer.microsoft.com/en-us/graph/docs/concepts/delta_query_users it sez:
The optional $select query parameter is included in the request to
demonstrate how query parameters are automatically included in future
requests.
I haven't tried this. Did you include the properties you want to track changes for on your original request? Or perhaps try $select=* to return everything? The API sez:
By default, only a limited set of properties are returned
(businessPhones, displayName, givenName, id, jobTitle, mail,
mobilePhone, officeLocation, preferredLanguage, surname,
userPrincipalName).

Modifying a class in a collection with undo

This is not so much a question as to how to do something, but rather how I can implement something better or think about the problem differently.
I have a winforms application that allows the user to select multiple rows in a grid. These rows represent accounts and when the user selects the accounts and hits a button, a boolean property on the objects will change to whatever the selected value is regardless of it's existing state. However, if a validation method fails, a message is sent to the user and the boolean property needs to be set back to it's original state.
public void ModifyAccounts(List<DemoAccount> accts, bool updateIsSpecial)
{
// Dictionary that will hold the account ID along with the booleans original state
Dictionary<int, bool> originalState = new Dictionary<int, bool>();
foreach(var acct in accts)
{
// Add the current state to the dictionary
originalState.Add(acct.Id, acct.IsSpecial);
acct.IsSpecial = updateIsSpecial;
}
// Send the list to another method that loops through each account and checks
// for specific validation rules. Returns a collection of tuples. The tuple
// contains the account for item1 and a bool validated flag for item2
var valAccounts = ValidateAccounts(accts);
var failedAccounts = from obj in valAccounts
where !acct.Item2
select new
{
account = obj.Item1,
isValid = obj.Item2
};
if (failedAccounts.Count() > 0)
{
// Alert the user with custom msg box method that the accounts failed
// Do Custom Method
// Reset the values of the failed accounts to their previous state.
// It is possible that some accounts passed validation and were saved,
// only the failed accounts should be reset.
foreach (var obj in failedAccounts)
{
bool originalFlagState = false;
originalFlagStates.TryGetValue(obj.account.Id, out originalFlagState);
var origAccount = accts.Where(x => x.Id == obj.account.Id).FirstOrDefault();
origAccount.IsSpecial = originalFlagState;
}
}
}
I hope this isn't too confusing. I only have ~3 years of dev experience which is not a lot. However, I feel it's enough to understand when working on something that if it feels like there is a better way then I am probably not doing it correctly or efficiently. Modifying the account flag changes the object in the accounts list. Obviously adding the object to a new list will just create a reference to that object. So I can't do something like holding 2 collections one for modification and the other for original state. I also can't do a deep copy because the account class is not marked serializable. I cannot change this because of the type of object.
Thanks to anyone who can provide some advice or insight!
I do not understand why you want to validate after changing, and not beforehand.
But if you really have to validate and use undo afterwards there is a design pattern which supports this behavior
Have a look at the command pattern. Here is a code project link that describes how to implement it
http://www.codeproject.com/Articles/8303/Using-the-Command-pattern-for-undo-functionality
In your particular case I would iterate through the command stack and undo all commands which are used on failed accounts
It could look something like this
foreach (var obj in failedAccounts)
foreach ICommand command in commandStack
If(command.element.Equals(obj))
command.undo;
command.element should contain the element you want to change with your command.
if you dont want two foreach u could use System.Linq operations

Categories

Resources