Why are all activities showing Unknown for the User/Actor .NET Server API w/React-JS client components - getstream-io

I am working on a proof of concept with GetStream.io using the .NET server side API to add activities and the react-js client components to render feeds. For some reason every activity is coming into my feeds with Unknown in bold at the top. I assume this is supposed to be the username or something? I read a post about passing in a reference to the user instead of the string userId but the .NET API constructor signature creating a new Activity only takes in a string userId parameter. I have verified that I am passing in a valid userId. Any suggestions on what I am doing wrong here?

Stream stores the unique reference and replaces it at read time. In some complex cases, you need to be able to generate a reference to an existing object and embed that inside of an activity.
Then, can you try this way:
// Since we know their IDs we can create a reference without reading from APIs
var userRef = Users.Ref(userId);
// And then add an activity with these references
var activity = new Activity(userRef, activityAction, message)

Related

Azure Insights: tracking custom property through the chain of function executions

I have Azure Function1->Function2->Service flow of calls in my Azure app. There are multiple concurrent calls of Function1 and each could be identified by some unique input Document Id. I wonder how in c# code I can set something in Azure Insight context to that document id in the beginning of Funciton1, so that any [traces] or [exceptions] or [dependencies] logged to Azure Insights in any of the follow up calls contains the document id. I noticed all of them have customDimension nested list of properties, so maybe somehow add one more property to there. Also if Function1 runs multiple times in parallel, I do not want these document id to be mixed up.
Goal is to be able to track this document id in all kinds of logs with min amount of additional c# code, avoid passing the document id from function to other functions and other services, so looking into any type of log (wheatear it's traces or exceptions or other) I'm able to immediately identify document the execution belonged to. Is it possible?
To attach a custom property to all logs whithin an azure function is not that diffucult, one could simply use a telemetry initializer to do that:
public class TelemetryEnrichment : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
if (!(telemetry is ISupportProperties item)) return;
// Demonstrate static property
item.Properties["Environment"] = "Production";
}
}
If it is an http triggered function you can enricht the request telemetry like this:
var requestTelemetry = req.HttpContext.Features.Get<RequestTelemetry>();
requestTelemetry.Properties.Add("aProp", "aValue");
You also want to have to property logged by other functions that are called by the entry function. This is not easy doable: you will need to pass the id to the other function manually, for example by passing it using the url of that function.
However, if you have to Id attached to the logs of the entry function you can easily create a query to correlate the logs. Based on the operation id you can get the whole picture of the communication flow between the functions and services, see the docs:
That way, you do not need to include the Id as a custom property to each and every telemetry item.

Logic Apps and CosmosDB

So I'm trying to do something I expected to be simple - using Logic App to insert a json object into Cosmos DB.
I've created a CosmosDB (based on Core SQL API) and created a container called Archive with the partition key /username (which is in my json object).
Now to Logic App.
First, I YOLO'ed the simple approach.
Which gave me error: "The input content is invalid because the required properties - 'id; ' - are missing"
But my json object doesnt have an id field. Maybe use the IsUpsert parameter? I dont feel like manipulating my input document to add a field called 'id'.
Which gave me error: "One of the specified inputs is invalid" Okay - feels even worse.
I now tried to use the other logic app connector (Not V2, but the original).
which gave me error: "The partition key supplied in x-ms-partitionkey header has fewer components than defined in the the collection."
I saw that this connector(unlike the V2 one) has a Partition Key Value parameter from UI, which I added to pass the value of my username
which gave me error "The input content is invalid because the required properties - 'id; ' - are missing".
At this point I thought, let me just give the bloody machine what it wants, and so I added "id" to my json object.
and yes that actually worked.
So questions are
With Logic Apps connectors, are you only able to insert json objects into Cosmos DB without that magic field "id" in the message payload?
If the partitioning key is required. Why is it not available from the V2 connector parameter UI?
Thanks.
The v1 version of this thing doesn't have partition key because it's so old, Cosmos didn't have partitioned containers. You will want to use the v2 preview. I think that will go GA at some point here soon because it's been in preview for a while now.
And yes, With Cosmos DB you can't insert anything without it's id so you will need to generate from whatever calls your endpoint and pass it in the body of your http request.

