C# post JSON data to REST API - c#

I am new to REST API JSON but have been able to consume a few API with asp.net. Here is the problem I am currently facing.
I have been able to send JSON data to an API using this method.
public void PostData()
{
string sName = sysName.Text;
string sDescrip = sysDescrip.Text;
var httpclient = new HttpClient();
httpclient.BaseAddress = new Uri("http://33.248.292.99:8094/bizzdesk/sysconfig/api/");
var sys = new Bizsys(){name= sName, description= sDescrip};
httpclient.PostAsJsonAsync("system", sys);
}
it work just fine.
Now I modify the code in order to accommodate more values thus:
var httpclient = new HttpClient();
// ArrayList paramList = new ArrayList();
httpclient.BaseAddress = new Uri("http://179.683.197.115:9091/tua-slte/api/organisations/");
var org = new Organisation() { id=1, name = "inno", abbreviation = "abx", type="school", sort = 7, isShow = true, createdBy=8, createdDate = "10/04/2017", editedBy = 11, editDate="11/04/2017"};
var bas = new Basic() { id=1, username = "inno", password = "123", firstName="Innocent", lastName="Ujata", email = "ea#bizz.co", mobile = "123456", photo="10201001", loginIp="127.0.0.1", loginDate="10/04/2017", locked=false, organisation = org, createdDate = "10/04/2017", editedBy = 11, editDate="11/04/2017", admin=true};
var org2 = new Organisation2() { id=1, name = "inno", abbreviation = "abx", type="school", sort = 7, isShow = true, createdBy=17, createdDate = "10/04/2017", editedBy = 09, editDate="11/04/2017"};
var hq = new HeadQuarter() { zonId=09, organisation = org2, zonCode = "123", zonName = "Abuja", zonAddress = "123456", zonCity = "Abuja", zonPostalCode = "120076", zonEmail = "answers", zonPhoneNumber = "0908765", zonFaxNumber = "1212", zonState = "FCT", createdBy=17, createdDate = "10/04/2017", editedBy = 11, editDate="11/04/2017", version=1};
var examp = new RootObject() {basic=bas, headQuarter=hq };
var status = httpclient.PostAsJsonAsync("register", examp);
return status;
It keep returning this:
Id = 19, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
I hard coded the data to see it work first before making it dynamic.
I have tried using await async method too the result is the same.
all the questions and answers I have seen here are not similar.
What does that mean, and what am I getting wrong?

You are calling an async method, but not awaiting it's results.
Change:
var status = httpclient.PostAsJsonAsync("register", examp);
to
var status = await httpclient.PostAsJsonAsync("register", examp);

Extension method PostAsJsonAsync returns Task<HttpResponseMessage>. You grab this task and see it's details. If you want to return status code of completed request, you should await for task completion and then grab status code from response message:
private async Task<HttpStatusCode> PostSomethingAsync()
{
...
var response = await httpclient.PostAsJsonAsync("register", examp);
return response.StatusCode;
}
Or you can synchronously wait for request completion:
private HttpStatusCode PostSomething()
{
...
var response = httpclient.PostAsJsonAsync("register", examp).Result;
return response.StatusCode;
}

That's cause you are not awaiting the call like
var status = await httpclient.PostAsJsonAsync("register", examp);
Or, use ConfigureAwait()
var status = httpclient.PostAsJsonAsync("register", examp).ConfigureAwait(false);

Related

AsyncEnumerator library not processing collection

I am using the AsyncEnumerator library by #Serge Semenov, and after getting the orders, creating the ConcurrentBag and setting count to 0, nothing happens - can anyone see what's missing here? It never hits the processedOrders.ToList() line when debugging.
private async Task<List<OrderDto>> ProcessOrderEvents(DateTime cob)
{
var orders = await _client.GetOrderEvents(cob);
var processedOrders = new ConcurrentBag<OrderDto>();
var count = 0;
await orders.ParallelForEachAsync(async order =>
{
var orderDto = new FidessaOrderDto {Cob = cob};
var orderId = order.Ids.PrimaryId;
Debug.WriteLine($"Processing OrderId: {orderId} #= {++count}");
var instrumentDetails = await GetInstrumentDetails(order);
if (instrumentDetails.Results.Any())
{
//...
}
var tradeDetails = await _client.GetTrade(tradeId: fill, cob);
processedOrders.Add(orderDto);
}, maxDegreeOfParallelism:2);
return processedOrders.ToList();
}
Update: Adding Test root.
[TestMethod]
public async Task Test_20_07_2022()
{
var service = new DataService(new ApiClient());
var data = await service.ProcessData(new DateTime(2022, 07, 20), ReportDataType.Orders);
Assert.AreEqual(920, data.Count);
}
public async Task<List<OrderDto>> ProcessData(DateTime cob,
ReportDataType dataType)
{
await PopulateRouteEvents(cob);
var reportData = new List<OrderDto>();
if (dataType == ReportDataType.Orders)
reportData = await ProcessOrderEventsTpl(cob);
return reportData;
}

