Query Comcast/Xfinity monthly data quota via .NET/C# - c#

The following code reports "error: unauthenticated".
How can I use .NET to authenticate against this Comcast/Xfinity API to query/fetch used and available data of an account with a monthly quota?
static async Task Main() {
using (var httpClient = new HttpClient()) {
using (var request = new HttpRequestMessage(new HttpMethod("GET"), "https://customer.xfinity.com/apis/services/internet/usage")) {
var response = await httpClient.SendAsync(request);
var responseStream = await response.Content.ReadAsStreamAsync();
var streamReader = new StreamReader(responseStream, Encoding.UTF8);
var responseContent = streamReader.ReadToEnd(); // {"error":"unauthenticated"}
}
}
}

Figured it out. This code runs in either .NET Framework (tested 4.7.1) or .NET Core (tested 2.2). It authenticates with otherwise-defined Username and Password values and prints the data used and the data remaining in the month.
static async Task Main() {
using (var httpClient = new HttpClient()) {
double totalUsage;
double allowableUsage;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // this line can be removed in .NET Core
using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://login.xfinity.com/login")) {
var data = new Dictionary<string, string> {
{"user", Username}
, {"passwd", Password}
, {"s", "oauth"}
, {"continue", "https://oauth.xfinity.com/oauth/authorize?client_id=my-account-web&prompt=login&redirect_uri=https%3A%2F%2Fcustomer.xfinity.com%2Foauth%2Fcallback&response_type=code"}
};
var content = string.Join("&", data.Select(x => $"{x.Key}={WebUtility.UrlEncode(x.Value)}"));
request.Content = new StringContent(content, Encoding.UTF8, "application/x-www-form-urlencoded");
await httpClient.SendAsync(request);
}
using (var request = new HttpRequestMessage(new HttpMethod("GET"), "https://customer.xfinity.com/apis/services/internet/usage")) {
var response = await httpClient.SendAsync(request);
var responseStream = await response.Content.ReadAsStreamAsync();
var streamReader = new StreamReader(responseStream);
var responseContent = streamReader.ReadToEnd();
var parsedResponse = JObject.Parse(responseContent);
var usageMonths = parsedResponse["usageMonths"];
var currentMonthUsage = usageMonths.Last;
totalUsage = currentMonthUsage.Value<double?>("totalUsage") ?? 0;
allowableUsage = currentMonthUsage.Value<double?>("allowableUsage") ?? 0;
}
Console.WriteLine($"Allowable: {allowableUsage}");
Console.WriteLine($"Total : {totalUsage}");
Console.ReadKey();
}
}
Depends on nuget.org/packages/Newtonsoft.Json/12.0.1

Related

How to handle httpClient respond right?

Because of Net 6.0 usage I'm frustrated how to convert old HttpWebResponse to httpClient
Could someone help me to handle it right?
I have httpClient request
var handler = new HttpClientHandler();
if (handler.SupportsAutomaticDecompression)
{
handler.AutomaticDecompression = DecompressionMethods.GZip |
DecompressionMethods.Deflate;
}
var httpClient = new HttpClient(handler);
httpClient.SendAsync(new HttpRequestMessage(new HttpMethod.Post, url));
And I have old HttpWebResponse
using (var dataStream = httpWebRequest.GetRequestStream())
{
var reqDataByte = Encoding.GetEncoding(encoding).GetBytes(reqData);
dataStream.Write(reqDataByte, 0, reqDataByte.Length);
}
using (var httpWebResponse = (HttpWebResponse) httpWebRequest.GetResponse())
{
var responseStream = httpWebResponse.GetResponseStream();
if (responseStream != null)
using (var streamReader =
new StreamReader(responseStream, Encoding.GetEncoding(encoding)))
{
getString = streamReader.ReadToEnd();
}
}
Couldn't understand how to handle respond with httpClient right
using var dataStream = httpClient.GetAsync(url, HttpCompletionOption.ResponseHeadersRead);
var reqDataByte = Encoding.GetEncoding(encoding).GetBytes(reqData);
dataStream.CopyToAsync(reqDataByte, 0, reqDataByte.Length);
using var response = (HttpWebResponse) httpClient.GetResponse();
var responseStream = response.GetResponseStream();
using var streamReader =
new StreamReader(responseStream, Encoding.GetEncoding(encoding));
getString = streamReader.ReadToEnd();
If you are trying to simply post raw bytes and get a string response back it is quite simple. You will need this to be an async method and await the async calls.
var reqDataByte = Encoding.GetEncoding(encoding).GetBytes(reqData);
var response = await httpClient.PostAsync(url, new ByteArrayContent(reqDataByte));
if (response.IsSuccessStatusCode)
{
getString = await response.Content.ReadAsStringAsync();
}
else
{
//Handle any unsuccessful post
}

