Get Azure DevOps comment details including comment id in .NET C# - c#

I am trying to get list of comments of a specific Azure DevOps workitem through C# Azure DevOps SDK.
Nuget packages I have used:
Microsoft.TeamFoundationServer.Client 16.170.0
Microsoft.VisualStudio.Services.Client 16.170.0
Here is the C# code to get WorkItem comments:
// create instance of work item tracking http client
var credentials = new VssBasicCredential(string.Empty, PAT);
using (var httpClient = new WorkItemTrackingHttpClient(new Uri(COLLECTION_URI), credentials))
{
// get all comments for this work item
var comments = await httpClient.GetCommentsAsync(workItemId);
}
The "httpClient.GetCommentsAsync" method works fine and returns object of "WorkItemComments" class. The "WorkItemComments" object contains a property named "Comments" of data type "IEnumerable of WorkItemComment". If I further go inside "WorkItemComment" class then I can see only four properties inside it.
Revision
Text
RevisedBy
RevisedDate
So, in short, I am not able to get other details of comment like comment id, created by, created date, modifed by, modified date, etc.
How can I get other details of comments ? Do I need to call any other method ?

Related

How to define your own database ID - Firebase Xamarin

I have the following database:
And I want to use the "Nome" value as an ID instead of a generated code. Instead of -MzKveR8JIXgWsrph_or I wanted it to be Teste1.
My current insert code looks like this:
MyDatabaseRecord databaserecord = new MyDatabaseRecord
{
Nome = EntryNome.Text.ToString(),
Prato1 = EntryPrt1.Text.ToString(),
Prato2 = EntryPrt2.Text.ToString(),
Sopa = EntrySopa.Text.ToString(),
Contacto = EntryContacto.Text.ToString()
};
firebaseClient.Child("Restaurantes").PostAsync(databaserecord);
What do I need to change in order to set the decided value as a Firebase ID? I've been trying to get there but couldn't yet find the right answer.
The Firebase Realtime Database API for C# follow a REST-ful pattern for its method names. This means that calling POST on a URL creates a resource under that location with an identifier determined by the system. If you want to determine your own identifier, call PUT on the entire path (including that identifier).
So:
firebaseClient.Child("Restaurantes/RestaurantOne").PutAsync(databaserecord);

How can I retrieve all users that have been assigned to a Service Principal in one call with navigation properties

How can I retrieve all users within a Service Principal with navigation properties such as Manager and properties such as Full name using Microsoft Graph API in as few as possible calls?
I'm using the Microsoft.Graph package and I've tried:
Attempt 1:
await graphClient.ServicePrincipals["objectId"].AppRoleAssignedTo.Request().GetAsync();
But this gives me only the Ids, which is 'okay' but then I would have to get all users separately, which would make for a lot of calls to the Graph API.
I could use the DirectoryObjects to get all users at once but that does not allow me to expand on the Manager property.
For example:
var users = await graphClient.DirectoryObjects.GetByIds(principals.Select(p => p.PrincipalId.ToString()), new string[1] { "User" }).Request().Expand("manager").PostAsync();
Gives me a error:
Could not find a property named 'manager' on type 'microsoft.graph.directoryObject'.
Attempt 2:
I've also tried to get the users by using a filter
await graphClient.Users.Request().Filter("appRoleAssignments/any(u:u/principalId eq objectId)").Expand(u => u.Manager).GetAsync();
But that gives me a error:
Request_UnsupportedQuery
You can write the code like this:
var user = await graphClient.Users.Request().Filter("id in ('{objectId1}', '{objectId2}', ..., '{objectIdn}')").Expand(u => u.Manager).Select("displayName").GetAsync();
Ideally, this will use just one call to return the data you need.
BUT based on the requirement "in as few as possible calls", we will have to face a problem, that is, we need to put all the object ids into the request, which may cause the request to be too long and eventually fail.
I didn't test this scene and it's just a direction which may be helpful.
I still recommend that you use loop to get the information.

C# HttpRequestMessage.GetCorrelationId method returns duplicates