quickest way to findout if the ObjectID is Group Or User Or ServicePrincipal in Azure using C#

I am writing a method to get DisplayName of off ObjectID. Is there a quick way to figure out if the ObjectID is a Group Or an User Or a ServicePrincipal
Below is my weird\Rough method which is working for me. But I wanted to check if anyone has any simpler Or cooler solution.
I tried searching online for some solutions but no luck yet.
public static async Task<string> GetDisplayName(string TenantID, string ObjectID, string MSGraphToken, string ObjectType)
{
string DisplayNameURI = null;
string DisplayName = null;
var DisplayNamehttpClient = new HttpClient
{
BaseAddress = new Uri("https://graph.windows.net/")
};
if (ObjectType.Equals("Decide", StringComparison.OrdinalIgnoreCase))
{
// trying servicePrincipals
ObjectType = "servicePrincipals";
DisplayNameURI = $"{TenantID}/{ObjectType}/{ObjectID}?api-version=1.6";
var SPNhttpClient = new HttpClient
{
BaseAddress = new Uri("https://graph.windows.net/")
};
SPNhttpClient.DefaultRequestHeaders.Remove("Authorization");
SPNhttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + MSGraphToken);
HttpResponseMessage SPNResponse = await SPNhttpClient.GetAsync(DisplayNameURI).ConfigureAwait(false);
var SPNHttpsResponse = await SPNResponse.Content.ReadAsStringAsync();
dynamic SPNResult = JsonConvert.DeserializeObject<object>(SPNHttpsResponse);
DisplayName = SPNResult.displayName;
if (string.IsNullOrEmpty(DisplayName) == true)
{
// Trying for Users
ObjectType = "users";
DisplayNameURI = $"{TenantID}/{ObjectType}/{ObjectID}?api-version=1.6";
var usershttpClient = new HttpClient
{
BaseAddress = new Uri("https://graph.windows.net/")
};
usershttpClient.DefaultRequestHeaders.Remove("Authorization");
usershttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + MSGraphToken);
HttpResponseMessage usersResponse = await usershttpClient.GetAsync(DisplayNameURI).ConfigureAwait(false);
var usersHttpsResponse = await usersResponse.Content.ReadAsStringAsync();
dynamic usersResult = JsonConvert.DeserializeObject<object>(usersHttpsResponse);
DisplayName = usersResult.displayName;
if (string.IsNullOrEmpty(DisplayName) == true)
{
//Trying for Groups
ObjectType = "groups";
DisplayNameURI = $"{TenantID}/{ObjectType}/{ObjectID}?api-version=1.6";
var groupshttpClient = new HttpClient
{
BaseAddress = new Uri("https://graph.windows.net/")
};
groupshttpClient.DefaultRequestHeaders.Remove("Authorization");
groupshttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + MSGraphToken);
HttpResponseMessage groupsResponse = await groupshttpClient.GetAsync(DisplayNameURI).ConfigureAwait(false);
var groupsHttpsResponse = await groupsResponse.Content.ReadAsStringAsync();
dynamic groupsResult = JsonConvert.DeserializeObject<object>(groupsHttpsResponse);
DisplayName = groupsResult.displayName;
}
}
}
else
{
DisplayNameURI = $"{TenantID}/{ObjectType}/{ObjectID}?api-version=1.6";
DisplayNamehttpClient.DefaultRequestHeaders.Remove("Authorization");
DisplayNamehttpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + MSGraphToken);
HttpResponseMessage DisplayNameResponse = await DisplayNamehttpClient.GetAsync(DisplayNameURI).ConfigureAwait(false);
var DisplayNameHttpsResponse = await DisplayNameResponse.Content.ReadAsStringAsync();
dynamic DisplayNameResult = JsonConvert.DeserializeObject<object>(DisplayNameHttpsResponse);
DisplayName = DisplayNameResult.displayName;
}
//Console.WriteLine($"{DisplayName}");
if (string.IsNullOrEmpty(DisplayName) == true)
{
DisplayName = "Unknown";
}
return DisplayName;
}
You can directly find the AD object based on objectID using PowerShell.
Command: Get-AzureADObjectByObjectId -ObjectIds objectID1,objected2
Reference: Get-AzureADObjectByObjectId (AzureAD) | Microsoft Docs
Otherwise you can using C# for calling graph api to get the details.
Code:
GraphServiceClient graphClient = new GraphServiceClient( authProvider );
var ids = new List<String>()
{
"objectID1",
"objectID2"
};
var types = new List<String>()
{
"user"
};
await graphClient.DirectoryObjects
.GetByIds(ids,types)
.Request()
.PostAsync();
Reference: directoryObject: getByIds - Microsoft Graph v1.0 | Microsoft Docs

