Getting FullContent from blobBaseClient.DownloadToAsync - c#

I am trying to download blob using BlockBlobClient DownloadToAsync method.
As mentioned in documentation, I provided required param, but getting only partial content.
Related code is:
string messageJson = string.Empty;
try
{
var blobBaseClient = new BlobBaseClient(_connectionString, _containerName, blobName);
Stream stream = new MemoryStream();
CancellationToken cancelToken = new CancellationToken();
StorageTransferOptions storageTransferOptions = new StorageTransferOptions
{
//bytes * 1000000 = MB
InitialTransferSize = blobInitialChunkSize.Value * 1000000,
MaximumConcurrency = blobChunkUploadMaxThreadCount.Value,
MaximumTransferSize = long.MaxValue
};
BlobRequestConditions blobRequestConditions = new BlobRequestConditions();
Response response = await blobBaseClient.DownloadToAsync(stream, blobRequestConditions, storageTransferOptions, cancelToken);
if(response.Status == Convert.ToInt32(HttpStatusCode.OK)
{
using (StreamReader streamReader = new StreamReader(stream))
{
messageJson = streamReader.ReadToEnd();
}
}
else
{
_logger.LogInformation("response.Headers.ContentType : " + response.Headers.ContentType + DateTime.Now.ToString());
_logger.LogInformation("response.Headers.ContentLength : " + response.Headers.ContentLength + DateTime.Now.ToString());
_logger.LogInformation("response.Headers.ETag : " + response.Headers.ETag + DateTime.Now.ToString());
_logger.LogInformation("response.Headers.RequestId : " + response.Headers.RequestId + DateTime.Now.ToString());
_logger.LogInformation("response.Status : " + response.Status + DateTime.Now.ToString());
_logger.LogInformation("response.ReasonPhrase : " + response.ReasonPhrase + DateTime.Now.ToString());
_logger.LogInformation("stream : " + stream + DateTime.Now.ToString());
}
catch (Exception ex)
{
_logger.LogInformation(ex.Message + " " + DateTime.Now.ToString());
_logger.LogInformation(ex.StackTrace + " " + DateTime.Now.ToString());
_logger.LogInformation(ex.Source + " " + DateTime.Now.ToString());
_logger.LogInformation(ex.InnerException + " " + DateTime.Now.ToString());
throw;
}
return messageJson;
the result I got is else block(not exception) & log values :
response.Headers.ContentType : application / octet - stream
response.Headers.ContentLength : 189778220
response.Headers.ETag : 0x8D860678531E07B
response.Status : 206
response.ReasonPhrase : Partial Content
stream: System.IO.MemoryStream
messageJson:
I want to know how can I get full data instead of Partial Data ? Any pointers/Help will be appreciated.

Try the code bellow with DownloadAsync method, it will return 200.
BlobServiceClient blobServiceClient = new BlobServiceClient(_connectionString);
BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(_containerName);
BlobClient blobClient = containerClient.GetBlobClient(blobName);
if (await blobClient.ExistsAsync())
{
var response = await blobClient.DownloadAsync();
using (var streamReader = new StreamReader(response.Value.Content))
{
while (!streamReader.EndOfStream)
{
var line = await streamReader.ReadLineAsync();
Console.WriteLine(line);
}
}
Console.WriteLine(response);
}
Azure Blob storage supports return 206 response if you're using API version 2011-01-18 or later. As the documentation says:
A successful operation to read the full blob returns status code 200
(OK).
A successful operation to read a specified range returns status code
206 (Partial Content).

As suggested on Bug I asked on Github, I have added success condition for HTTP 206 too and it is working fine:
if ((response.Status == Convert.ToInt32(HttpStatusCode.OK))
|| response.Status == Convert.ToInt32(HttpStatusCode.PartialContent))
{
using StreamReader streamReader = new StreamReader(response.ContentStream);
stream.Position = 0;
messageJson = streamReader.ReadToEnd();
}

Related

multi-threaded foreach Api Post and write response to a folder

I have a api in which I need to post a request and write the response to individual txt files.
Each post request needs to go with a MaterialID which I am reading from a list. The list can contain anything from 1000 to 5000 MaterialIDs
I need a way to do multiple parallel requests.
The below code is what I currently have but is built more for synchronous request.
How do i go about doing parallel requests ?
//reads MaterialID from file
System.IO.StreamReader fileTXT =
new System.IO.StreamReader(#"C:\\Temp\Test.txt");
while ((line = fileTXT.ReadLine()) != null)
{
Material_Count.Add(line.Trim());
UpdateLogTxt("Material_Count = " + line.ToString() + " ");
}
fileTXT.Close();
//loops through MaterialID list and starts post request
foreach (var item in Material_Count)
{
try
{
UpdateLogTxt(" Submitting = " + item.ToString());
var Set = Properties.Settings.Default;
using (var httpClient = new HttpClient())
{
string FCSEndPoint = #"https://www.api.co.za";
string FCSToken = "";
FCSToken = textBoxDescription.Text.Trim();
string uri = $"{FCSEndPoint}/material/pageIndex=" + item.ToString() + "";
HttpResponseMessage response = null;
httpClient.BaseAddress = new Uri(uri);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SessionToken", FCSToken);
AuthenticationHeaderValue headerObj = new AuthenticationHeaderValue("SessionToken", FCSToken);
httpClient.DefaultRequestHeaders.Authorization = headerObj;
var TaskObj = httpClient.PostAsJsonAsync(uri, String.Empty);
TaskObj.Wait();
HttpResponseMessage messageOut = TaskObj.Result;
response = TaskObj.Result;
if (response.IsSuccessStatusCode)
{
var TaskObj2 = messageOut.Content.ReadAsStringAsync();
TaskObj2.Wait();
string ResponseStr = TaskObj2.Result;
//writes response to a txt file.
string fileName = #"C:\Temp\material\Material_ " + item.ToString() + " " + DateTime.Now.ToString("yyyyMMddmmss") + ".txt";
try
{
// Check if file already exists. If yes, delete it.
if (File.Exists(fileName))
{
File.Delete(fileName);
}
// Create a new file
using (StreamWriter sw = File.CreateText(fileName))
{
sw.WriteLine(ResponseStr.ToString());
}
}
catch (Exception ex)
{
UpdateLogTxt("Exception Write to file Failed = --- " + ex.ToString());
}
}
else if (response.StatusCode == System.Net.HttpStatusCode.Forbidden)
{
UpdateLogTxt("Response Failed (Forbidden) = --- " + response.StatusCode.ToString());
}
else
{
}
}
}
catch (HttpRequestException h)
{
UpdateLogTxt("HttpRequestException Send Failed = --- " + h.ToString());
}
catch (Exception ex)
{
UpdateLogTxt("Exception Send Failed = --- " + ex.ToString());
}
}
Replace the foreach by the Parallel.ForEach in the System.Threading.Tasks namespace
You can find handy sample codes here =>
Parallel.ForEach method
Here's an alternative using Microsoft's Reactive Framework - NuGet System.Reactive and then you can do this:
Start by collecting a couple of constants used in your code to make sure they happen on the UI thread and only once:
string fcsToken = textBoxDescription.Text.Trim();
string now = DateTime.Now.ToString("yyyyMMddmmss");
Now lets create a helper method to handle the HTTP call:
Task<HttpResponseMessage> PostAsJsonAsync(HttpClient hc, string item)
{
string fcsEndPoint = #"https://www.api.co.za";
string uri = $"{fcsEndPoint}/material/pageIndex={item}";
hc.BaseAddress = new Uri(uri);
hc.DefaultRequestHeaders.Accept.Clear();
hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
hc.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SessionToken", fcsToken);
AuthenticationHeaderValue authorization = new AuthenticationHeaderValue("SessionToken", fcsToken);
hc.DefaultRequestHeaders.Authorization = authorization;
return hc.PostAsJsonAsync(uri, String.Empty);
}
Now we can write the observable query:
IObservable<(string fileName, string responseText)> query =
from item in
File
.ReadLines(#"C:\\Temp\Test.txt")
.Select(x => x.Trim())
.ToObservable()
from output in
Observable
.Using(
() => new HttpClient(),
hc =>
from response in Observable.FromAsync(() => PostAsJsonAsync(hc, item))
where response.IsSuccessStatusCode
from responseText in Observable.FromAsync(() => response.Content.ReadAsStringAsync())
select
(
fileName: $#"C:\Temp\material\Material_ {item} {now}.txt",
responseText: responseText
))
select output;
And finally we have the subscription:
IDisposable subscription =
query
.Subscribe(x => File.WriteAllText(x.fileName, x.responseText));
That's it. It's all asynchronous and concurrent.

API is giving Error {{System.Runtime.CompilerServices.AsyncTaskMethodBuilder1+AsyncStateMachineBox1}}

I am creating a API consumption tool where I have a issue in which It is giving following error when I try to call API. Please help me with this. I am trying to get CSV file and converted to TXT format with this API.
System.Runtime.CompilerServices.AsyncTaskMethodBuilder1+AsyncStateMachineBox1[System.String,StarRezToolApp.Program+d__2]
public static void GetReportInformation(string file_path_1, string Filename)
{
Utility.Utility.Log("TestFIle Reached");
var report_data = HTTP_GET();
Console.WriteLine(report_data.ToString());
var sb_csv = new StringBuilder();
try
{
if (File.Exists(file_path_1 + Filename))
{
using (StreamWriter apiresponse = File.AppendText(file_path_1 + Filename))
{
apiresponse.Write(report_data.ToString());
apiresponse.WriteLine();
}
}
else
{
using (StreamWriter apiresponse = new StreamWriter(file_path_1 + Filename))
{
apiresponse.Write(report_data.ToString());
apiresponse.WriteLine();
}
}
Utility.Utility.Log("File Created Successfully.");
}
catch (Exception ex)
{
Utility.Utility.Log("Error: Could Not Convert. Original error: " + ex.Message);
}
}
I have been calling the following method for other Information
private static async Task<string> HTTP_GET()
{
var TARGETURL = Properties.Resources.URL + Properties.Resources.Report_Name;
Console.WriteLine("GET: + " + TARGETURL);
Utility.Utility.Log("GET: + " + TARGETURL);
NetworkCredential credentials = new NetworkCredential(Properties.Resources.Username, Properties.Resources.Tocken.ToString());
HttpClientHandler handler = new HttpClientHandler
{
Credentials = credentials
};
// ... Use HttpClient with handlers which has credentials
HttpClient client = new HttpClient(handler);
HttpResponseMessage response = await client.GetAsync(TARGETURL);
HttpContent content = response.Content;
// ... Check Status Code
Utility.Utility.Log("Response StatusCode: " + (int)response.StatusCode);
Console.WriteLine("Response StatusCode: " + (int)response.StatusCode);
// ... Read the string.
string result = await content.ReadAsStringAsync();
// ... Display the result.
if (result != null && result.Length >= 50)
{
Utility.Utility.Log("Response message: Successful");
return result.ToString();
}
else
{
Utility.Utility.Log("Response message: " + response.Content);
return null;
}
}
Thank you Mr. #RuardvanElburg. I got the solution by your help.
My controller method GetReportInformationAsync needs to await for response to get out.

Facebook active token failure C# HttpWebRequest

I obtain an access_token OK from Facebook, but whenever I try to use it, it fails (bad request).
It looks like the access_token is not being sent to the server correctly. I have used Server.UrlEncode to encode it.
Any ideas what I am doing wrong?
string ourAccessToken = "unknown";
//--------------------------------------
protected void Page_Load(object sender, EventArgs e)
{
getAccessToken();
getMe();
}
// -----------------------
private void getAccessToken()
{
string result = "unknown";
try
{
// get app access token
string thisURL = "https://graph.facebook.com/oauth/access_token";
thisURL += "?client_id=" + ourClientID;
thisURL += "&client_secret=" + ourClientSecret;
thisURL += "&grant_type=client_credentials";
thisURL += "&redirect_uri=" + Server.UrlEncode(ourSiteRedirectURL);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create( thisURL);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
HttpStatusCode rc = response.StatusCode;
if( rc == HttpStatusCode.OK)
{
StreamReader Sreader = new StreamReader( response.GetResponseStream());
result = Sreader.ReadToEnd();
Sreader.Close();
}
response.Close();
}
catch (Exception exc)
{
result = "ERROR : " + exc.ToString();
}
Response.Write( "<br>result=[" + result + "]");
// extract accessToken
string accessToken = "";
int equalsAt = result.IndexOf( "=");
if( equalsAt >= 0 && result.Length > equalsAt) accessToken = (result.Substring( equalsAt + 1)).Trim();
Response.Write( "<br>accessToken=[" + accessToken + "]");
ourAccessToken = accessToken;
}
// -----------------------
private void getMe()
{
string result = "unknown";
try
{
string thisURL = "https://graph.facebook.com/me?access_token=" + Server.UrlEncode(ourAccessToken);
Response.Write("<br>thisURL=" + thisURL);
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create( thisURL);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
HttpStatusCode rc = response.StatusCode;
if( rc == HttpStatusCode.OK)
{
StreamReader Sreader = new StreamReader( response.GetResponseStream());
result = Sreader.ReadToEnd();
Sreader.Close();
}
response.Close();
}
catch (Exception ex)
{
Response.Write("<br>getMe Exc: " + ex.Message.ToString() + "<br>");
}
Response.Write("<br>getMe result = " + result + "<br><br>");
}
Thanks
Right settings in App-Dashboard? If you active "Native/Desktop" you can not send API-Calls with this method, see:
https://developers.facebook.com/docs/facebook-login/access-tokens?locale=en_US#apptokens
After a lot of trial and error, I conclude that an App Access Token is not relevant, and that the ClientID and ClientSecret should be used directly. I want my App to generate a set of photographs of registered users. Because the server is making the call, there is no meaning to "me". A set of data can be obtained by preparing a batch process:
string p1 = "access_token=" + Server.UrlEncode(ourClientID + "|" + ourClientSecret);
string p2 = "&batch=" +
Server.UrlEncode( " [ { \"method\": \"get\", \"relative_url\": \"" + chrisFBID + "?fields=name,picture.type(square)\" }, " +
" { \"method\": \"get\", \"relative_url\": \"" + johnFBID + "?fields=name,picture.type(large)\" }, " +
" { \"method\": \"get\", \"relative_url\": \"" + stephFBID + "?fields=name,picture.type(large)\" } ]");
string responseData = "";
try
{
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create("https://graph.facebook.com/");
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
byte[] bytedata = Encoding.UTF8.GetBytes(p1 + p2);
httpRequest.ContentLength = bytedata.Length;
Stream requestStream = httpRequest.GetRequestStream();
requestStream.Write(bytedata, 0, bytedata.Length);
requestStream.Close();
HttpWebResponse httpWebResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream responseStream = httpWebResponse.GetResponseStream();
StreamReader reader = new StreamReader(responseStream, System.Text.Encoding.UTF8);
responseData = reader.ReadToEnd();
}
catch (Exception ex)
{
Response.Write(ex.Message.ToString() + "<br>");
}
Response.Write("<br>" + responseData + "<br><br>");
I also conclude that the FB documentation suffers from the usual fatal flaw of documentation: it has been written by an expert and never tested on a novice user before release.

Middleware - performance issues

I'm developing a Middleware for my client and it's found that there are some delay when executing the process.
We are currently investigating what's the exact causes of the issue, from architecture design to coding.
Below are part of the scripts we are calling, and just wondering if the codes itself is optimized and properly written?
There's no error from the codes below, just wondering if there's any performance or coding issues. Tks
public string getResponse(System.Type type, Object input, string taskName, string method)
{
string response = string.Empty;
try
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(type);
MemoryStream mem = new MemoryStream();
ser.WriteObject(mem, input);
string data = Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length);
using (WebClient webClient = new WebClient())
{
webClient.Headers["Content-type"] = "application/json";
webClient.Encoding = Encoding.UTF8;
logger.Info("Sending [" + method + "] request to API[" + string.Format(Configuration.getTargetURI(), taskName) + "]");
response = webClient.UploadString(string.Format(Configuration.getTargetURI(), taskName), method, data);
logger.Info("Response of API[" + string.Format(Configuration.getTargetURI(), taskName) + "] successfully retrieved");
logger.Debug("Response: " + response);
}
}
catch (Exception ex)
{
logger.Info("Failed to invoke [" + method + "] request to API[" + string.Format(Configuration.getTargetURI(), taskName) + "], Error: " + ex.Message);
logger.Error(ex.Message + ex.StackTrace);
throw ex;
}
return response;
}
public string getResponseNoInput(string taskName, string method)
{
string response = string.Empty;
try
{
WebRequest req = WebRequest.Create(String.Format(Configuration.getTargetURI(), taskName));
req.Method = method;
req.ContentType = "application/json; charset=utf-8";
logger.Info("Sending [" + method + "] request to API[" + string.Format(Configuration.getTargetURI(), taskName) + "]");
HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
using (StreamReader sr = new StreamReader(resp.GetResponseStream()))
{
response = sr.ReadToEnd();
}
logger.Info("Response of API[" + string.Format(Configuration.getTargetURI(), taskName) + "] successfully retrieved");
logger.Debug("Response: " + response);
}
catch(Exception ex)
{
logger.Info("Failed to invoke [" + method + "] request to API[" + string.Format(Configuration.getTargetURI(), taskName) + "], Error: " + ex.Message);
logger.Error(ex.Message + ex.StackTrace);
throw ex;
}
return response;
}

Windows store apps: web request delayed with 1 minute

My app needs to perform a lot of diffrerent requests (~ 1-2 per second). I have a type of requests which runs continuously(RequestMade -> ResponseReceived -> RequestMade ->...).
If I enter another screen I should start a new set of requests to run continuously as long as I remain in that screen.
The problem is the that the new set of requests (the initial request) is delayed with ~ 1 minute.
Below is posted the code used to perform the requests.
Please note this line is printed out to console at, let's say 12:00:
Debug.WriteLine("Writing RequestStream ("+_request.GetType().FullName + " | " + DateTime.Now.ToLocalTime()+")");
And the lines:
Debug.WriteLine("Request is posting.....(" + _request.GetType().FullName + " | " + DateTime.Now.ToLocalTime()+")");
Debug.WriteLine("Reading ResponseStream (" + _request.GetType().FullName + " | " + DateTime.Now.ToLocalTime() + ")");
are printed at 12:01 (after 1 minute....)
private class RequestResponseTask
{
private Uri _uri = null;
private string _uriAddress = null;
private WebRequest _webRequest = null;
private ARequest _request = null;
private JsonTextParser _parser = null;
private RequestState _requestState = null;
public RequestResponseTask(ARequest request)
{
// uri address
_uriAddress = CVSCustomRelease.Instance.ReleaseSettings.SelectedPrivateLabel.GetServer(LoginSettings.Instance.SelectedServer).Address
+ CONTEXTUAL_REQUEST_PATH;
// uri
_uri = new Uri(_uriAddress);
// request
_request = request;
_parser = new JsonTextParser();
_requestState = new RequestState(_request);
}
public void StartRequest()
{
Debug.WriteLine("Starting RUN.......(" + _request.GetType().FullName + " | " + DateTime.Now.ToLocalTime() + ")");
Task.Factory.StartNew(() =>
{
Debug.WriteLine("RUN Started. - for "+_request.GetType().FullName + " | " + DateTime.Now.ToLocalTime());
_request.ResponseReceived = false;
Debug.WriteLine("Before WebRequest ("+_request.GetType().FullName + " | " + DateTime.Now.ToLocalTime()+")");
_webRequest = WebRequest.Create(_uri);
Debug.WriteLine("after WebRequest (" + _request.GetType().FullName + " | " + DateTime.Now.ToLocalTime() + ")");
_webRequest.ContentType = "text/x-gwt-rpc;charset=utf-8";
_webRequest.Method = "Post";
_requestState.Request = _webRequest;
// Start the Asynchronous 'BeginGetRequestStream' method call.
Debug.WriteLine("Writing RequestStream ("+_request.GetType().FullName + " | " + DateTime.Now.ToLocalTime()+")");
IAsyncResult r = (IAsyncResult)_webRequest.BeginGetRequestStream(
new AsyncCallback(PostRequest), _requestState);
_requestState.ResetEvent.WaitOne();
Debug.WriteLine("Reading ResponseStream (" + _request.GetType().FullName + " | " + DateTime.Now.ToLocalTime() + ")");
IAsyncResult asyncResp = (IAsyncResult)_webRequest.BeginGetResponse(
new AsyncCallback(ReadResponse), _requestState);
});
}
private void PostRequest(IAsyncResult asynchronousResult)
{
Debug.WriteLine("======================================================");
Debug.WriteLine("Request is posting.....(" + _request.GetType().FullName + " | " + DateTime.Now.ToLocalTime()+")");
// End the Asynchronus Request.
Stream streamResponse = _webRequest.EndGetRequestStream(asynchronousResult);
ARequest request = _requestState.OriginalRequest;
request.UpdateTimestampRealtime();
string postData = request.GetPostData();
EventsLog.Instance.WriteEvent("Request: " + postData);
// Create a string that is to be posted to the uri.
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
EventsLog.Instance.CurrentSession.AddTraficAmount(TraficType.Outgoing, byteArray.Length);
// Write the data to the stream.
streamResponse.Write(byteArray, 0, postData.Length);
streamResponse.Flush();
Debug.WriteLine("Request POSTED.");
Debug.WriteLine("======================================================");
_requestState.ResetEvent.Set();
}
private async void ReadResponse(IAsyncResult asyncResult)
{
_requestState = (RequestState)asyncResult.AsyncState;
WebRequest myWebRequest = _requestState.Request;
WebResponse response = (WebResponse)myWebRequest.EndGetResponse(asyncResult);
Stream responseStream = response.GetResponseStream();
StreamReader streamRead = new StreamReader(responseStream);
string responseString = await streamRead.ReadToEndAsync();
byte[] byteArray = Encoding.UTF8.GetBytes(responseString);
EventsLog.Instance.CurrentSession.AddTraficAmount(TraficType.Incomming, byteArray.Length);
// build response object
JsonObject jsonObject = _parser.Parse(responseString);
EventsLog.Instance.WriteEvent("Response: " + jsonObject.ToString() + "\nFor Request: " + _requestState.OriginalRequest.RequestId + " | " +_requestState.OriginalRequest.GetType().FullName);
_requestState.ResetEvent.Reset();
// notify listeners
_requestState.OriginalRequest.ResponseReceived = true;
_requestState.OriginalRequest.NotifyResponseListeners(jsonObject as JsonObjectCollection);
}
}
performing a request:
new RequestResponseTask(_request).StartRequest();
My guess: Your code blocks, which leads to a timeout on another thread (that's where the 1 minute comes from) which then leads to unblocking the first thread.
You have things like BeginGetRequestStream and ResetEvent.WaitOne in your code - which shouldn't be needed in a Windows Store code like yours. Try to use WebClient's async methods or HttpClient instead. Use await instead of WaitOne.

Categories

Resources