.NET Azure SDK - get raw response for async pageable result - c#

I'm using the lastest Azure.ResourceManager SDK for .NET to list all resources in a subscription, this works fine:
var armClient = new ArmClient(new DefaultAzureCredential());
var subscription = await armClient.GetDefaultSubscriptionAsync();
await foreach(var resource in subscription.GetGenericResourcesAsync())
{
_logger.LogInformation("Got resource {id}", resource.Id);
}
However, I would like to get access to the raw HTTP response. This article explains how to do this for other, non-pageable responses. So I'm looking for a way to do this in my case, too. Something like GetRawResponse() - but I don't have a response object.

Please try something like the following:
var credential = new DefaultAzureCredential();
var armClient = new ArmClient(credential);
var subscription = await armClient.GetDefaultSubscriptionAsync();
var allResources = subscription.GetGenericResourcesAsync();
await foreach(Page<GenericResource> page in allResources.AsPages())
{
Response http = page.GetRawResponse();
Stream contentStream = http.ContentStream;
// Rewind the stream
contentStream.Position = 0;
using (StreamReader reader = new StreamReader(contentStream))
{
Console.WriteLine(reader.ReadToEnd());
}
}
For more details, please see this link: https://learn.microsoft.com/en-us/dotnet/azure/sdk/pagination

Related

Get Data of online API

I want to download data of this website into a json file but as I am quite new to coding with C# I cant manage to get the data. I want to get Data of https://discosweb.esoc.esa.int/api/objects the authorization via token works but I dont know how I can send a request so the server gives me a json back and I cant find a solution online. I cant give you a screenshot of the API because you have to be logged in to see it. Plz ask me for detailed information if you can help me. Thank you realy for trying.
The code I want to run is here.
class Program
{
static HttpClient client = new HttpClient();
static void Main(string[] args)
{
client.BaseAddress = new Uri("https://discosweb.esoc.esa.int");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.api+json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("my_token");
var httpRequest = (HttpWebRequest)WebRequest.Create(client.BaseAddress);
var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var streamReaderResult = streamReader.ReadToEnd();
}
Console.WriteLine("Status https://discosweb.esoc.esa.int : " + httpResponse.StatusCode);
}
}
Try this
var url = "https://discosweb.esoc.esa.int/api/objects";
var httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Method = "POST";
httpRequest.Headers["Authorization"] = "Basic XXXx";
httpRequest.ContentType = "";
httpRequest.Headers["Content-Length"] = "0";
var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Console.WriteLine(httpResponse.StatusCode);
Where XXXx is user:password in base64.
Here is a basic implementation for making that API call to get the JSON result. You will need to parse that JSON into something other than a string but I'll assume you can handle that part.
This uses System.Net.HttpClient which is the modern HTTP api provided by .NET. Its operations are async so hopefully your code is or can be written to properly await async operations.
//Someplace convenient, create a shared HttpClient to avoid
//creating and disposing for each request.
HttpClient client = new HttpClient();
string data = await GetObjects(client);
//Example implementation
public async Task<string> GetObjects(HttpClient client)
{
string url = "https://discosweb.esoc.esa.int/api/objects";
using (HttpRequestMessage msg = new HttpRequestMessage(HttpMethod.Get, url))
{
msg.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "your personal access token here");
using (var result = await client.SendAsync(msg))
{
string content = await result.Content.ReadAsStringAsync();
return content;
}
}
}
While I may be a month late, I've actually developed an SDK for this particular API.
So, if you use this SDK it's pretty simple to do what you want. You can essentially forget about handling anything HTTP related, my SDK abstracts all of that away.
For example, to fetch Sputnik's data (which has an ID of 1) you'd run.
HttpClient innerClient = new();
innerClient.BaseAddress = "https://discosweb.esoc.esa.int/api/"
innerClient.DefaultRequestHeaders.Authorization = new("bearer", yourApiKey);
DiscosClient client = new();
DiscosObject sputnik = await client.GetSingle<DiscosObject>("1");
If you're using ASP.NET, there's a set of DI extensions that can actually set it all up for you, so you can skip the first three lines.
If you do choose to use it, please let me know, as it would be nice knowing my SDK is getting some use. If you have any issues, please just reach out through the GitHub issues page and I'll try to help!