C# : set default payment method in stripe

I am new in stripe, how can we set default payment method in stripe.
And can we pass cardId/sourceId to charge customer along with customerId.
Code:-
private static async Task<string> ChargeCustomer(string customerId)
{
return await System.Threading.Tasks.Task.Run(() =>
{
var myCharge = new StripeChargeCreateOptions
{
Amount = 50,
Currency = "gbp",
Description = "Charge for property sign and postage",
CustomerId = customerId
};
var chargeService = new StripeChargeService();
var stripeCharge = chargeService.Create(myCharge);
return stripeCharge.Id;
});
}
And 1 more question, how to get charge-list, I am using below code but getting exception(conversion error):-
private IEnumerable<StripeCharge> GetChargeList()
{
var chargeService = new StripeChargeService();
return chargeService.List();
}
This is what I ended up doing. Not sure why Stripe Checkout didn't set the card for the subscription setup as the default. Anyway, this fires triggered from the payment_intent.succeeded web hook. Sure there is a better way, but...
var customerService = new CustomerService(Configs.STRIPE_SECRET_KEY);
var c = customerService.Get(pi.CustomerId);
if (!string.IsNullOrEmpty(c.InvoiceSettings.DefaultPaymentMethodId)) {
status = "already has default payment method, no action";
hsc = HttpStatusCode.OK;
return;
}
var paymentMethodService = new PaymentMethodService(Configs.STRIPE_SECRET_KEY);
var lopm = paymentMethodService.ListAutoPaging(options: new PaymentMethodListOptions {
CustomerId = pi.CustomerId,
Type = "card"
});
if (!lopm.Any()) {
status = "customer has no payment methods";
hsc = HttpStatusCode.BadRequest;
return;
}
var pm = lopm.FirstOrDefault();
customerService.Update(pi.CustomerId, options: new CustomerUpdateOptions {
InvoiceSettings = new CustomerInvoiceSettingsOptions {
DefaultPaymentMethodId = pm.Id
}
});
hsc = HttpStatusCode.OK;
return;
We can pass cardId/BankAccountId/TokenId/SourceId in SourceTokenOrExistingSourceId property of StripeChargeCreateOptions,
private static async Task<string> ChargeCustomer(string customerId, string cardId)
{
try
{
return await System.Threading.Tasks.Task.Run(() =>
{
var myCharge = new StripeChargeCreateOptions
{
Amount = 50,
Currency = "gbp",
Description = "Charge for property sign and postage",
CustomerId = customerId,
SourceTokenOrExistingSourceId = cardId
};
var chargeService = new StripeChargeService();
var stripeCharge = chargeService.Create(myCharge);
return stripeCharge.Id;
});
}
catch(Exception ex)
{
return "";
}
}
To set/change default payment method:-
public void ChangeDefaultPayment(string customerId, string sourceId)
{
var myCustomer = new StripeCustomerUpdateOptions();
myCustomer.DefaultSource = sourceId;
var customerService = new StripeCustomerService();
StripeCustomer stripeCustomer = customerService.Update(customerId, myCustomer);
}
Still looking for how to get charge-list.

