how to find where & why is server taking too much time to executing the controller function? - c#

i am new to .net environment . I am trying to upload multiple files through UI controller to some other api. it like from UI Js ajax request to asp.net UI Controller to some other api actual function. when i am uploading one it is uploading . but when is upload multiple files it taking too much time. most of files size are 3 MB.
i am really confuse where or how to know where in IIS taking too much time. because when make direct call to api from js it uploading files very fast but when it went through UI controller it is taking too much time.
i am adding UI Controller code. i
public async Task<JsonResult> DataList()
{
var client = GetHttpClientWithBearerToken();
client.Timeout = TimeSpan.FromSeconds(300);
var url = "some url";
string Rec;
string File;
try
{
var requestContent = new MultipartFormDataContent();
requestContent.Add(new StringContent(HttpContext.Request.Form["Id"]), "Id");
int FilesCount = HttpContext.Request.Files.Count;
for (int i = 0; i < FilesCount; i++)
{
HttpPostedFileBase file = HttpContext.Request.Files[i];
requestContent.Add(new StreamContent(file.InputStream), "file[]", file.FileName);
}
HttpResponseMessage responseMessage = await client.PostAsync(url, requestContent);
if (responseMessage.IsSuccessStatusCode)
{
var returnData = responseMessage.Content.ReadAsStringAsync().Result;
var jsonResult = Json(new { success = true, Content = returnData }, JsonRequestBehavior.AllowGet);
return jsonResult;
}
else
{
return Json(new { success = false, Content = "-1" }, JsonRequestBehavior.AllowGet);
}
}
catch (Exception e)
{
Logging.WriteLog(e.Message, Logging.LogMsgType.General);
}
return Json(new { success = false, Content = "-1" }, JsonRequestBehavior.AllowGet);
}`
have added some logs but there is not high time in the log so request is taking so much time to reach there. till the time chrome network tab showing

Related

.NET Web API Blueimp multiple file upload error "Unexpected end of MIME multipart stream. MIME multipart message is not complete."

I am building a video management app that allows for uploading multiple videos to Azure Storage which is then encoded by Azure Media Services.
My issue is that if I upload just 1 file at a time with blueimp, everything works fine. When I add more than one file to the upload, I get the error on the second file.
Unexpected end of MIME multipart stream. MIME multipart message is not complete.
I have read that it could be to the stream missing the end of file terminator, so I added in the suggested tweak to append the line terminator (per this article ASP.NET Web API, unexpected end of MIME multi-part stream when uploading from Flex FileReference) with no luck.
If I post as single files (by either iterating over the files selected for upload) and send them as individual posts, it works. My issue is that I want to select several files as well as add additional metadata and hit one submit button. When I do it this way, the first file uploads, and the second one appears to start to upload but then I get the error 500 "Unexpected end of MIME multipart stream. MIME multipart message is not complete" message.
Here is my upload code (Web API):
[HttpPost]
public async Task<HttpResponseMessage> UploadMedia()
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Headers["content-type"] != null)
{
httpRequest.Headers.Remove("content-type");
}
httpRequest.Headers.Add("enctype", "multipart/form-data");
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = HttpContext.Current.Server.MapPath("~/" + postedFile.FileName);
string assignedSectionList = string.Empty;
postedFile.SaveAs(filePath);
docfiles.Add(filePath);
string random = Helpers.Helper.RandomDigits(10).ToString();
string ext = System.IO.Path.GetExtension(filePath);
string newFileName = (random + ext).ToLower();
MediaType mediaType = MediaType.Video;
if (newFileName.Contains(".mp3"))
{
mediaType = MediaType.Audio;
}
if (httpRequest.Form["sectionList"] != null)
{
assignedSectionList = httpRequest.Form["sectionList"];
}
MediaUploadQueue mediaUploadQueueItem = new MediaUploadQueue();
mediaUploadQueueItem.OriginalFileName = postedFile.FileName;
mediaUploadQueueItem.FileName = newFileName;
mediaUploadQueueItem.UploadedDateTime = DateTime.UtcNow;
mediaUploadQueueItem.LastUpdatedDateTime = DateTime.UtcNow;
mediaUploadQueueItem.Status = "pending";
mediaUploadQueueItem.Size = postedFile.ContentLength;
mediaUploadQueueItem.Identifier = random;
mediaUploadQueueItem.MediaType = mediaType;
mediaUploadQueueItem.AssignedSectionList = assignedSectionList;
db.MediaUploadQueue.Add(mediaUploadQueueItem);
db.SaveChanges();
byte[] chunk = new byte[httpRequest.ContentLength];
httpRequest.InputStream.Read(chunk, 0, Convert.ToInt32(httpRequest.ContentLength));
var provider = new AzureStorageMultipartFormDataStreamProviderNoMod(new AzureMediaServicesHelper().container);
provider.fileNameOverride = newFileName;
await Request.Content.ReadAsMultipartAsync(provider); //this uploads it to the storage account
//AzureMediaServicesHelper amsHelper = new AzureMediaServicesHelper();
string assetId = amsHelper.CommitAsset(mediaUploadQueueItem); //begin the process of encoding the file
mediaUploadQueueItem.AssetId = assetId;
db.SaveChanges();
////start the encoding
amsHelper.EncodeAsset(assetId);
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}
Here is the code for the upload handler that sends to Azure Blob storage
public override Stream GetStream(HttpContent parent, HttpContentHeaders headers)
{
if (parent == null) throw new ArgumentNullException(nameof(parent));
if (headers == null) throw new ArgumentNullException(nameof(headers));
if (!_supportedMimeTypes.Contains(headers.ContentType.ToString().ToLower()))
{
throw new NotSupportedException("Only jpeg and png are supported");
}
// Generate a new filename for every new blob
var fileName = Guid.NewGuid().ToString();
if (!String.IsNullOrEmpty(fileNameOverride))
fileName = fileNameOverride;
CloudBlockBlob blob = _blobContainer.GetBlockBlobReference(fileName);
if (headers.ContentType != null)
{
// Set appropriate content type for your uploaded file
blob.Properties.ContentType = headers.ContentType.MediaType;
}
this.FileData.Add(new MultipartFileData(headers, blob.Name));
return blob.OpenWrite();
}
Here is the javascript code. The first one is sending the files individual as separate posts, it works.
$("#fileupload").fileupload({
autoUpload: false,
dataType: "json",
add: function (e, data) {
data.context = $('<p class="file">')
.append($('<a target="_blank">').text(data.files[0].name))
.appendTo(document.body);
data.submit();
},
progress: function (e, data) {
var progress = parseInt((data.loaded / data.total) * 100, 10);
data.context.css("background-position-x", 100 - progress + "%");
},
done: function (e, data) {
data.context
.addClass("done")
.find("a")
.prop("href", data.result.files[0].url);
}
});
This code below does not work. It pushes all the files into and array and sends them in one single post. This one fails on the second file. If I upload just one file using this code, it works.
var filesList = new Array();
$(function () {
$('#fileupload').fileupload({
autoUpload: false,
dropZone: $('#dropzone'),
add: function (e, data) {
filesList.push(data.files[0]);
data.context = $('<div class="file"/>', { class: 'thumbnail pull-left' }).appendTo('#files');
var node = $('<p />').append($('<span/>').text(data.files[0].name).data(data));
node.appendTo(data.context);
},
progress: function (e, data) { //Still working on this part
//var progress = parseInt((data.loaded / data.total) * 100, 10);
//data.context.css("background-position-x", 100 - progress + "%");
},
}).on('fileuploadprocessalways', function (e, data) {
var index = data.index,
file = data.files[index],
node = $(data.context.children()[index]);
if (file.preview) {
node.prepend('<br>').prepend(file.preview);
}
if (file.error) {
node.append('<br>').append($('<span class="text-danger"/>').text(file.error));
}
}).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled');
$("#uploadform").submit(function (event) {
if (filesList.length > 0) {
console.log("multi file submit");
event.preventDefault();
$('#fileupload').fileupload('send', { files: filesList })
.success(function (result, textStatus, jqXHR) { console.log('success'); })
.error(function (jqXHR, textStatus, errorThrown) { console.log('error'); })
.complete(function (result, textStatus, jqXHR) {
console.log('complete: ' + JSON.stringify(result)); //The error 500 is returned here. In fiddler, it shows and error 500. If I try to trap in Visual Studio, I can't seem to pinpoint the exception.
// window.location='back to view-page after submit?'
});
} else {
console.log("plain default form submit");
}
});
});
Any thoughts on why this would be happening? I have tried every approach I can think about with no luck. Thank you in advance!
I want to point out that the architecture of your code might cause timeouts or errors.
I would first upload everything to azure storage, storage the status in cache or database.
then I would fire a background job (hangfire, azure functions, webjobs) to process uploading to media service to do the other stuff.
I would suggest doing this asynchronously from the user input.
as per the documentation of dropzone make sure you add name in the HTML tag
<form action="/file-upload" class="dropzone">
<div class="fallback">
<input name="file" type="file" multiple />
</div>
</form>
if you are doing it programatically:
function param() {
return "files";
}
Dropzone.options.myDropzone = {
uploadMultiple: true,
paramName: param,
}
on the backend you need to add \r\n after each stream:

Calling WEB API to download excel file

below is C# WEB API Code to generate Excel :
public class FileExportController : ApiController
{
[HttpGet]
public HttpResponseMessage Get()
{
var callerContext = CallerContext.DefaultCallerContext;
ReportingInput userInput = new ReportingInput();
userInput.ClientOneCode = "AVON";
string handle = Guid.NewGuid().ToString();
var #event = new GetJobReprotDataBlEvent(callerContext, userInput);
WebApiApplication.ApplicationInitializerObj.EventBus.Publish(#event);
XLWorkbook wb = new FileExportEngine().ExportExcel(#event.ReportData); //this is returning XLWorkbook
string fileName = "JobReport_" + DateTime.Now.ToString("yyyy -MM-dd HH':'mm':'ss") + ".xlsx";
using (MemoryStream memoryStream = new MemoryStream())
{
wb.SaveAs(memoryStream);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(memoryStream.ToArray())
};
result.Content.Headers.ContentDisposition =
new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = fileName
};
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
return result;
}
}
When I call this API from browser, I am able to generate excel file.
http://localhost/ETLScheduler/api/FileExport -- this is working when hit direct in browser
Now I want to use consume this API in angular 5 application.I have a button.On click button I call the component method downloadFile() to download the file.
Below is the code :
downloadReport() {
this._service.downloadJobReport('AVON');
}
where downloadJobReport() is in my service file as below :
downloadJobReport(clientCode: string) {
return this._http.get(APIs.downloadJobReport);
}
When I am running the application and click on Download button, I am getting nothing, I mean file is not downloading. Can anyone have idea,how should I update my angular code to consume the API.
Thanks in advance.
As you mentioned above in comments you are using below angular code to download file:
downloadFile(data: Blob) {
const contentType = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
const blob = new Blob([data], { type: contentType });
const url = window.URL.createObjectURL(blob);
window.open(url);
}
As I also have tried this code, it is working in chrome browser but not working in IE and edge.
You may update your method somthing like below:
var downloadFile=function (file_name, content) {
var csvData = new Blob([content], { type: 'text/csv' });
if (window.navigator && window.navigator.msSaveOrOpenBlob) { // for IE
window.navigator.msSaveOrOpenBlob(csvData, file_name);
} else { // for Non-IE (chrome, firefox etc.)
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
var csvUrl = URL.createObjectURL(csvData);
a.href = csvUrl;
a.download = file_name;
a.click();
URL.revokeObjectURL(a.href)
a.remove();
}
};
you can refer below link for more information:
Open links made by createObjectURL in IE11
Problem is, that Angular expects JSON as a result. You need to configure your GET request so, that it expects something different.
public downloadJobReport(clientCode: string)): Observable<Blob> {
return this._http.get(APIs.downloadJobReport, { responseType: 'blob' });
}
Just a tiny question, you pass an argument clientCode to the downloadJobReport, but never use it. Maybe wise to leave that out?

Download a file in FORM POST request C#

I am using C# ASP.NET code and trying to download file on the post request of a form. here is my sample code.
[HttpPost]
public ActionResult PostMethodName(PostModel inputModel)
{
if (ModelState.IsValid)
{
//other code is removed.
//Writing this for the test
//Download Method call
DownloadCertificate("This is the test file to download.");
var statusHtml = RenderViewToString("Status",
new ErrorMsgModel
{
IsSuccess = true,
ErrorDesc = "desc"
});
return Json(new { IsSuccess = true, ErrorDescription =
statusHtml}, JsonRequestBehavior.AllowGet);
}
var statusHtml1 = RenderViewToString("Status",
new ErrorMsgModel
{
IsSuccess = false,
ErrorDesc = "desc"
});
statusHtml1 = statusHtml1.Replace("'", "\\'");
statusHtml1 = statusHtml1.Replace(Environment.NewLine, "");
return Json(new { IsSuccess = false, ErrorDescription = statusHtml1
}, JsonRequestBehavior.AllowGet);
}
Download method which is called from this method.
public ActionResult DownloadCertificate(string content)
{
//Certificate Download
const string fileType = "application/pkcs10";
string fileName = "Certificate" + DateTime.Today.ToString(#"yyyy-MM-dd") + ".csr";
var fileContent = String.IsNullOrEmpty(contrnt) ? "" : contrnt;
byte[] fileContents = Encoding.UTF8.GetBytes(fileContent);
var result = new FileContentResult(fileContents, fileType) { FileDownloadName = fileName };
return result;
}
file download is not working, post functionality is working as desired.
[HttpPost]
public ActionResult DownloadCertificate(PostModel inputModel, string content)
{
if(!ModelState.IsValid){return Json(new {Success=false,//error descr})}
//Certificate Download
const string fileType = "application/pkcs10";
string fileName = "Certificate" + DateTime.Today.ToString(#"yyyy-MM-dd") + ".csr";
var fileContent = String.IsNullOrEmpty(contrnt) ? "" : contrnt;
byte[] fileContents = Encoding.UTF8.GetBytes(fileContent);
var result = new FileContentResult(fileContents, fileType) { FileDownloadName = fileName };
return result;
}
In your previous code you don`t use DownloadCertificate result, you simly execute it.
Your DownloadCertificate method returns a value, but you never use the return value in your PostMethodName method.
Given that you are returning json from that method I would suggest that you return a direct link to the file result in the response. The consuming client can then initiate the download. Something like:
return Json(new { IsSuccess = true, Location = Url.Action("DownloadContent")});
Alternatively you could consider a more restful approach and return a 302 response from the post action:
if (ModelState.IsValid)
{
// you code here
return RedirectToAction("Controller", "DownloadContent", new {content = "myContent"});
}
This may well proceed with the download transparently depending on your client whilst keeping to the Post-Redirect-Get pattern