My team and I have been working on this issue for a couple of days and we can't determine the root cause why GetCorrelationId() returns duplicates GUID sometimes.
Within the application that I'm working right now we use the correlation id to tie up the request path.
For example the UI sends a Save request to the API in .NET. When the API calls the save method in the query service from the controller, it pass through the result of Request.GetCorrelationId() to the method call.
The save method in the query service uses this parameter to insert a new row in the audit_logs table with the request information.
The save method then calls other save methods on nested objects that belongs to the main Object, passing the correlation_id generated in the controller.
Something like this
[ Controller ]
var correlation_id = HttpRequestMessage.GetCorrelationId();
{
ParentObject.save(correlation_id) -> {
ChildObject1.save(correlation_id),
ChildObject2.save(correlation_id),
}
}
My question is. Is this an issue of how GetCorrelationId creates the GUID object or there is something wrong with the configuration of the framework?
The framework is .NET Framework 4.6.1
We see this issue in IIS Express and IIS server
I can't share code but I'll do my best to share as much information is needed to troubleshoot this issue.
This are some examples of duplicates GUID
Thanks
OK I found a solution. I'm posting it so if someone else has the same issue can get this example.
After some more digging on Google I found this post
https://www.codeproject.com/Articles/392926/Grouping-application-traces-using-ActivityId
Sebastian is using the ActivityId generated by IIS to tied together the different commands executed during his process.
Then I found the source code of HttpRequestMessageExtensions https://github.com/aspnet/AspNetWebStack/blob/master/src/System.Web.Http/HttpRequestMessageExtensions.cs
There, you can see that the method GetCorrelationId() uses the ActivityId to assign a correlation ID to the request.
ActivityId is not completely random. It is tied to the thread started by IIS. I notice that all our request from localhost:port have the same string at the end b63f-84710c7967bb.
We wanted to tied all the commands executed to save an object or retrieve it. So all we needed was a random Guid generated per request. Following the example posted by Sebastian, I stored the current ActivityId in an aux variable, then assigned a new GUID to it, executed Request.GetCorrelationId() and finally assigned back the ID stored in the aux variable to the ActivityId.
In pseudo code =>
Guid prevActivityId = Trace.CorrelationManager.ActivityId
Trace.CorrelationManager.ActivityId = Guid.NewGuid()
...
guid correlation_id = Request.GetCorrelationId()
...
Trace.CorrelationManager.ActivityId = prevActivityId
Hope this is helpful to someone else.

Use IAmazonDynamoDB or IDynamoDBContext (both?)

I started my Visual Studio project from AWS SDK template. It uses IDynamoDBContext in the function and IAmazonDynamoDB in the tests.
Everything worked to save and received documents when I received them with an id (hash). But it stopped to work when I added a range to my table. All my test were against AWS dynamoDb. But I got it to work in 2 ways. The first way were when I downloaded the local instance of dynamoDb. The second were when I replaced IDynamoDBContext to IAmazonDynamoDB in my function (so it used the same interface in both the function and in my test class). I don't know what the correct solution is, but why use 2 interfaces in the first place? Should I keep digging in why it didn't work with different interfaces or should I only use one of them?
// IDynamoDBContext (default) - Didn't save my item (did save it in local DynamoDB)
var test = new Test
{
UserId = "Test",
Id = 1
};
await DDBContext.SaveAsync<Test>(test);
// IAmazonDynamoDB - Did save my item
var putItemRequest = new PutItemRequest
{
TableName = "TestTable",
Item = new Dictionary<string, AttributeValue>()
{
{ "UserId", new AttributeValue { S = "Test" }},
{ "Id", new AttributeValue { N = "1" }}
}
};
await DDBContext.PutItemAsync(putItemRequest);
My test:
var item = new GetItemRequest
{
TableName = "TestTable",
Key = new Dictionary<string, AttributeValue>
{
{ "UserId", new AttributeValue { S = "Test" } },
{ "Id", new AttributeValue { N = "1" } },
},
};
Assert.True((await this.DDBClient.GetItemAsync(item)).Item.Count > 0);
We probably need someone on the AWS .Net SDK team to speak to this but here is my best insight.
Amazon documentation is always fun.
The documentation does not make it overly clear but IDynamoDBContext is found in the Amazon.DynamoDbv2.DataModel namespace which is used for object persistence data access.
So I think the IAmazonDynamoDB interface is used for general API calls against the DynamoDB service. The two modes have overlapping functionality in that both can work with given items in a dynamoDb table.
The docs, of course, are really clear in that for IDynamoDbContext it says
Context interface for using the DataModel mode of DynamoDB. Used to
interact with the service, save/load objects, etc.
https://docs.aws.amazon.com/sdkfornet/v3/apidocs/Index.html
For IAmazonDynamoDB it says
Interface for accessing DynamoDB Amazon DynamoDB
IAmazonDynamoDB is from the Amazon.DynamoDbv2 namespace and IDynamoDBContext is found in the Amazon.DynamoDbv2.DataModel.
If you look at the documentation for them both though you will see by looking at the methods the actions each can performance are very different.
IAmazonDynamoDb allows you to interact and work more with DynamoDb via:
Creating tables
Deleting tables
Creating global indexes and backups
etc.
You can still work directly with items but the number of API calls
available via this interface is larger and allows working with
the overall DynamoDB service.
While IDynamoDBContext allows you work directly with items in a given DynamoDb table with methods like:
Save
Query
Scan
Load
Consistency is always key in programming so always use the same interface for areas that are meant to do the same level of work. So your code and tests should be using the same interface as they are focused on the same work scope. Hopefully based on that additional clarification you know what interface you are after. If all your code is trying to do is work with items in a DynamoDb table then IDynamoDBContext is probably what you are after.

