ASP MVC Image upload error when using HttpClient.PostySync - c#

I have asp mvc web page to upload image, I need to validate the image width and height. I try to convert image from FromStream and than post it to server via PostSync method. I do not get any error but image is not posting to the server. If I bypass the FromStream method, than I do not see any error
public virtual ActionResult SaveFileConfigure(ConfigurationDto configuration, HttpPostedFileBase filePost)
{
System.IO.Stream stream = filePost.InputStream;
System.Drawing.Image image = System.Drawing.Image.FromStream(stream);
//check image width here
WebApiClient.UploadFile(this.FileService, stream, configuration.FileName);
}
Here is web api upload code
public static void UploadFile(string serviceUrl, Stream file, string fileName)
{
using (var client = new HttpClient())
{
using (var content = new MultipartFormDataContent())
{
var fileContent = new StreamContent(file);
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {
FileName = fileName
};
content.Add(fileContent);
var result = client.PostAsync(string.Format("{0}/upload", serviceUrl.TrimEnd('/')), content).Result;
}
}
}

I am able to fix the issue by using FromFile method.
System.Drawing.Image image = System.Drawing.Image.FromFile(filePost.FileName);
Looks like after I use FromStream method, the stream is getting closed and not able to post the file.

Related

IFormFileCollection is null when adding file to Flurl multi-part POST request

I am trying to upload a file using Flurl using AddFile.
The resulting IFormFileCollection is null, although I am able to see the item when looking at Request.Form.Files[0] with the right content length.
Creating the request:
public Task<HttpResponseMessage> UploadImage(string fileName, MemoryStream stream)
{
stream.Position = 0;
_baseUrl
.AppendPathSegments("uploadImage")
.PostMultipartAsync(mp => mp
.AddFile("files", stream, fileName))
}
Handling the request:
[HttpPost]
[Route("uploadImage")]
public async Task<HttpResponseMessage> UploadImages([FromForm] IFormFileCollection files)
{
//files is null, but Request.Form.Files[0] in the immediate window shows the file.
}
A common problem seems to be a mismatch in the name of the parameter and the name in the Content-Disposition header, but I updated them to both be files and I am still having the same issue.
That is strange that it works on my side :
MemoryStream ms = new MemoryStream();
using (FileStream file = new FileStream("txt.txt", FileMode.Open, FileAccess.Read))
file.CopyTo(ms);
ms.Position = 0;
var _baseUrl = "https://localhost:44392/";
var result = await _baseUrl
.AppendPathSegments("uploadImage")
.PostMultipartAsync(mp => mp
.AddFile("files", ms, "txt.txt"));
Result :
Please firstly try with a clean file and use await for handing request .

How to upload image of various type (jpg/png/gif) to the server through Stream using WCF web API

For some reason, Im using WCF for webAPIs..I have been using WCF for few days now. On the hunt to find the code to upload image to the server I found many answers and solutions like:
Could not upload Image to WCF Rest service
Uploading image as attachment in RESTful WCF Service
Uploading an image using WCF RESTFul service full working example
the above (full woking) example is working for me..accept for the part that it accepts only jpeg images. Since im using Postman to hit on the request, Stream datatype is accepting it and run to the program. Is there anyway to get a file type or file name from input stream data?
Following is the code
interface:
Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
string PostImage(Stream stream);
method implementation:
public string PostImage(Stream stream)
{
byte[] buffer = new byte[10000];
stream.Read(buffer, 0, 10000);
FileStream f = new FileStream("C:\\temp\\sample.jpg", FileMode.OpenOrCreate);
f.Write(buffer, 0, buffer.Length);
f.Close();
return "Recieved the image on server";
}
PS: im using postman request to send image like the following simple browse file option under byte section like this:
enter image description here
PS: Along with the image, I cannot pass the file name if even i want to, since Stream parameter does not allow any other parameter with it.
As joehoper mentioned, presently we could pass the additional information to the server by using Http header, please refer to my code design.
Server-side.
Service interface.
[OperationContract]
[WebInvoke(Method = "POST", ResponseFormat = WebMessageFormat.Json,BodyStyle =WebMessageBodyStyle.Bare)]
Task UploadStream(Stream stream);
Service implementation.
public async Task UploadStream(Stream stream)
{
var context = WebOperationContext.Current;
string filename = context.IncomingRequest.Headers["filename"].ToString();
string ext = Path.GetExtension(filename);
using (stream)
{
//save the image under the Uploads folder on the server-side(root directory).
using (var file = File.Create(Path.Combine(HostingEnvironment.MapPath("~/Uploads"), Guid.NewGuid().ToString() + ext)))
{
await stream.CopyToAsync(file);
}
}
}
Client-side.
The body section will post the binary data, just like you do.
Besides, WCF doesn’t support the form-data by default, while we could take advantage of the third-party library, which enables us to pass the form-data parameter.
https://archive.codeplex.com/?p=multipartparser
Then we could post form-data to transfer the file information. Please refer to the below code.
public async Task UploadStream(Stream stream)
{
MultipartParser parser = new MultipartParser(stream);
if (parser.Success)
{
//absolute filename, extension included.
var filename = parser.Filename;
var filetype = parser.ContentType;
var ext = Path.GetExtension(filename);
using (var file = File.Create(Path.Combine(HostingEnvironment.MapPath("~/Uploads"), Guid.NewGuid().ToString() +ext)))
{
await file.WriteAsync(parser.FileContents, 0, parser.FileContents.Length);
}
}
}
Finally, there is built-in support for passing the form-data in Asp.net WebAPI.
https://learn.microsoft.com/en-us/aspnet/web-api/overview/advanced/sending-html-form-data-part-2
Feel free to let me know if there is anything I can help with.
The stream will only contain the bytes in the body of the request which will be the contents file only, no extra metadata like its filename. You can add custom headers to your request that specify the filename and any other info you'd like and read them from the request context in your method:
public string PostImage(Stream stream)
{
var context = WebOperationContext.Current;
string filename = context.IncomingRequest.Headers["Filename"].ToString();
string extraInfo = context.IncomingRequest.Headers["Extra-Info"].ToString();
byte[] buffer = new byte[10000];
stream.Read(buffer, 0, 10000);
FileStream f = new FileStream("C:\\temp\\sample.jpg", FileMode.OpenOrCreate);
f.Write(buffer, 0, buffer.Length);
f.Close();
return "Recieved the image on server";
}