Microsoft.Graph.AttendeeType not enumerated correctly

I am attempting to create an event through the Microsoft Graph API inviting users as attendees. The code to set the attendees is as follows:
var attendees = new List<Microsoft.Graph.Attendee>();
foreach (var e in emailAddresses)
{
var userProfile = await AzureGraph.GetOtherUserProfile(e);
if (e != currentUserEmail.First())
{
Microsoft.Graph.EmailAddress email = new Microsoft.Graph.EmailAddress();
email.Name = userProfile.DisplayName;
email.Address = e;
attendees.Add(new Microsoft.Graph.Attendee()
{
EmailAddress = email,
Type = Microsoft.Graph.AttendeeType.Optional
});
}
}
await AzureGraph.AddEvent(new Microsoft.Graph.Event
{
Subject = string.Format("Follow Up: {0}", Id),
Body = new Microsoft.Graph.ItemBody
{
Content = "content"
},
Start = start,
End = start.AddMinutes(30),
Attendees = attendees
});
However, when making the request, i get a Bad Request response. The reason for this is that the 'Type' of an attendee is a n enum of Microsoft.Graph.AttendeeType and this is not being enumerated properly. Therefore it is attempting to send through the numeric value '1' instead of the string value "Optional" causing it to fail.
I was able to confirm this using fiddler, if i manually change the numeric value to the string value then it works no problem.
Has anybody come across this or have any ideas how i can solve this?
Many Thanks for your help in advance :)
I have now managed to solve this. The solution is a bit of a hack but it works. My original call code was as follows:
public static async Task AddEvent(Event e)
{
using (var client = new HttpClient())
{
using (var req = new HttpRequestMessage(HttpMethod.Post, _calendarUrl))
{
var token = await GetToken();
req.Headers.Add("Authorization", string.Format("Bearer {0}", token));
req.Headers.TryAddWithoutValidation("Content-Type", "application/json");
var requestContent = JsonConvert.SerializeObject(new
{
Subject = e.Subject,
Body = new
{
ContentType = "HTML",
Content = e.Body.Content
},
Start = new
{
DateTime = e.Start,
TimeZone = "UTC"
},
End = new
{
DateTime = e.End,
TimeZone = "UTC"
}
});
req.Content = new StringContent(requestContent, Encoding.UTF8, "application/json");
using (var response = await client.SendAsync(req))
{
if (response.IsSuccessStatusCode)
{
return;
}
else
{
throw new HttpRequestException("Event could not be added to calendar");
}
}
}
}
}
I have now changed this to:
public static async Task AddEvent(Event e)
{
using (var client = new HttpClient())
{
using (var req = new HttpRequestMessage(HttpMethod.Post, _calendarUrl))
{
var token = await GetToken();
req.Headers.Add("Authorization", string.Format("Bearer {0}", token));
req.Headers.TryAddWithoutValidation("Content-Type", "application/json");
IList<Attendee> attendees = new List<Attendee>();
foreach(var a in e.Attendees)
{
attendees.Add(new Attendee()
{
EmailAddress = a.EmailAddress,
Type = Enum.GetName(typeof(AttendeeType), AttendeeType.Optional)
});
}
var requestContent = JsonConvert.SerializeObject(new
{
Subject = e.Subject,
Body = new
{
ContentType = "HTML",
Content = e.Body.Content
},
Start = new
{
DateTime = e.Start,
TimeZone = "UTC"
},
End = new
{
DateTime = e.End,
TimeZone = "UTC"
},
Attendees = attendees
});
req.Content = new StringContent(requestContent, Encoding.UTF8, "application/json");
using (var response = await client.SendAsync(req))
{
if (response.IsSuccessStatusCode)
{
return;
}
else
{
throw new HttpRequestException("Event could not be added to calendar");
}
}
}
}
}
As well as adding the following local class:
private class Attendee
{
public EmailAddress EmailAddress { get; set; }
public string Type { get; set; }
}
Essentially, the Graph Attendee expected:
1. an EmailAddress object containing Name (string) and Email (string).
2. a Type object of type AttendeeType which was the enum not being passed correctly.
Therefore, i created my own version of the class Attendee to contain the same EmailAddress object and Type of type string as the API expects it to be.
I then had to change the enum type to the name of the enum rather than the int value. This was done as follows:
attendees.Add(new Attendee()
{
EmailAddress = a.EmailAddress,
Type = Enum.GetName(typeof(AttendeeType), AttendeeType.Optional)
});
This gave me the value "Optional" rather than 1 which made it acceptable to the API.
I hope this helps someone in the future.
It looks like a major oversight on microsoft's part to use an enum in the code and the expect a string rather than an integer in the API and i think this needs addressing.

