I am working with RestSharp and create object of RestRequest for sending FileData to API. But after getting response I want to delete the file from my local machine but when I try to do the same it gives me the error "File is being used by other process". The reason I think is that I am unable to dispose the object of RestRequest. Please help me to solve it. Below is the code. Thanks in Advance..!!!
public string PostMultiformDataAPI(Method method, string apiUrl, string data = "", Dictionary<string, string> headers = null)
{
string[] files = null;
try
{
RestClient client = new RestClient(apiUrl);
var request = new RestRequest();
request.Method = method;
//Add header values to request
if (headers != null)
{
foreach (var header in headers)
{
request.AddHeader(header.Key, header.Value);
}
}
string filename = string.Empty;
if (Directory.Exists(HttpContext.Current.Server.MapPath("/Upload")))
{
files = Directory.GetFiles(HttpContext.Current.Server.MapPath("/Upload"));
foreach (string file in files)
{
request.AddFile(file.Split('/').Last(), file);
}
}
// execute the request
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
foreach (string file in files)
{
GC.Collect();
GC.WaitForPendingFinalizers();
var fileInfo = new FileInfo(file);
fileInfo.Refresh();
fileInfo.Delete();
//File.Delete(file);
}
return content;
}
finally
{
}
}
You just need to assign null to request object instance to remove the reference it has to file. Worked for me. Please let me know if it works for you.
// execute the request
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
request = null;
response = null;
foreach (string file in files)
{
GC.Collect();
GC.WaitForPendingFinalizers();
var fileInfo = new FileInfo(file);
fileInfo.Refresh();
fileInfo.Delete();
File.Delete(file);
}
return content;
Related
Net core application. I have one rest API which will send files to another API.
Below is the logic inside first API to send files to second API.
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await _tokenService.GetToken());
MultipartFormDataContent multipartFormData = new MultipartFormDataContent();
string contentJson = JsonConvert.SerializeObject(request);
HttpContent data = new StringContent(contentJson, Encoding.UTF8, "application/json");
multipartFormData.Add(data, "data");
foreach (var file in fileList)
{
if (file.Length <= 0)
continue;
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
multipartFormData.Add(new StreamContent(file.OpenReadStream())
{
Headers =
{
ContentLength = file.Length,
ContentType = new MediaTypeHeaderValue(file.ContentType)
}
}, "File", fileName);
}
try
{
var response = await client.PostAsync("https://localhost:44370/apisendfile", multipartFormData);
}
catch (Exception ex)
{
}
}
I have second API as below
public async Task<ActionResult> SendMail([FromBody] MultipartFormDataContent formDataContent)
{
}
When I debug in my first API I receive error
Unsupported Media Type
I am trying all the way to figure it out but could not succeed. Can someone help me to identify this issue. Any help would be appreciated. Thanks
Well, you could try following way,
Web API Controller:
[HttpPost]
public string UploadMultipartFile()
{
var file = HttpContext.Current.Request.Files.Count > 0 ?
HttpContext.Current.Request.Files[0] : null;
if (file != null && file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(
HttpContext.Current.Server.MapPath("~/MrPerfectMaltipartFolder"),
fileName
);
file.SaveAs(path);
}
return file != null ? "/MrPerfectMaltipartFolder/" + file.FileName : null;
}
Folder Location:
Tested on Post Man:
Open Folder Location:
File Uploaded:
For N Type of Multipart Data Upload:
[HttpPost]
public object UploadMultipartFileList()
{
var uploadedFilesName = new List<string>();
if (HttpContext.Current.Request.Files.Count > 0)
{
int count = 0;
foreach (var item in HttpContext.Current.Request.Files)
{
var getFile = HttpContext.Current.Request.Files[count];
if (getFile != null)
{
var fileName = Path.GetFileName(getFile.FileName);
var path = Path.Combine(
HttpContext.Current.Server.MapPath("~/MrPerfectMaltipartFolder"),
fileName
);
getFile.SaveAs(path);
}
count++;
string file = "/MrPerfectMaltipartFolder/" + getFile.FileName;
uploadedFilesName.Add(file);
}
}
return uploadedFilesName;
}
Output:
Example Both Data and File:
[HttpPost]
public object UploadMultipartFileList()
{
HttpRequest multipartRquest = HttpContext.Current.Request;
//General Data Part
string engineerName = multipartRquest.Form["EngineerName"];
string engineerEmail = multipartRquest.Form["EngineerEmail"];
//File Upload Part
var FilesName = new List<string>();
if (HttpContext.Current.Request.Files.Count > 0)
{
int count = 0;
foreach (var item in HttpContext.Current.Request.Files)
{
var getFile = HttpContext.Current.Request.Files[count];
if (getFile != null)
{
var fileName = Path.GetFileName(getFile.FileName);
var path = Path.Combine(
HttpContext.Current.Server.MapPath("~/MrPerfectMaltipartFolder"),
fileName
);
getFile.SaveAs(path);
}
count++;
string file = "/MrPerfectMaltipartFolder/" + getFile.FileName;
FilesName.Add(file);
}
}
return FilesName;
}
Request Format:
Output:
Hope it would resolve your problem. Feel free to share if you still encounter any issues.
Correct API style :
[HttpPost("logfiles")] // etc
public async Task<IActionResult> AddLogFile(IFormFile reportFile)
{
//UploadFile with any options with correct property Name = "ReportFile"
// all assigment will do framework itself in default impl
if (reportFile == null || reportFile.Length <= 0)
{
Submit client side style :
using (MultipartFormDataContent httpContent = new MultipartFormDataContent())
{
// read bytes from memstream etc
//...
httpContent.Add((HttpContent) bytes, "ReportFile", "test.log");
Hi my xamarin post is not making it to my rest api.I keep getting "An error occure while sending the request" all my other posts work but just not this one. I have set network permissions as my login and geting data works. any help would be great. below is a code snippet.
public async Task<string> PostChecklist(string json)
{
try
{
JToken rootObject = JObject.Parse(json);
HttpClient httpClient = new HttpClient();
MultipartFormDataContent multipartContent = new MultipartFormDataContent();
httpClient.DefaultRequestHeaders.Add("Authorization", "Bearer " + TokenId);
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
string sFile = (string)rootObject["Answers"]["Signature"];
//Get file
if (!File.Exists((string)rootObject["Answers"]["Signature"]))
{
return "no signature found";
}
FileStream fs = File.OpenRead((string)rootObject["Answers"]["Signature"]);
StreamContent streamContent = new StreamContent(fs);
streamContent.Headers.Add("Content-Type", "application/octet-stream");
multipartContent.Add(streamContent, "signature", "signature.png");
#region Upload images
JToken jobectImages = rootObject["Images"];
foreach (var item in jobectImages)
{
foreach (var internalitem in item)
{
foreach (var imageGroup in internalitem)
{
foreach (JObject image in imageGroup)
{
JToken tokenName, tokenFileName;
image.TryGetValue("FileName", out tokenName);
image.TryGetValue("FilePath", out tokenFileName);
string FileName = tokenName.ToString();
string FilePath = tokenFileName.ToString();
//Get file
FileStream fs2 = File.OpenRead(FilePath);
StreamContent streamContent2 = new StreamContent(fs);
streamContent2.Headers.Add("Content-Type", "application/octet-stream");
multipartContent.Add(streamContent2, FileName, FileName);
}
}
}
}
#endregion
var contentJson = new StringContent(json);
contentJson.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "JSONString"
};
var contentLong = new StringContent("26");
contentLong.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "Long"
};
var contentLat = new StringContent("96");
contentLat.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "Lat"
};
multipartContent.Add(contentJson);
multipartContent.Add(contentLong);
multipartContent.Add(contentLat);
var response = await httpClient.PostAsync(GlobalVariables.url + "/checkurl/answers/v12", multipartContent).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
Information = await response.Content.ReadAsStringAsync();
JObject jsonOther = JObject.Parse(Information);
if(((String)jsonOther["status"]) == "success")
{
return "";
}
else
{
return (String)jsonOther["message"];
}
}
else{
return "Server Error";
}
}
catch(Exception e)
{
return e.ToString();
}
}
Cool Looks like there was a problem with one of my MultipartFormDataContent when trying to attach images, if i dont attach an image it does work, so the Url post was breaking. Simulator cant take images so never had the problem.. Thanks anyways
MultipartFormDataContent has a bug with how it generates request content based on the order the headers and body are added.
For example
StreamContent streamContent = new StreamContent(fs);
streamContent.Headers.Add("Content-Type", "application/octet-stream");
multipartContent.Add(streamContent, "signature", "signature.png");
Will cause the content type header to be added before the content disposition header,
-----------------------------some boundary value here
Content-Type: application/octet-stream
Content-Disposition: form-data; name=signature; filename=signature.png
which is known to cause issues with how some servers read the body/content of the request
Instead make sure to set the content composition header first and also make sure that the name and file name are wrapped in double quotes before adding it to the multi-part form data content
StreamContent streamContent = new StreamContent(fs);
streamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {
Name = "\"signature\"",
Filename = "\"signature.png\""
};
streamContent.Headers.Add("Content-Type", "application/octet-stream");
multipartContent.Add(streamContent);
The same will need to be done for the other section where images are added
//Get file
FileStream fs2 = File.OpenRead(FilePath);
StreamContent streamContent2 = new StreamContent(fs);
streamContent2.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data") {
Name = string.Format("\"{0}\"", FileName),
Filename = string.Format("\"{0}\"", FileName),
};
streamContent2.Headers.Add("Content-Type", "application/octet-stream");
multipartContent.Add(streamContent2);
I need help converting the follow Python code to c# .net. This code is posting/uploading a text file to a webserver. The Python script has been tested and works. I have tried a few solutions with HTTPClient and WebRequest with no luck. Any guidance will be greatly appreciated.
# request a session
client = requests.session()
# Establish the URL
newurl = 'https://localhost/filedist/upload/'
source_file = 'data/test.txt'
headers = {'Authorization': 'Token MYTOKEN'}
# Populate the values with our environment and target path
values = dict(environment='dev', path='Business/Tools')
files = dict(file=open(source_file, 'rb'))
r = client.post(newurl, files=files, data=values, headers=headers)
Here is my latest attempt, which currently is getting a 'Forbidden' error.
public static async Task<string> UploadFile(string path, string fileName)
{
var client = new HttpClient();
string NewURL = "https://localhost/filedist/upload/";
string SourceFile = path;
var content = new MultipartFormDataContent();
client.DefaultRequestHeaders.Add("Authorization", "Token MYTOKEN");
Stream fs = System.IO.File.Open(path, FileMode.Open, FileAccess.Read, FileShare.None);
content.Add(CreateFileContent(fs, fileName, "text/plain"));
var parameters = new Dictionary<string, string> { { "environment", "dev" }, { "path", "Business/Tools" } };
content.Add(new FormUrlEncodedContent(parameters));
var response = await client.PostAsync(NewURL, content);
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
string responseString = response.Content.ReadAsStringAsync().Result;
return "true";
}
else
{
return "false";
}
}
private static StreamContent CreateFileContent(Stream stream, string fileName, string contentType)
{
try
{
var fileContent = new StreamContent(stream);
fileContent.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
{
Name = "UploadedFile",
FileName = "\"" + fileName + "\""
};
fileContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
return fileContent;
}
catch (Exception ex)
{
return null;
}
}
Thanks
I am not 100% on this, but I don't think you can set the authorization header that way. Try using the client authorization header type.
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Token", "MYTOKEN");
I have a requirement to upload large files (upto 2GB) from my .NET web application to a java web service which in turn consumes a .jar file.
The java webservice API accepts MultipartFormDataContent as its parameter.
Problem I am facing is, I am unable to load the entire 2GB into a byte array as it throws "SystemOutOfMemoryException" when I attempt to upload a file anything larger that 300MB.
I also tried BufferedReader, StreamWriter but in vain.
Provided my code below for your reference:
public bool SendMessage(Dictionary<string, byte[]> files, string fromAddress, string toAddresses, string ccAddresses, string subject, string body)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
Dictionary<string, long> fileSizes = new Dictionary<string, long>();
Dictionary<string, ByteArrayContent> fileContent = new Dictionary<string, ByteArrayContent>();
HttpContent fileSizesContent = null;
try
{
HttpContent messageContent = new StringContent(jss.Serialize(new
{
to = toAddress,
cc = ccAddresses,
subject = subject,
body = "Test"
}));
if (files != null)
{
foreach (var entry in files)
{
fileSizes.Add(entry.Key, entry.Value.Length);
fileContent.Add(entry.Key, new ByteArrayContent(entry.Value));
}
fileSizesContent = new StringContent(jss.Serialize(fileSizes));
}
using (var client = new HttpClient())
{
using (var formData = new MultipartFormDataContent())
{
if (fileContent.Count > 0)
{
foreach (var entry in fileContent)
{
formData.Add(entry.Value, "attachments", entry.Key);
}
formData.Add(fileSizesContent, "fileSizes");
}
formData.Add(messageContent, "message");
var response = client.PostAsync(<java web service url>, formData).Result;
if (!response.IsSuccessStatusCode)
{
return false;
}
return true;
}
}
}
catch (Exception ex)
{
return false;
}
}
Issue is: I am unable to opulate the parameter ByteArrayContent as it throws SystemOutOfMemoeyException for files >300MB.
Please help me out.
Thanks.
I am trying to call the Web api method for saving the File Data.When I debug Webapi method I found that ContentLength is not coming as correct, because of this when i am retrieving the file it is showing error as corrupted file.
My Class method is :-
using (var formData = new MultipartFormDataContent())
{
HttpContent stringContent = new StringContent(file);
formData.Add(stringContent, "file", file);
formData.Add(new StringContent(JsonConvert.SerializeObject(file.Length)), "ContentLength ");
HttpResponseMessage responseFile = client.PostAsync("Report/SaveFile?docId=" + docId, formData).Result;
}
My Web api method is :-
[HttpPost]
public HttpResponseMessage SaveFile(long docId)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Unauthorized);
try
{
var httpRequest = HttpContext.Current.Request;
bool IsSuccess = true;
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
HttpPostedFile postedFile = httpRequest.Files[file];
// Initialize the stream.
Stream myStream = postedFile.InputStream;
myStream.Position = 0;
myStream.Seek(0, SeekOrigin.Begin);
var _item = CorrectedReportLibrary.Services.ReportService.SaveFile(myStream,docId);
response = Request.CreateResponse<bool>((IsSuccess)
? HttpStatusCode.OK
: HttpStatusCode.NoContent,
IsSuccess);
}
}
}
catch (Exception ex)
{
Theranos.Common.Library.Util.LogManager.AddLog(ex, "Error in CorrectedReportAPI.Controllers.SaveDocument()", null);
return Request.CreateResponse<ReportDocumentResult>(HttpStatusCode.InternalServerError, null);
}
return response;
}
How can I set the ContentLength from C# class method?
It looks a bit strange that you use ContentLength as the second parameter on the StringContent class. It is suppose to be which encoding you want to use, for example
new StringContent(content, Encoding.UTF8). I don't think it is the content length that is the issue here.
StringContent class
I guess since it is a file you want to upload, you already have the file read as a stream, so I usually do something like this:
Client:
private async Task UploadFile(MemoryStream file)
{
var client = new HttpClient();
var content = new MultipartFormDataContent();
content.Add(new StreamContent(file));
var result = await client.PostAsync("Report/SaveFile?docId=" + docId, content);
}
Edit. Since it's a multipartform it's easier to let the framework handle the details. Try something like this:
Server:
[HttpPost]
public async Task<HttpResponseMessage> SaveFile(long docId)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Unauthorized);
try
{
var filedata = await Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider());
foreach(var file in filedata.Contents)
{
var fileStream = await file.ReadAsStreamAsync();
}
response = Request.CreateResponse<bool>(HttpStatusCode.OK, true);
}
catch (Exception ex)
{
response = Request.CreateResponse<bool>(HttpStatusCode.InternalServerError, false);
}
return response;
}
At Last I found the solution no need to change the web api service,
issue was from client where I was directly passing the file data, Now the modified
working code is like this:-
using (var formData = new MultipartFormDataContent())
{
var bytes = File.ReadAllBytes(file);
formData.Add(new StreamContent(new MemoryStream(bytes)), "file", file);
HttpResponseMessage responseFile = client.PostAsync("ReportInfo/SaveFile?docId=" + docId, formData).Result;
}