How can I create HttpRequest (in C#) with attached files?

As title says, can find plenty of resources on posting to an endpoint (from JS, for example), but how do I construct a HttpRequest (in C# .Net core) with files?
What I've Tried
var myRequest = new DefaultHttpContext().Request;
myRequest.Form.Files // GET only!
I can't seem to set the Files collection (IFormFileCollection), I can only get it.
Further Context
This is to integration test an endpoint. Except I have to hit the method, not reach it via URL (for one reason or another). The method accepts a HttpRequest and parses out the Form.Files collection. Hence I need to add some files for my assertions.
Did you already try something like this:
using (var stream = new MemoryStream(fileBytes))
{
var bla = new DefaultHttpContext().Request;
bla.Form.Files.Append(new Microsoft.AspNetCore.Http.Internal.FormFile(stream, 0, stream.Length, "file.txt", "file.txt"));
}
you can achieve this by take advantage of the following Method
public async Task<string> UploadFile(string filePath)
{
if (string.IsNullOrWhiteSpace(filePath))
{
throw new ArgumentNullException(nameof(filePath));
}
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"File [{filePath}] not found.");
}
using var form = new MultipartFormDataContent();
using var fileContent = new ByteArrayContent(await File.ReadAllBytesAsync(filePath));
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(fileContent, "file", Path.GetFileName(filePath));
form.Add(new StringContent("789"), "userId");
form.Add(new StringContent("some comments"), "comment");
form.Add(new StringContent("true"), "isPrimary");
var response = await _httpClient.PostAsync($"{_url}/api/files", form);
response.EnsureSuccessStatusCode();
var responseContent = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<FileUploadResult>(responseContent);
return result.Guid;
}
this method was snipped from a good blog: https://codeburst.io/upload-download-files-using-httpclient-in-c-f29051dea40c
It would look something like this:
var context = new DefaultHttpContext();
var formFiles = new FormFileCollection();
var formValues = new Dictionary<string, StringValues>() { };
var formCollection = new FormCollection(formValues, formFiles);
context.Features.Set<IFormFeature>(new FormFeature(formCollection));
Fill in the formFiles and formValues variables based on what you're trying to test. The key here is setting the feature to your custom FormFeature. That will cleanly plug into the default behavior of .Form and ReadFormAsync
PS: This is for unit testing assuming you're not trying to send a real file to the server side, otherwise mustafa hassan's answer works

TelegramBot 400 Bad Request: media not found

I try to send album by telegram bot.
Sometimes I get error Telegram.Bot.Exceptions.ApiRequestException: Bad Request: media not found at Telegram.Bot.TelegramBotClient.MakeRequestAsync[TResponse](IRequest 1 request, CancellationToken cancellationToken). InputMedia not is empty. Whats is wrong?
var streams = new List<Stream>();
try
{
List<IAlbumInputMedia> inputMedia = new List<IAlbumInputMedia>();
foreach (var image in images)
{
var stream = new MemoryStream(image.Data, false);
var photo = new InputMedia(stream, image.Name);
inputMedia.Add(new InputMediaPhoto(photo) {Caption = image.Name});
streams.Add(stream);
}
var response = await _bot.SendMediaGroupAsync(inputMedia, chatId, cancellationToken: token);
}
I had the same problem, which was caused by image.Name in your code. it should be only like someImage.png or someImage.jpg. You probably have "C:\SomeStuff\someImage.png" over there which is FULL Name intead of name, so Stream is good but name is wrong and the Api is confused

Microsoft Graph Content return null

I am trying to retrieve the content of my word document stored in my company SharePoint.
The code is as follows:
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
DriveItem document = await graphClient.Sites[_siteId].Drive.Items[remoteId].Request().GetAsync();
DocumentDTO dto = new DocumentDTO { Content = document.Content };
The dto has accessed the other information contained in the DriveItem such as Id and Name, but I don't understand why I can't access the content.
Looking for any possible help :-) Thanks
If you look at the example response in the docs, the content is not returned when you make call as you have done in your example.
To get the content you would need to make a different/separate request as shown here.
Therefore, your code should look like something like this to get the content.
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
Stream content = await graphClient.Sites[_siteId].Drive.Items[remoteId].Content.Request().GetAsync();
DocumentDTO dto = new DocumentDTO { Content = content };
I end up doing this to retrieve my content in Stream.
GraphServiceClient graphClient = new GraphServiceClient(authProvider);
var document = await graphClient.Sites[_siteId].Drive.Items[remoteId].Request().GetAsync();
var url = document.AdditionalData["#microsoft.graph.downloadUrl"].ToString();
HttpClient http = new HttpClient();
var response = await http.GetAsync(url);
var content = await response.Content.ReadAsStreamAsync();

Create Azure DevOps attachment

I want to create a Azure DevOps Attachment. The attachment is an Outlook message.
From the documentation seen here.
The body must be "[BINARY FILE CONTENT]". How can I read a .msg-File into C# and add it to a JsonBody Request?
Had to do something like this recently, the code looks like the stuff below.
The byte[] is the data i read directly from the filestream, like so
byte[] bytes;
using (var img = File.OpenRead("message.msg"))
{
using (var memoryStream = new MemoryStream())
{
stream.CopyTo(memoryStream);
bytes = memoryStream.ToArray();
}
}
then posting it to Azure DevOps
internal async Task<Attachement> UploadAttachment(string filename,byte[] content)
{
ByteArrayContent data = new ByteArrayContent(content);
HttpClient client = GetApiClient();
using (HttpResponseMessage response = await client.PostAsync($"https://dev.azure.com/{_org}/_apis/wit/attachments?fileName={filename}&api-version=5.1", data))
{
// Parse response body en evaluate result
var responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Attachement>(responseBody);
}
}
This seems to work quit well for us :)
don't forget to also actually add it to the workitem using: https://learn.microsoft.com/en-us/rest/api/azure/devops/wit/work%20items/update?view=azure-devops-rest-5.1#add-an-attachment

Categories