I'm calling a Microsoft API to create a printer however I need a way to get the response header where the information about the post is.
I'm following this guide https://learn.microsoft.com/en-us/graph/api/printer-create?view=graph-rest-beta&tabs=csharp but not sure how to extract the response from the call as I can not assign a variable to the call.
await graphClient.Print.Printers
.Create(displayName,manufacturer,model,certificateSigningRequest,physicalDeviceId,hasPhysicalDevice,connectorId)
.Request()
.PostAsync();
Operation-Location
You can send HTTP request with the .Net Microsoft Graph client library and read response headers.
Something like this:
var requestUrl = graphClient.Print.Printers.Request().RequestUrl;
var content = "json_content";
var hrm = new HttpRequestMessage(HttpMethod.Post, requestUrl);
hrm.Content = new StringContent(content, System.Text.Encoding.UTF8, "aplication/json");
// Authenticate (add access token)
await client.AuthenticationProvider.AuthenticateRequestAsync(hrm);
// Send the request and get the response.
var response = await client.HttpProvider.SendAsync(hrm);
if (!response.IsSuccessStatusCode)
{
throw new ServiceException(
new Error
{
Code = response.StatusCode.ToString(),
Message = await response.Content.ReadAsStringAsync()
});
}
else
{
// read header values
var headerValues = response.Headers.GetValues("Operation-Location");
}
Example of the request body:
{
"displayName": "Test Printer",
"manufacturer": "Test Printer Manufacturer",
"model": "Test Printer Model",
"physicalDeviceId": null,
"hasPhysicalDevice": false,
"certificateSigningRequest": {
"content": "{content}",
"transportKey": "{sampleTransportKey}"
},
"connectorId": null
}
Documentation
Related
I've got a minimal API service with a MapPost:
app.MapPost("/sendmessage", (RabbitMessage rm) => server.SendMessage(rm.exchange,
rm.routingkey, rm.message));
app.Run();
record RabbitMessage(string exchange, string routingkey, string message);
It works fine when sending a JSON with Postman:
{
"message": "msg",
"routingkey": "freestorage",
"exchange": "system"
}
But from a C# client:
var kv = new Dictionary<string, string> {
{ "exchange", "system" },
{ "routingkey", routingkey },
{ "message", message }
};
var content = new FormUrlEncodedContent(kv);
string contentType = "application/json";
if (Client.DefaultRequestHeaders.Accept.FirstOrDefault(hdr => hdr.MediaType == contentType) == default)
Client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(contentType));
var response = await Client.PostAsync("sendmessage", content);
The response is UnsupportedMediaType. What is the proper way to send these values to minimal API? Or do I need to setup the API itself differently?
I don't think using FormUrlEncodedContent is the correct way as it is used for application/x-www-form-urlencoded MIME type.
Instead, you should pass the request body with StringContent and serialize the kv as content.
using System.Text;
using Newtonsoft.Json;
var stringContent = new StringContent(JsonConvert.SerializeObject(kv),
Encoding.UTF8,
"application/json");
var response = await Client.PostAsync("sendmessage", stringContent);
I'm Trying to get the access token form OneLogin using the Authorization Code with PKCE. I'm able to go through step1 for PKCe and getting the authorization code back from OneLogin. But when i try to get the token using the authorization code sent by one login i keep getting 400 bad request error. I'm not sure what is wrong. I followed the info provided by oneLogin website to all required parameters in the request for Step 2. below the code i'm using. I will appreciate if some one can help on this.
public async Task GetAccessToken(string redirecturl, string authCode)
{
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
var client = new HttpClient(clientHandler);
var body = JsonConvert.SerializeObject(new
{
grant_type = "authorization_code",
code = authCode, ---The code returned from OneLogin in step 1
client_id=XXXXXXXXXXXXXXXXXX386d707215718",
redirect_uri=redirecturl,--The redirect URL registered in onelogin account
code_verifier=GetCacheEntry(CodeKey)-- the code verifier used in step one
});
var req = new HttpRequestMessage
{
Method = HttpMethod.Post,
RequestUri = new Uri("https://MySubdomain.onelogin.com/oidc/2/token"),
Content = new StringContent(body)
};
req.Content.Headers.ContentType= new MediaTypeHeaderValue(#"application/x-www-form-urlencoded");
var response = await client.SendAsync(req);
if (response.StatusCode == HttpStatusCode.OK)
{
var responseBody =await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<OAuthTokenResponse>(responseBody);
memoryCache.Remove(CodeKey);
return Ok(json);
}
return BadRequest(response);
}
Looks like you're sending the body as a json content, although you've correctly specified the Content Type as x-www-form-urlencoded.
Here's how I create the body and send the request
var data = new Dictionary<string, string>(){
{ "code", code },
{ "code_verifier", AuthCodeParticipantDetail.CodeVerifier},
{ "grant_type", "authorization_code" },
{ "redirect_uri", AuthCodeParticipantDetail.CallBackUrl},
{"client_id", AuthCodeParticipantDetail.ClientId}
};
_httpClient.DefaultRequestHeaders.Accept.Clear();
_httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
HttpResponseMessage response = await _httpClient.PostAsync(url, new FormUrlEncodedContent(data));
var tokens = await response.Content.ReadFromJsonAsync<Tokens>();
There are 3 steps to upload a feed via Amazon SP API, the first one is to get feed encryption info via createFeedDocument API. But I am getting Bad Request as response with following content:
{
"errors": [
{
"code": "InvalidInput",
"message": "Invalid Input",
"details": ""
}
]
}
C# code
private async Task<IRestResponse> CreateFeedDocument()
{
IRestRequest restRequest = new RestRequest("feeds/2020-09-04/documents", Method.POST);
restRequest.AddParameter("contentType", "application/xml; charset=UTF-8", ParameterType.RequestBody);
restRequest.AddQueryParameter("MarketplaceIds", "A21TJRUUN4KGV");
restClient = new RestClient(live_url_base);
restRequest = await signRequest(restRequest, restClient);
return restClient.Execute(restRequest);
}
private async Task<IRestRequest> signRequest(IRestRequest restRequest, RestClient restClient)
{
var roleAcccess = await GetAssumeRoleTokenDetail();
restRequest.AddHeader("x-amz-access-token", accessToken);
AWSAuthenticationCredentials AWSCredentials = new AWSAuthenticationCredentials();
AWSCredentials.AccessKeyId = roleAcccess.Credentials.AccessKeyId;
AWSCredentials.SecretKey = roleAcccess.Credentials.SecretAccessKey;
AWSCredentials.Region = region;
restRequest.AddHeader("X-Amz-Security-Token", roleAcccess.Credentials.SessionToken);
return new AWSSigV4Signer(AWSCredentials).Sign(restRequest, restClient.BaseUrl.Host);
}
I doubt that I am not using restRequest.AddParameter properly, but I am not sure.
I have been following below links:
https://github.com/amzn/selling-partner-api-docs/blob/main/references/feeds-api/feeds_2020-09-04.md#createfeeddocument
https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/use-case-guides/feeds-api-use-case-guide/feeds-api-use-case-guide-2020-09-04.md#step-1-create-a-feed-document
How to Encrypt and upload data using selling-partner-api in Amzon using .net
Update
I also tried replacing below line
restRequest.AddParameter("contentType", "application/xml; charset=UTF-8", ParameterType.RequestBody);
with
restRequest.AddJsonBody(new { contentType = "text/xml; charset=UTF-8" });
but then I was getting InvalidSignature error as below:
{
"errors": [
{
"message": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
The Canonical String for this request should have been
'POST
/feeds/2020-09-04/documents
host:sellingpartnerapi-eu.amazon.com
x-amz-access-token:Atza|IwEBIA5KgrCsBbSXHmrXFS_FIgBTInh_xPAydLfi5q2P9xaFQf7p8Zl4NjqhHHxqRzUku__Q7GN1p2WQGRzuAoAa8oMkPLx57NJ05SqxEVXXG-fet3_XgKj8uBCU30HaGPsKltf4g2MD8Pqqt2OUrOXtkv4dAAjjCIxC-bFwVqOhvHktAur--NBv-bJaPZ608Av1GEu96GsNEV9eb0saVBwLaZD7NW3oOjzlCc8GPV9hdqHV5TUXY77QZgBLD1y94Vs1fSo54ShpyoMMOZebzbSr1K5gtf3wJZ.........................{ I hid it }...........................................
x-amz-date:20210524T175148Z
x-amz-security-token:FwoGZXIvYXdzEGsaDNUytY0xuP5/u61APiK2ARMZgv4IT+y2HLzdg5FjZOv6aL2bJ3baJPxBtCY2/7ASntTXfAF5s39P3/qspLLQfmqHPZiMGjweCE3Yf3aW5Q1mt+FLT2s2VUwuOawOQwDll51T2HB3wqyaDOSEpsWeR2Iym4TJXE2hbo7q5CQQBXissOo1Oruk5gcAp7uQHpnyuhCRCkfv/ErEpzdDA0JqfhMxdzmViVgsL1Kzalnbcy9lp+ACI4TL70iOl6j6xkyhFexe/aLXKLLPr4UGMi3Ver2CL6Q4kz.........................{ I hid it }...........................................
host;x-amz-access-token;x-amz-date;x-amz-security-token
4d719849acd655844ab5129f5e54a0ed16954c9580c7a9a737504faf42b309e2'
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20210524T175148Z
20210524/eu-west-1/execute-api/aws4_request
a20e7ffe252dbf98d6a4b9213511ac1918f8bbad75ccbfd7ec46f5c9c1457b08'
",
"code": "InvalidSignature"
}
]
}
Note: I have removed some trailing chars of tokens and placed ......{ I hid it }..........
try this one
restRequest.AddJsonBody("{\"contentType\":\"text/tab-separated-values; charset=UTF-8\"}");
RestClient restClient = new RestClient("https://sandbox.sellingpartnerapi-eu.amazon.com/");
IRestRequest restRequest = new RestRequest("/feeds/2021-06-30/documents", Method.POST);
restRequest.AddJsonBody("{\"contentType\":\"text/tab-separated-values; charset=UTF-8\"}");
I do that in my open source library and its work without problem
https://github.com/abuzuhri/Amazon-SP-API-CSharp
Here sample to create and submit feed
ConstructFeedService createDocument = new ConstructFeedService("A3J37AJU4O9RHK", "1.02");
var list = new List<PriceMessage>();
list.Add(new PriceMessage()
{
SKU = "8201031206122...",
StandardPrice = new StandardPrice()
{
currency = BaseCurrencyCode.AED.ToString(),
Value = (201.0522M).ToString("0.00")
}
});
createDocument.AddPriceMessage(list);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_PRODUCT_PRICING_DATA);
Thread.Sleep(1000*30);
var feedOutput=amazonConnection.Feed.GetFeed(feedID);
var outPut=amazonConnection.Feed.GetFeedDocument(feedOutput.ResultFeedDocumentId);
var reportOutpit = outPut.Url;
private async Task UploadFile(byte[] bytes, string url)
{
var contentType = "text/plain; charset=utf-8"; // this should be the same as what was used in Step #1 (in the CreateFeedDocument API request)
RestClient restClient = new RestClient(url);
IRestRequest restRequest = new RestRequest(Method.PUT);
restRequest.AddParameter(contentType, bytes, ParameterType.RequestBody);
var response = await restClient.ExecuteAsync(restRequest);
if (!response.IsSuccessful)
{
// your error logic
}
// success. Move to Step #3
}
IllegalLocationConstraintExceptionThe unspecified location constraint is incompatible for the region specific endpoint this request was sent to.5B8EGG143CSG45XCi7DqESeN8Q/1QfotMvQIiijcEj/76sr2T+gNh9Ubhq5aQZ7SbZMXCIS/8Mgw6iDod2mCwX/LX6Q=
I have created an Azure logic app that exposes a REST endpoint.
The following JSON body works fine when I call it through postman.
{
"to": "ggtest#yahoo.com",
"subject": "Hello there",
"message": "Hello there!!!!!"
}
I'm able to see the incoming request formed nicely
{
"headers": {
"Cache-Control": "no-cache",
"Connection": "keep-alive",
"Accept": "*/*",
"Accept-Encoding": "gzip,deflate",
"Host": "maskedout.northcentralus.logic.azure.com:443",
"User-Agent": "PostmanRuntime/6.4.1",
"Content-Length": "99",
"Content-Type": "application/json"
},
"body": {
"to": "ggtest#yahoo.com",
"subject": "Hello there",
"message": "Hello there!!!!!"
}
}
However, when I try to make the same call using C# PostAsJsonAsync with this code:
var email = new Email
{
to = "gg#live.com.sg",
subject = "from webapp",
message = "hello world"
};
var client = new HttpClient();
var uri = "maskedout";
var response = await client.PostAsJsonAsync<Email>(uri, email);
I'm able to call my REST endpoint successfully, but it does not contain the body
This is the incoming request I see:
{
"headers": {
"Connection": "Keep-Alive",
"Transfer-Encoding": "chunked",
"Host": "maskedout.northcentralus.logic.azure.com",
"x-ms-request-root-id": "9e5513c2-43961642a3688718",
"x-ms-request-id": "|9e5513c2-43961642a3688718.1.",
"Request-Id": "|9e5513c2-43961642a3688718.1.1.",
"Content-Type": "application/json; charset=utf-8",
"Content-Length": "0"
}
}
What am I missing here? What's different in my C# code compared to postman?
I've just run into this problem too. The issue appears to be the Content-Length header. In Postman it is the length of the content but using HttpClient the length is 0 so I am guessing the endpoint is ignoring the body as it is being told it is empty.
I created my own extension to get around this:
public static async Task<HttpResponseMessage> PostJsonAsync<T>(
this HttpClient client,
string requestUri,
T value)
{
var data = JsonConvert.SerializeObject(value);
var content = new StringContent(data,
Encoding.UTF8,
MimeTypes.Json);
Debug.WriteLine(client.BaseAddress + requestUri);
return await client.PostAsync(requestUri,
content)
.WithRequestTimeout()
.ConfigureAwait(false);
}
I just had the same problem. It seems that the content-length header is set to 0 when using the default PostAsJsonAsync extension method, which causes the server to ignore the request body.
My solution was to install the System.Net.Http.Json nuget package that uses the new System.Text.Json serializer.
When you add using System.Net.Http.Json;, you should be able to use the new extension method PostAsJsonAsync that works (sets the content-length header) properly.
namespace System.Net.Http.Json
{
public static class HttpClientJsonExtensions
{
public static Task<HttpResponseMessage> PostAsJsonAsync<TValue>(this HttpClient client, string? requestUri, TValue value, CancellationToken cancellationToken)
{
return client.PostAsJsonAsync(requestUri, value, null, cancellationToken);
}
}
}
the TransferEncodingChunked header property should be false by default.
However, try this:
var email = new Email
{
to = "gg#live.com.sg",
subject = "from webapp",
message = "hello world"
};
var client = new HttpClient();
var uri = "maskedout";
client.DefaultRequestHeaders.TransferEncodingChunked = false;
var response = await client.PostAsJsonAsync<Email>(uri, email);
I am trying to update a OneNote page using the PATCH request through the Microsoft Graph API. I keep getting Error 19999 which according to this https://msdn.microsoft.com/en-us/office/office365/howto/onenote-error-codes means "Unknown Error"
var pageId = settings.DefaultPage;
string requestUrl = $"https://graph.microsoft.com/v1.0/me/onenote/pages/{pageId}/content";
string body = #"{
{
'target':'body',
'action':'append',
'position':'after',
'content':'<div> added new </div>'}}";
var content = new StringContent(body, Encoding.UTF8, "application/json");
HttpRequestMessage req = new HttpRequestMessage()
{
Method = new HttpMethod("PATCH"),
Content = content,
RequestUri = new Uri(requestUrl)
};
HttpClient client = new HttpClient()
{
BaseAddress = new Uri(requestUrl),
};
client.DefaultRequestHeaders.TryAddWithoutValidation("authorization", "Bearer " + settings.MsaAccessCode);
HttpResponseMessage response = await client.SendAsync(req);
I can verify that the Authorization Code is valid (as I am able to do other actions like creating a new page) and has the necessary scopes to update a page. Can anyone help me with identifying the problem here?
Your JSON is invalid. Here is what I believe you want.
[{
"target": "body",
"action": "append",
"position": "after",
"content": "<div> added new </div>"
}]