Microsoft Cognitive Services Vision API: Sending multipart data

I am trying to call the Microsoft Cognitive API by passing multiple images as per documentation and using the multipart/form-data, but I am getting an error that says "Unsupported Media Type". I have tried to use both ByteArray and StreamContent.
Api documentation.
private static byte[] GetImageAsByteArray(Stream fileStream)
{
using (var binaryReader = new BinaryReader(fileStream))
{
return binaryReader.ReadBytes((int)fileStream.Length);
}
}
static void Main(string[] args)
{
var uriBase = "https://westus.api.cognitive.microsoft.com/vision/v1.0/recognizeText";
var subscriptionKey = "<subscriptionKey>";
var client = new HttpClient();
var uri = string.Concat(uriBase, "?", "language=en&detectOrientation=true");
var images = new List<Stream>();
var img = Image.FromStream(File.Open("<imageName>", FileMode.Open));
var stream = new MemoryStream();
img.Save(stream, ImageFormat.Bmp);
stream.Position = 0;
images.Add(stream);
using (var content = new MultipartFormDataContent())
{
foreach (var image in images)
{
//content.Add(new StreamContent(stream));
content.Add(new ByteArrayContent(GetImageAsByteArray(image)));
}
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
content.Headers.ContentType = new MediaTypeHeaderValue("multipart/form-data");
var response = client.PostAsync(uri, content).Result;
}
}
I am trying to call the Microsoft Cognitive API by passing multiple images as per documentation and using the multipart/form-data, but I am getting an error that says "Unsupported Media Type".
It is not possible to send multiple images, regardless of header.
Please refer to the documentation Step 2, it mentions:
The basic way to perform the Computer Vision API call is by uploading an image directly. This is done by sending a "POST" request with application/octet-stream content type together with the data read from the image.
Example code can be found here
Test environment here.
Notice regardless of header, it is still sending 1 image.
The limits also mention a single image.

Tweetsharp SendTweetWithMedia from url

I am trying to use Tweetsharp's SendTweetWithMedia with a image which I don't have stored locally, I only have a url. All the examples I have found of SendTweetWithMedia use a file on the local system.
var thumb = "http://somesite.net/imageurl";
var service = new TwitterService(key, secret);
service.AuthenticateWith(token, tokenSecret);
var req = WebRequest.Create(thumb);
using (var stream = req.GetResponse().GetResponseStream())
{
response = service.SendTweetWithMedia(new SendTweetWithMediaOptions
{
Status = tweet.Trim(),
Images = new Dictionary<string, Stream> { { fullname, stream } }
});
}
I get the following error from SendTweetWithMedia:
'System.NotSupportedException': This stream does not support seek operations.
I could download the file from the url and save locally, but I'd rather use the url. Is this possible?
In the end, I just created a temporary file:
byte[] data;
using (var client = new WebClient())
{
data = client.DownloadData(thumb);
}
File.WriteAllBytes($"{Path.GetTempPath()}\\xyz.jpg", data);
best answer I could come up with. Still a few more lines than I'd like though.

Using CSVHelper to output stream to browser but unable to save file

I am trying to achieve exactly what the poster in this question is trying to do except the browser (Chrome) doesn't attempt to download the .csv file or present the user with a download box. I am using a HTTP GET request and the code is virtually identical in the question above. I'm using Fiddler to monitor the traffic and I can see the .csv file stream in the response, but the browser seems to be ignore it and I can't work out why...
Here is my current implemenation (base on #MattThrower's question):
I make an AJAX call to the MVC controller:
$("#exportToCsvLink").click(function () {
$.ajax({
type: "GET",
url: window.project.common.routes.urls.ExportChartDataToCsv,
data: { parameterId: parameter.parameterId }
});
});
The MVC controller processes the CSV export and returns a FileStreamResult
public FileStreamResult ExportChartDataToCsv(int parameterId)
{
List<TestViewModel> data = _CommonService.GetData(parameterId);
var result = WriteCsvToMemory(data);
var memoryStream = new MemoryStream(result);
return new FileStreamResult(memoryStream, "text/csv") { FileDownloadName = "export.csv" };
}
public byte[] WriteCsvToMemory(IEnumerable<TestViewModel> data)
{
using (var memoryStream = new MemoryStream())
using (var streamWriter = new StreamWriter(memoryStream))
using (var csvWriter = new CsvWriter(streamWriter))
{
csvWriter.WriteRecords(data);
streamWriter.Flush();
return memoryStream.ToArray();
}
}

Categories