How do I use XUnit `InlineData` so that I can insert multiple test data for MultipartFormDataContent?

I have this working Xunit code.
[Fact]
public async Task When_DocumentTypeInvalidFileType_Then_ShouldFail()
{
using (var client = new HttpClient())
{
var filePath = #"D:\Files\test.pdf";
using (var stream = File.OpenRead(filePath))
{
using (var form = new MultipartFormDataContent())
{
form.Add(new StringContent(Guid.NewGuid().ToString()), "Id");
var file = new StreamContent(stream);
file.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
form.Add(file, "File", Path.GetFileName(filePath));
// Act
var response = await client.PostAsync("/ABC/Document", form);
var responseString = await response.Content.ReadAsStringAsync();
_output.WriteLine("response: {0}", responseString);
HttpStatusCode statusCode = response.StatusCode;
Assert.Equal(HttpStatusCode.BadRequest, statusCode);
var result = JsonConvert.DeserializeObject<ResponseMessage>(responseString);
Assert.Equal("Invalid file type.", result.file[0]);
}
}
}
But the above only test for one scenario. How do I use XUnit InlineData so that I can insert multiple test data for MultipartFormDataContent?
[Theory]
[InlineData(MediaTypeNames.Application.Pdf, #"D:\Files\test.pdf")]
[InlineData(MediaTypeNames.Application.Xml, #"D:\Files\test.xml")]
// else files what you need
public async Task When_DocumentTypeInvalidFileType_Then_ShouldFail(string contentType, string filePath)
{
using (var client = new HttpClient())
{
using (var stream = File.OpenRead(filePath))
{
using (var form = new MultipartFormDataContent())
{
form.Add(new StringContent(Guid.NewGuid().ToString()), "Id");
var file = new StreamContent(stream);
file.Headers.ContentType = new MediaTypeHeaderValue(contentType);
form.Add(file, "File", Path.GetFileName(filePath));
// Act
var response = await client.PostAsync("/ABC/Document", form);
var responseString = await response.Content.ReadAsStringAsync();
_output.WriteLine("response: {0}", responseString);
HttpStatusCode statusCode = response.StatusCode;
Assert.Equal(HttpStatusCode.BadRequest, statusCode);
var result = JsonConvert.DeserializeObject<ResponseMessage>(responseString);
Assert.Equal("Invalid file type.", result.file[0]);
}
}
}
}
OR
[Theory]
[MemberData(nameof(TestGenerator.GetTestData), MemberType = typeof(TestGenerator))]
public async Task When_DocumentTypeInvalidFileType_Then_ShouldFail(string contentType, string filePath)
{
using (var client = new HttpClient())
{
using (var stream = File.OpenRead(filePath))
{
using (var form = new MultipartFormDataContent())
{
form.Add(new StringContent(Guid.NewGuid().ToString()), "Id");
var file = new StreamContent(stream);
file.Headers.ContentType = new MediaTypeHeaderValue(contentType);
form.Add(file, "File", Path.GetFileName(filePath));
// Act
var response = await client.PostAsync("/ABC/Document", form);
var responseString = await response.Content.ReadAsStringAsync();
_output.WriteLine("response: {0}", responseString);
HttpStatusCode statusCode = response.StatusCode;
Assert.Equal(HttpStatusCode.BadRequest, statusCode);
var result = JsonConvert.DeserializeObject<ResponseMessage>(responseString);
Assert.Equal("Invalid file type.", result.file[0]);
}
}
}
}
class TestGenerator
{
public static IEnumerable<object[]> GetTestData() => new List<object[]>
{
new object[] { MediaTypeNames.Application.Pdf, #"D:\Files\test.pdf" },
new object[] { MediaTypeNames.Application.Xml, #"D:\Files\test.xml" }
};
}

How to send a json file with HttpClient in C#?

I'm trying send a JSON file with postman and it's working. But when I'm trying to send the same contents via HttpClient it's not working.
System.IO.File.WriteAllText(dirName + "\\importproduct.json", jsonitems);
var fileByteArray = File.ReadAllBytes(dirName + "\\importproduct.json");
using (var _client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
content.Add(new StreamContent(new MemoryStream(fileByteArray)), "file");
var url = $"{firmInfo.ServiceUrl}/product/api/products/import";
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearer_token.id_token);
var response = _client.PostAsJsonAsync(url, content).Result;
var result = response.Content.ReadAsStringAsync().Result;
}
}
PostMan:
Instead of using PostAsJsonAsync(); method you should use PostAsync(); So your code should be looking something like that
using (var _client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
content.Add(new StreamContent(new MemoryStream(fileByteArray)), "file");
var url = $"{firmInfo.ServiceUrl}/product/api/products/import";
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearer_token.id_token);
var response = _client.PostAsync(url, content).Result;
var result = response.Content.ReadAsStringAsync().Result;
}
}
PostAsJsonAsync method is a generic method, it expects as the second parameter the object that will be serialized and sent in the POST body.
var obj = JsonConvert.DeserializeObject<SomeModelClass>(jsonString);
var response = await _client.PostAsJsonAsync(url, obj).Result;
This is based on efecetir's post above. It works for me. BTW, I also upvoted his post.
My issue was I needed to set the content type at the content-based level.
var fileByteArray = File.ReadAllBytes(filePath);
HttpContent bytesContent = new ByteArrayContent(fileByteArray);
using (var httpClient = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
var RequestUri = new Uri($"http://whatever.com/");
//client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearer_token.id_token);
formData.Headers.Add("super-secret-key", "blah");
bytesContent.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
//httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); //("multipart/form-data")); // Not needed
formData.Add(bytesContent, "file", "blah.json");
var response = httpClient.PostAsync(RequestUri, formData).Result;
return await HandleResponse(response);
}
Thanks for your comments.
I fixed it and convert my codes as below. Now it's working and much more clean.
HttpContent bytesContent = new ByteArrayContent(fileByteArray);
using (var client = new HttpClient())
using (var formData = new MultipartFormDataContent())
{
var url = $"{firmInfo.ServiceUrl}/product/api/products/import";
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearer_token.id_token);
formData.Add(bytesContent, "file", "importproduct.json");
var response = client.PostAsync(url, formData).Result;
var result = response.Content.ReadAsStringAsync().Result;
}
Here's code I'm using to post form information and a file
using (var httpClient = new HttpClient())
{
var surveyBytes = ConvertToByteArray(surveyResponse);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var byteArrayContent = new ByteArrayContent(surveyBytes);
byteArrayContent.Headers.ContentType = MediaTypeHeaderValue.Parse("text/csv");
var url = $"{firmInfo.ServiceUrl}/product/api/products/import";
var response = await httpClient.PostAsync(url , new MultipartFormDataContent
{
{byteArrayContent, "\"file\"", dirName + "\\importproduct.json"}
});
return response;
}
This is for .net 4.5.

How to send a file and form data with HttpClient in C#

How can I send a file and form data with the HttpClient?
I have two ways to send a file or form data. But I want to send both like an HTML form. How can I do that? Thanks.
This is my code:
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
var client = new HttpClient();
var requestContent = new MultipartFormDataContent();
filename = openFileDialog1.FileName;
array = File.ReadAllBytes(filename);
var imageContent = new ByteArrayContent(array);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("audio/*");
requestContent.Add(imageContent, "audio", "audio.wav");
var values = new Dictionary<string, string>
{
{ "token", "b53b99534a137a71513548091271c44c" },
};
var content = new FormUrlEncodedContent(values);
requestContent.Add(content);
var response = await client.PostAsync("localhost", requestContent);
var responseString = await response.Content.ReadAsStringAsync();
txtbox.Text = responseString.ToString();
}
Here's code I'm using to post form information and a csv file
using (var httpClient = new HttpClient())
{
var surveyBytes = ConvertToByteArray(surveyResponse);
httpClient.DefaultRequestHeaders.Add("X-API-TOKEN", _apiToken);
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var byteArrayContent = new ByteArrayContent(surveyBytes);
byteArrayContent.Headers.ContentType = MediaTypeHeaderValue.Parse("text/csv");
var response = await httpClient.PostAsync(_importUrl, new MultipartFormDataContent
{
{new StringContent(surveyId), "\"surveyId\""},
{byteArrayContent, "\"file\"", "\"feedback.csv\""}
});
return response;
}
This is for .net 4.5.
Note the \" in the MultipartFormDataContent. There is a bug in MultipartFormDataContent.
In 4.5.1 MultipartFormDataContent wraps the data with the correct quotes.
Update: This link to the bug no longer works since the have retired Microsoft Connect.
Here's code I'm using a method to send file and data from console to API
static async Task uploaddocAsync()
{
MultipartFormDataContent form = new MultipartFormDataContent();
Dictionary<string, string> parameters = new Dictionary<string, string>();
//parameters.Add("username", user.Username);
//parameters.Add("FullName", FullName);
HttpContent DictionaryItems = new FormUrlEncodedContent(parameters);
form.Add(DictionaryItems, "model");
try
{
var stream = new FileStream(#"D:\10th.jpeg", FileMode.Open);
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(#"http:\\xyz.in");
HttpContent content = new StringContent("");
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "uploadedFile1",
FileName = "uploadedFile1"
};
content = new StreamContent(stream);
form.Add(content, "uploadedFile1");
client.DefaultRequestHeaders.Add("Authorization", "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.dsfdsfdsfdsfsdfkhjhjkhjk.vD056hXETFMXYxOaLZRwV7Ny1vj-tZySAWq6oybBr2w");
var response = client.PostAsync(#"\api\UploadDocuments\", form).Result;
var k = response.Content.ReadAsStringAsync().Result;
}
catch (Exception ex)
{
}
}

Using HttpRequestHeaders in WinRT & C#

I'm using HttpWebRequests to contact an API and need to add a header but the compiler tells me that the method does not exists.
Yet, when I check MSDN, it tells me that the method already exists.
Setting my UserAgent-property fails as well.
Can anyone help me please?
try{
HttpWebRequest wr = (HttpWebRequest)HttpWebRequest.Create(url);
wr.Method = "GET";
wr.Headers.Add(System.Net.HttpRequestHeader.Authorization, string.Format("Bearer {0}", _accessToken));
wr.UserAgent = _appNameAndContact;
var resp = (System.Net.HttpWebResponse) await wr.BetterGetResponse();
if (resp.StatusCode == System.Net.HttpStatusCode.OK)
{
using (var sw = new System.IO.StreamReader(resp.GetResponseStream()))
{
var msg = sw.ReadToEnd();
User usr = JsonConvert.DeserializeObject<User>(msg);
//var results = JSONHelper.Deserialize<User>(msg);
return usr;
}
}
}
You will have to use a HttpRequestMessage like this:
using (var httpClient = new HttpClient())
{
var url = new Uri("http://bing.com");
var accessToken = "1234";
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, url))
{
httpRequestMessage.Headers.Add(System.Net.HttpRequestHeader.Authorization.ToString(),
string.Format("Bearer {0}", accessToken));
httpRequestMessage.Headers.Add("User-Agent", "My user-Agent");
using (var httpResponseMessage = await httpClient.SendAsync(httpRequestMessage))
{
// do something with the response
var data = httpRequestMessage.Content;
}
}
}

Categories