Ajax calls are slower to controller in physically different file

While trying to speed up some ajax calls in one of our MVC pages, I encountered some strange behavior which I can't really explain. I have some ajax calls being made every N seconds for polling some statistics.
It seems like ajax calls being made to a controller in a physically different file are substantially slower than similar calls being made to a controller in the same physical file as where the view originates from.
See my simplified examples:
Situation 1: Only 1 file
FooController.cs
namespace FooBar.Areas.FooArea.Controllers
{
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class FooTestController: _BaseController
{
public JsonResult GetStats()
{
try
{
var req = new RestRequest() { Method = Method.GET };
req.AddHeader("Content-Type", "application/json");
req.AddHeader("Accept", "application/json");
req.AddParameter("apikey", /*APIKEY*/);
var client = new RestClient(/*STATSURL*/);
var response = client.Execute(req);
if (response.StatusCode == HttpStatusCode.OK)
return Json(new { success = true, content = response.Content });
else
return Json(new { success = false });
}
catch
{
return Json(new { success = false });
}
}
public JsonResult GetAgents()
{
var req = new RestRequest() { Method = Method.GET };
req.AddHeader("Content-Type", "application/json");
req.AddHeader("Accept", "application/json");
req.AddParameter("apikey", /*APIKEY*/);
try
{
var client = new RestClient(/*AGENTSURL*/);
var response = client.Execute(req);
if (response.StatusCode == HttpStatusCode.OK)
return Json(new { success = true, content = response.Content });
else
return Json(new { success = false });
}
catch
{
return Json(new { success = false });
}
}
}
public class FooController : _BaseController
{
// VIEW OF THE PAGE MAKING THE AJAX REQUESTS
public ActionResult Index()
{
Title = "Home";
return View();
}
}
}
Situation 2: 2 seperate files in same folder
FooController.cs
namespace FooBar.Areas.FooArea.Controllers
{
public class FooController: _BaseController
{
// VIEW OF THE PAGE MAKING THE AJAX REQUESTS
public ActionResult Index()
{
Title = "Home";
return View();
}
}
}
FooAjaxController.cs
namespace FooBar.Areas.FooArea.Controllers
{
[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class FooAjaxController: _BaseController
{
public JsonResult GetStats()
{
try
{
var req = new RestRequest() { Method = Method.GET };
req.AddHeader("Content-Type", "application/json");
req.AddHeader("Accept", "application/json");
req.AddParameter("apikey", /*APIKEY*/);
var client = new RestClient(/*STATSURL*/);
var response = client.Execute(req);
if (response.StatusCode == HttpStatusCode.OK)
return Json(new { success = true, content = response.Content });
else
return Json(new { success = false });
}
catch
{
return Json(new { success = false });
}
}
public JsonResult GetAgents()
{
var req = new RestRequest() { Method = Method.GET };
req.AddHeader("Content-Type", "application/json");
req.AddHeader("Accept", "application/json");
req.AddParameter("apikey", /*APIKEY*/);
try
{
var client = new RestClient(/*AGENTSURL*/);
var response = client.Execute(req);
if (response.StatusCode == HttpStatusCode.OK)
return Json(new { success = true, content = response.Content });
else
return Json(new { success = false });
}
catch
{
return Json(new { success = false });
}
}
}
}
In both situations, the ajax calls are made from jQuery as follows:
jQuery
$.ajax({
url: // URL TO ACTION DEPENDING ON SITUATION,
type: "POST",
dataType: "json",
cache: false,
success: function (result)
{
if (result.success)
{
var content = JSON.parse(result.content);
console.log(content);
}
}
});
Now, the response times from the ajax requests for both situations are as follows, with situation 1 being displayed on the left and situation 2 on the right:
So, as you can see the average time of a call made to GetStats() and GetAgents() in situation 1 is 52.8 ms and 53.8 ms respectively.
However, in situation 2, the average time of the calls is 486.8 ms and 529.9 ms.
My question now is: how can it be that ajax calls made to actions are on average almost 10 times slower when those actions reside in a controller in a physically different file, than when those actions reside in a controller which shares the same physical file as the file rendering the view in the first place?
Is it because the file containing the action to render the view is already loaded and kept in memory, while the seperate file, as in in situation 2, is opened and closed every time the action is called? Or is something more sinister going on?
You shared most of the code but not _BaseController.cs
On each request, MVC gets the controller using dependency injection.
[speculation] MVC may store the most recently-used controller, returning the same one several times. However if you are switching controllers, perhaps it creates a new one each time.
Perhaps there is some very slow code in the _BaseController default constructor - perhaps database queries. It sounds unlikely but has happened in my experience.
Taken together, these things would cause the slowdown you describe.

Error reusing some async json method on windows phone

EDIT 1: I added below the code who calls and uses the second method, and the error and data I recive
First of all sorry if my English isn't good enough, and sorry if there is another thread with the solution. I haven't found it.
Ok, I'm making a windows phone 8 app that uses a lot of info from a web service. The app makes different Json Post and uses the info. I maked a method for Posting that WORKS:
public static async void checkdeviceid()
{
//Where we are posting to:
Uri theUri = new Uri("urlofexample");
//Create an Http client
HttpClient aClient = new HttpClient();
//Class that will be serialized into Json
objetoslistas.checkdeviceidinput paquete = new objetoslistas.checkdeviceidinput();
//Set some values
paquete.Text = "deviceID";
paquete.Text2 = App.device_id;
//serialize data
var serializado = JsonConvert.SerializeObject(paquete);
//Post the data
HttpResponseMessage aResponse = await aClient.PostAsync(theUri, new StringContent(JsonConvert.SerializeObject(paquete), Encoding.UTF8, "application/json"));
if (aResponse.IsSuccessStatusCode)
{
string res = await aResponse.Content.ReadAsStringAsync();
var respuestaperfil = JsonConvert.DeserializeObject<objetoslistas.checkdeviceidoutput>(res.ToString());
//Do something with the data
}
else
{
// show the response status code
String failureMsg = "HTTP Status: " + aResponse.StatusCode.ToString() + " - Reason: " + aResponse.ReasonPhrase;
}
}
This code its actually working, but the fact it's that my app will have maybe 30 or 40 diferent POST, so I tried to make a reusable method like this:
public static async Task<string> jsonPOST(Uri theUri, object paquete)
{
//Create an Http client and set the headers we want
HttpClient aClient = new HttpClient();
//serialize data
var serializado = JsonConvert.SerializeObject(paquete);
//Post the data
HttpResponseMessage aResponse = await aClient.PostAsync(theUri, new StringContent(JsonConvert.SerializeObject(paquete), Encoding.UTF8, "application/json"));
if (aResponse.IsSuccessStatusCode)
{
string res = await aResponse.Content.ReadAsStringAsync();
return res;
}
else
{
// show the response status code
String failureMsg = "HTTP Status: " + aResponse.StatusCode.ToString() + " - Reason: " + aResponse.ReasonPhrase;
return failureMsg;
}
}
This code gives me problems in the main, were it's called. As I can understand, the problem is that, as the method calls some await process, the rest of the code continues with the execution without expect for the await result...
The code in Main is:
objetoslistas.checkdeviceidinput paquete = new objetoslistas.checkdeviceidinput();
paquete.Text = "deviceID";
paquete.Text2 = App.device_id;
Uri url = new Uri("urlofhteservice");
Task<string> recibo = metodosJson.jsonPOST(url, paquete);
var respuestaperfil = JsonConvert.DeserializeObject<objetoslistas.checkdeviceidoutput>(recibo.ToString);
if (respuestaperfil.Text2 == null)
{
IsolatedStorageSettings.ApplicationSettings["DeviceRegistered"] = true;
}
else
{
IsolatedStorageSettings.ApplicationSettings["DeviceRegistered"] = false;
}
And I recive this error (translated from google translator, sorry)
There was an exception of type 'Newtonsoft.Json.JsonReaderException' in Newtonsoft.Json.DLL but not controlled in the user code
The data I have in "recibo" is
recibo Id = 1, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}" System.Threading.Tasks.Task<string>
So as I understand the await method is still waiting.
Was I clear?
Thanks

Categories