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>();
Related
So, I'm attempting to include Serilog in my application at the moment, and was wondering about the following:
Is it possible to add an object so my Azure Tablestorage sink will pick it up and write it out completely to JSON in the respective "Data" column, without adding it to the plain text message?
My initial approach was this:
m_logger.Information("{message} #{context}", message, context);
And this is what my question originates from. This worked, but I'd like to keep the message itself human readable and keep metadata from the context in a separate column.
So, my second attempt now looks like this:
using (LogContext.PushProperty("context", context))
{
m_logger.Information("{message}", message);
}
Given, I added this to my logger config: .Enrich.FromLogContext()
Now this kind of works, the object does not appear in the message anymore and is actually added to the Data, but instead of completely writing it out to JSON, this is what I end up with in my Data column on the Tablestorage endpoint:
{"Timestamp":"2019-09-01T08:52:29.4835746+02:00","Level":"Information","MessageTemplate":"{message}","Properties":{"message":"Login happened","context":"MooMed.Core.DataTypes.Session.Context"}}
So, it seems like this internally merely calls .ToString().
I'd now like to know whether there is a built in way to recursively jsonify the object, or if I have to (seemingly) just override .ToString() in my Context class?
Unless you explicitly tell Serilog to destructure your context data it will simply use the ToString representation. In your initial approach you're telling Serilog to destructure by using the # symbol (although I assume you used it inside the curly braces rather than outside, i.e. {#context} rather than #{context} otherwise this shouldn't have worked).
When using LogContext you can tell Serilog to destructure the object by passing a flag when pusing a property:
using (LogContext.PushProperty("context", context, destructureObjects: true))
{
// ...
}
I assume you're aware that this will add the context to all messages logged inside the using block, including any that occur further down the call stack. As an alternative, you can also create a temporary logger enriched with this context data if you want more control over which messages the context gets added to. This is done using the ILogger.ForContext method:
var enrichedLogger = m_logger.ForContext("context", context, destructureObjects: true);
// Use `enrichedLogger` instead of `m_logger` whenever you want context data included.
enrichedLogger.Information("This message has context data attached!");
m_logger.Information("This message does not have context data attached.");
You can also use the same approach above to add context to a single message:
m_logger.ForContext("context", context, destructureObjects: true)
.Information("This message has context data attached!")
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).
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.
I'm using v2.0 of the API via the C# dll. But this problem also happens when I pass a Query String to the v2.0 API via https://rally1.rallydev.com/slm/doc/webservice/
I'm querying at the Artifact level because I need both Defects and Stories. I tried to see what kind of query string the Rally front end is using, and it passes custom fields and built-in fields to the artifact query. I am doing the same thing, but am not finding any luck getting it to work.
I need to be able to filter out the released items from my query. Furthermore, I also need to sort by the custom c_ReleaseType field as well as the built-in DragAndDropRank field. I'm guessing this is a problem because those built-in fields are not actually on the Artifact object, but why would the custom fields work? They're not on the Artifact object either. It might just be a problem I'm not able to guess at hidden in the API. If I can query these objects based on custom fields, I would expect the ability would exist to query them by built-in fields as well, even if those fields don't exist on the Ancestor object.
For the sake of the example, I am leaving out a bunch of the setup code... and only leaving in the code that causes the issues.
var request = new Request("Artifact");
request.Order = "DragAndDropRank";
//"Could not read: could not read all instances of class com.f4tech.slm.domain.Artifact"
When I comment the Order by DragAndDropRank line, it works.
var request = new Request("Artifact");
request.Query = (new Query("c_SomeCustomField", Query.Operator.Equals, "somevalue").
And(new Query("Release", Query.Operator.Equals, "null")));
//"Could not read: could not read all instances of class com.f4tech.slm.domain.Artifact"
When I take the Release part out of the query, it works.
var request = new Request("Artifact");
request.Query = (((new Query("TypeDefOid", Query.Operator.Equals, "someID").
And(new Query("c_SomeCustomField", Query.Operator.Equals, "somevalue"))).
And(new Query("DirectChildrenCount", Query.Operator.Equals, "0"))));
//"Could not read: could not read all instances of class com.f4tech.slm.domain.Artifact"
When I take the DirectChildrenCount part out of the query, it works.
Here's an example of the problem demonstrated by an API call.
https://rally1.rallydev.com/slm/webservice/v2.0/artifact?query=(c_KanbanState%20%3D%20%22Backlog%22)&order=DragAndDropRank&start=1&pagesize=20
When I remove the Order by DragAndDropRank querystring, it works.
I think most of your trouble is due to the fact that in order to use the Artifact endpoint you need to specify a types parameter so it knows which artifact sub classes to include.
Simply adding that to your example WSAPI query above causes it to return successfully:
https://rally1.rallydev.com/slm/webservice/v2.0/artifact?query=(c_KanbanState = "Backlog")&order=DragAndDropRank&start=1&pagesize=20&types=hierarchicalrequirement,defect
However I'm not tally sure if the C# API allows you to encode additional custom parameters onto the request...
Your question already contains the answer.
UserStory (HierarchicalRequirement in WS API) and Defect inherit some of their fields from Artifact, e.g. FormattedID, Name, Description, LastUpdateDate, etc. You may use those fields in the context of Artifact type.
The fields that you are trying to access on Artifact object do not exist on it. They exist on a child level, e.g. DragAndDropRank, Release, Iteration. It is not possible to use those fields in the context of Artifact type.
Parent objects don't have access to attributes specific to child object.
Artifact is an abstract type.
If you need to filter by Release, you need to make two separate requests - one for stories, the other for defects.
I'm developing an application that does some CRUD operations through a WCF service. The read method returns a complete entity, the update is performed through a legacy system, and only the changed values should be updated.
What is the best way to design the data contract for this scenario without simply sending a dictionary of key-value pairs?
The only other thing I can think of is to make your component durable - i.e. persist its state to a file or database. That way, on the update you can compare the previous state to the state being passed in. I'm not sure that's a good way to go since it will introduce more overhead than just passing in the key-value pairs.
From the outside it might look more CRUDy or whatever, but from a practical standpoint you may be better off just passing some indication as to which values changed.
In case it helps, not sure exactly what you're looking for though ...
In the update request, only act upon fields that are not null.
In addition wrap any non-nullable types in a nullable structure.
As an example ...
Update( Nullable<int> orderNumber,
Nullable<DateTime> orderDate,
Nullable<bool> isComplete )
{
if( orderNumber != null )
databaseRecord.OrderNumber = orderNumber;
if( orderDate != null )
databaseRecord.OrderDate = orderDate;
if( isComplete != null )
databaseRecord.IsComplete = isComplete;
}
the best way to do this is with property dictionary, just represent your entities as dictionary of property name and value.
save all changes in some list and pass a partial dictionary with all changed properties.
i think this is best design,
if u wanna avoid this design, send entire entity with some list of changed properties.
(to save transport u can put null on other properties)
if u don't wanna change the service contract signature u can push the names of modified properties on the header
I had two ideas of how to achieve this;
Have the client send both the original entity, and the changed entity in full, the service would then figure out what properties were changed.
Use a pattern similar to Nullable, lets call it Modified with an IsModified flag and a NewValue property of type T. Each property of the DataContract would be of this type, the service can check the IsModified flag when performing the update.
The legacy sytem we use has an api that accepts String.Empty to identify unmodified fields, a '?' character is used to indicate an update to an empty string. I really don't like this, the user of the api is forced to read the documentation, and if you actually want to store a '?' you can't. I want our webservice api to be more explicit.
You can use DataSet to keep your changes. Call your record as DataSet then assign some values to the record. DataSet.Tables[0].GetChanges() will give you the columns which were changed.
You could leave the data contract alone and update your service contract. Just represent the required fields for the method as properties within the service contract. Any consuming application using the service will have to be updated if the service contact changes, but the consuming application will know what is required to successfully update the data.
There are positives and negatives to this method, but I use it when a method I am writing doesn't require the full data contract.
--Edited for a spelling error--
Looking at your requirements and statements, i've made a few assumptions before starting to write my vision on a possible solution:
You are using the same class for retrieving (return value type of "read" operation) and updating an item (input parameter type of "update" operation) in your WCF service.
Your current problem of implementation is how to use the original class (not a dictionary) AND still be able to determine 'what has changed compared to the read' when you get the "Update" operation called on your WCF service
You are writing both the server and client. Both are written using the MS .Net framework.
If this is true, the problem lies in the Update method missing information. The information required is 'has changed' which could be inferred if a 2nd state is present to compare against or should already be present along side the state to update in the back-end.
Since you only have the 'back-end state' (without flags) when the client posts its data to the WCF service, how should we determine what did change? Obviously, we want to prevent another 'read' roundtrip to get the current server state and start comparing.
Sending the original & changed state from the client to the server is a possible but heavy solution. Next to that, the client isn't interrested in this information, the server is.
Adding this all up makes my guess is that changing the type of the 'Update' operation input parameter is the easiest way to go. Create a decorator class that adds 'dirty bit' behavior to the original entity. Use this new class as input parameter for your "Update" operation. You then will have the availability in the server to check this dirty bit next to the full state send by the client. The major change on the client side is that the object needed for the 'Update' operation is no longer the same as the one provided by the 'Read' method. To eleviate this pain, i would probably create a decorator class which added the required 'dirty bit' handling. This only requires the object instanciation to change, while maintaining the interface signature for the client (very little code changes).