Using a "shared" type on a WCF/MVC project with two services ("cannot convert from...")

I've two WCF services connected to my client. I want to use a User-object, retrieved from service #1, and use this as paramter for service #2. Here is my MVC-Controller TournamentController.cs code:
private readonly GCTournamentServiceClient _tournamentClient = new GCTournamentServiceClient();
public ActionResult Join(int id)
{
GCUserServiceClient userClient = new GCUserServiceClient();
// Get current user
var currentUser = userClient.GetUser(0);
if (currentUser != null)
{
// Get selected tournament
var selectedTournament = _tournamentClient.GetTournament(id);
// Check if there are available seats in the tournament
if (selectedTournament.Seats > selectedTournament.RegistredUsers.Count)
{
// Check if user exist amoung registred users
if (!selectedTournament.RegistredUsers.Contains(currentUser))
{
selectedTournament?.RegistredUsers.Add(currentUser);
}
}
}
}
The error Visual Studio prompt me with:
Argument 1: cannot convert from 'GConnect.Clients.WebClient.GCUserService.User' to 'GConnect.Clients.WebClient.GCTournamentService.User'
So the problem is currentUser, which has the type GCUserService.User. I'm unable to use this as parameter for RegistredUsers
The error itself makes perfect sense, however, I'm not quite sure how I'm suppose to convert this type (properly). Some articles states, that a "shared"-service has to be created, which holds the User-type. I just can't believe, that a solution like that, should be necessary.
I might have misunderstood some basic stuff here (working with WCF and MVC), but please enlighten me, if that's the case.
So the problem is currentUser, which has the type GCUserService.User.
I'm unable to use this as parameter for RegistredUsers
There are 2 approaches to solve this problem:
1)
Create a class library project (Visual Studio) and add the User class in that project, compile it and add its assembly's (.dll) reference to both services and the client (your MVC application). Next retrieve that user object as you are already doing it
var currentUser = userClient.GetUser(0);
GetUser will return the type of User that is defined in a separate assembly which is added as reference as suggested above. The TournamentService will also reference the same assembly and the RegistredUsers.Add(User userToadd) method will take the same User object and WCF runtime should be able to serialise/desterilise it.
2)
In your MVC client application, new up the User object that is acceptable by the TournamentService.RegistredUsers.Add method. Populate its properties from the currentUser and pass in that object as parameter to RegistredUsers.Add method.
Best Practice
Ideally, I would recommend the first approach which is more work but a better practice and that your User class is maintained centrally and code is reused.
Hope this helps!

Categories

Resources