Node typescript library environment specific configuration

I am new to node and typescript. I am working on developing a node library that reaches out to another rest API to get and post data. This library is consumed by a/any UI application to send and receive data from the API service. Now my question is, how do I maintain environment specific configuration within the library? Like for ex:
Consumer calls GET /user
user end point on the consumer side calls a method in the library to get data
But if the consumer is calling the user end point in test environment I want the library to hit the following API Url
for test http://api.test.userinformation.company.com/user
for beta http://api.beta.userinformation.company.com/user
As far as I understand the library is just a reference and is running within the consumer application. Library can for sure get the environment from the consumer, but I do not want the consumer having to specify the full URL that needs to be hit, since that would be the responsibility of the library to figure out.
Note: URL is not the only problem, I can solve that with environment switch within the library, I have some client secrets based on environments which I can neither store in the code nor checkin to source control.
Additional Information
(as per jfriend00's request in comments)
My library has a LibExecutionEngine class and one method in it, which is the entry point of the library:
export class LibExecutionEngine implements ExecutionEngine {
constructor(private environment: Environments, private trailLoader:
TrailLoader) {}
async GetUserInfo(
userId: string,
userGroupVersion: string
): Promise<UserInfo> {
return this.userLoader.loadUserInfo(userId, userGroupVersion)
}
}
export interface ExecutionEngine {
GetUserInfo(userId: string, userGroupVersion: string): Promise<UserInfo>
}
The consumer starts to use the library by creating an instance of the LibraryExecution then calling the getuserinfo for example. As you see the constructor for the class accepts an environment. Once I have the environment in the library, I need to somehow load the values for keys API Url, APIClientId and APIClientSecret from within the constructor. I know of two ways to do this:
Option 1
I could do something like this._configLoader.SetConfigVariables(environment) where configLoader.ts is a class that loads the specific configuration values from files({environment}.json), but this would mean I maintain the above mentioned URL variables and the respective clientid, clientsecret to be able to hit the URL in a json file, which I should not be checking in to source control.
Option 2
I could use dotenv npm package, and create one .env file where I define the three keys, and then the values are stored in the deployment configuration which works perfectly for an independently deployable application, but this is a library and doesn't run by itself in any environment.
Option 3
Accept a configuration object from the consumer, which means that the consumer of the library provides the URL, clientId, and clientSecret based on the environment for the library to access, but why should the responsibility of maintaining the necessary variables for library be put on the consumer?
Please suggest on how best to implement this.
So, I think I got some clarity. Lets call my Library L, and consuming app C1 and the API that the library makes a call out to get user info as A. All are internal applications in our org and have a OAuth setup to be able to communicate, our infosec team provides those clientids and secrets to individual applications, so I think my clarity here is: C1 would request their own clientid and clientsecret to hit A's URL, C1 would then pass in the three config values to the library, which the library uses to communicate with A. Same applies for some C2 in the future.
Which would mean that L somehow needs to accept a full configuration object with all required config values from its consumers C1, C2 etc.
Yes, that sounds like the proper approach. The library is just some code doing what it's told. It's the client in this case that had to fetch the clientid and clientsecret from the infosec team and maintain them and keep them safe and the client also has the URL that goes with them. So, the client passes all this into your library, ideally just once per instance and you then keep it in your instance data for the duration of that instance

How to save MS bot state data and conversations ?

I am using node js and Microsoft Bot builder sdk to write a BOT. Currently, I am saving everything in data bags (conversationData, userData etc) and using CosmosDb to store the state. I followed this article to configure CosmosDB & made changes as per nodejs.
https://azure.microsoft.com/en-in/blog/bot-conversation-history-with-azure-cosmos-db/
There are few concerns with this approach,
conversationData bag is cleared when we call endConversation() in dialog. Thats expected by sdk design but we would like to persist this data for multiple conversation flows with same user (same conversation id.) Now, json cosmosDb in db gets replaced with new keys on conversationData when user start new intent.
Ex: schedule a meeting with {name} for {day} at {place}.
we save conversationData.name , conversationData.day , and conversationData. place.
same user starts over schedule a meeting with {name2} for {day2} at {place2}.
documentDb entry gets replaced with conversationData.name1 , conversationData.day2 , and conversationData. place2
Ideally, we would like to keep everything.
Is there a better way to save chat history & conversationData, userData
databags in MS BOT ?.
All storage implementations just write getData and saveData, they internally have a key:value store where key is typically userId + conversationId, but you can make it whatever you want as long as you can reliably derive it from the arguments passed to getData and setData.
Looking at a sample in redis https://github.com/suttna/botbuilder-redis-storage - https://github.com/suttna/botbuilder-redis-storage/blob/master/src/storage.ts for an example storage implementation that's pretty easy to follow.
You would use a custom implementation like this
// Create new storage with redis client
var storage = new YourStorage()
// this is just here for the sake of initializing a `bot`
var connector = new builder.ChatConnector()
var bot = new builder.UniversalBot(connector)
// Configure bot to use YourStorage
bot.set('storage', storage)
bot.set('persistConversationData', true);
storage is just an object that implements
public saveData(context: IBotStorageContext, data: IBotStorageData, callback?: (err: Error) => void)
public getData(context: IBotStorageContext, callback: (err: Error, data: IBotStorageData) => void)
I totally just copied those signatures from the linked redis module, but they are the same in the BotBuilder source for the default storage - https://github.com/Microsoft/BotBuilder/blob/5cf71c742f27d89e9dbc4076f850122bd6edac11/Node/calling/src/storage/BotStorage.ts
The samples are in typescript. If you are unfamiliar, ignore the bit right after : which indicates the type of a thing.

Microsoft Unity - How to register connectionstring as a parameter to repository constructor when it can vary by client?

I am relatively new to IoC containers so I apologize in advance for my ignorance.
My application is a asp.net 4.0 MVC app that uses the Entity Framework with a Repository layer on top of that. It is a multi tenant application so the connection string that is used varies by the logged in client.
The connection string is determined by a 'key' that gets passed in as part of the route which indicates the client. This route data is only present on the first request of the user's session.
The route looks kind of like this: http://{host}/login/dev/
where 'dev' indicates we are using the dev database.
Currently the IoC container is registering all dependencies in the global.asax Application_Start event handler and I have the 'key' hardcoded as follows:
var cnString = CommonServices.GetDBConnection("dev");
container.RegisterType<IRequestMgmtRecipientRepository, RequestMgmtRecipientRepository>(
new InjectionConstructor(cnString));
Is there a way with Unity to dynamically register the repository based on the logged in client using the route data that is supplied initially?
Note: I am not manually resolving the repositories. They are getting constructed by the container when the controllers get instantiated.
I am stumped.
Thanks!
Quick assumption, you can use the host to identify your tenant.
the following article has a slightly different approach http://www.agileatwork.com/bolt-on-multi-tenancy-in-asp-net-mvc-with-unity-and-nhibernate-part-ii-commingled-data/, its using NH, but it is usable.
based on the above this hacked code may work (not tried/complied the following, not much of a unity user, more of a windsor person :) )
Container.RegisterType<IRequestMgmtRecipientRepository, RequestMgmtRecipientRepository>(new InjectionFactory(c =>
{
//the following you can get via a static class
//HttpContext.Current.Request.Url.Host, if i remember correctly
var context = c.Resolve<HttpContextBase>();
var host = context.Request.Headers["Host"] ?? context.Request.Url.Host;
var connStr = CommonServices.GetDBConnection("dev_" + host); //assumed
return new RequestMgmtRecipientRepository(connStr);
}));
Scenario 2 (i do not think this was the case)
if the client identifies the Tenant (not the host, ie http: //host1), this suggests you would already need access to a database to access the client information? in this case the database which holds client information, will also need to have enough information to identify the tenant.
the issue with senario 2 will arise around anon uses, which tenant is being accessed.
assuming senario 2, then the InjectionFactory should still work.
hope this helps

Resources