Task.Wait locks the flow of the controller in MVC5

We are consuming a WebAPI from an MVC site. We did a proof of concept from a console application like this, consuming AddUser Method, which reguster a new user in our DB.
static void Main()
{
M_Users user = new M_Users();
var newUser = new M_Users()
{
Password = "123",
FirstName = "Andrew",
Email = "someAndrew#someplace.com",
AdminCode = 1,
IsDisabled = false,
CountryId = 48,
CityId = 149,
DepartmentId = 3,
CreationDate = DateTime.Now,
CreatorUserId = 1
};
var star = RunAsync(newUser);
star.Wait();
//THIS LINE IS REACHED ALWAYS
Console.WriteLine(star.Result.UserID);
Console.ReadLine();
}
static async Task<M_Users> AddUserAsync(M_Users newUser)
{
M_Users user = new M_Users();
string requestUri = "api/User/AddUser";
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:44873/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
HttpResponseMessage response = await client.PostAsJsonAsync<M_Users>(requestUri, newUser);
if (response.IsSuccessStatusCode)
{
Uri newUserUrl = response.Headers.Location;
user = await response.Content.ReadAsAsync<M_Users>();
}
return user;
}
}
This AddUserAsync method is called exactly the same in both cases,console application and MVC application, and methods in the biz layer are also the same, and not depicted here for doesn´t seem relevant.
In Console it just worked. User is registered and console printed the id which the user were saved with in the BD. This is pretty much what we needed to proof. That from a sync method we can invoke an async method. Now we try the same from the controler of our site, like this.
public ActionResult Index()
{
User spUser = null;
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
var model = new LoginViewModel();
// here we invoke sharepoint context for getting user info to bild the object
M_Users new_user = new M_Users()
{
Password = "123",
FirstName = spUser.Title,
Email = spUser.LoginName.Split('|')[2].ToString(),
AdminCode = 1,
IsDisabled = false,
CountryId = 48,
CityId = 149,
DepartmentId = 3,
CreationDate = DateTime.Now,
CreatorUserId = 1
};
var returnedUser = AddUserAsync(new_user);
returnedUser.Wait(); //HERE IT STOPS RUNNING
//THIS LINE IS NEVER REACHED
ViewBag.UserId = returnedUser.Result.UserID;
return View(model);
}
What needs to be done for the execution to continue.
We also tried ContinueWith() and it runs, but the async method is not executed and nothing is recorded in the DB. More specific, the method is invoked but it seem to go over it and retunrs nothing. :(
This is pretty much what we needed to proof. That from a sync method we can invoke an async method.
That's the wrong lesson to learn. Console applications use a different threading framework than ASP.NET, and that's what's tripping you up.
I explain it in full on my blog; the gist of it is that the await captures a "context" and uses that to resume the async method. In a Console app, this "context" is the thread pool context, so the async method continues running on some arbitrary thread pool thread, and doesn't care that you've blocked a thread calling Wait. However, ASP.NET has a request context that only allows in one thread at a time, so the async method is attempting to resume within that request context but it can't because there's already a thread blocked in that context.
The best solution is to allow async to grow through the codebase:
public Task<ActionResult> Index()
{
User spUser = null;
var spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext);
var model = new LoginViewModel();
M_Users new_user = new M_Users()
{
Password = "123",
FirstName = spUser.Title,
Email = spUser.LoginName.Split('|')[2].ToString(),
AdminCode = 1,
IsDisabled = false,
CountryId = 48,
CityId = 149,
DepartmentId = 3,
CreationDate = DateTime.Now,
CreatorUserId = 1
};
var returnedUser = await AddUserAsync(new_user);
ViewBag.UserId = returnedUser.UserID;
return View(model);
}

Categories

Resources