JSON input for Upload function in WebApi C# - asp.net-web-api

I have an upload function in my WebApi C# code, which works fine with Query string parameters. I will be passing the file in Rest client using multi-Form data and it works completely fine.
Now I have to change the parameters to JSON format, doing so the request is not hitting the controller. Can anyone please help me here.
public ReturnMsg UploadDocument(string fileName, string fileSize, string ApplNo, string DocId, string DocSize,string resumeId,string DependId)
{
ReturnMsg objReturnMsg = new ReturnMsg ();
HttpResponseMessage response = new HttpResponseMessage();
var httpRequest = HttpContext.Current.Request;
Stream stream = null;
if (httpRequest.Files.Count > 0)
{
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = string.Empty;
stream = postedFile.InputStream;
}
objReturnMsg = Bll.UploadFiles(fileName, fileSize, DocId, DocSize,DependId,stream);
}
else
{
objReturnMsg.Status = "F";
objReturnMsg.ReturnMessage = "Please Upload a Valid Form";
}
return objReturnMsg;
}
I want it in
public ReturnMsg UploadDocument(DocDetails docDet)
{
ReturnMsg objReturnMsg = new ReturnMsg ();
HttpResponseMessage response = new HttpResponseMessage();
var httpRequest = HttpContext.Current.Request;
Stream stream = null;
if (httpRequest.Files.Count > 0)
{
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
var filePath = string.Empty;
stream = postedFile.InputStream;
}
objReturnMsg = Bll.UploadFiles(docDet.fileName, docDet.fileSize, docDet.DocId, docDet.DocSize,docDet.DependId,stream);
}
else
{
objReturnMsg.Status = "F";
objReturnMsg.ReturnMessage = "Please Upload a Valid Form";
}
return objReturnMsg;
}

Related

xamarin.forms - Upload multiple images and files using multipart/form data

In my xamarin.forms app. I am using Media.plugin to select images from gallery and camera.And also file picker plugin to select files like pdf,jpg etc from file manager.User can select multiple images and files and It will store in an observable collection.In this observable collection I have the path of images as well as files. Where I am stuck is I want to send these data to rest API by using multipart/form data.How can I send these multiple files to the server? Any help is appreciated.
My ObservableCollection
public ObservableCollection<SelectedDocumentModel> DataManager
{
get
{
return _selectedfile ?? (_selectedfile = new ObservableCollection<SelectedDocumentModel>());
}
}
My Data Model
public class SelectedDocumentModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string FileName { get; set; }
public string Path { get; set; }
public ImageSource SelectedImage { get; set; }
public object Tasks { get; internal set; }
private bool isLoadingVisible = false;
public bool IsLoadingVisible
{
get
{
return isLoadingVisible;
}
set
{
if (value != null)
{
isLoadingVisible = value;
NotifyPropertyChanged("IsLoadingVisible");
}
}
}
}
Selecting image using media.plugin and allocating to my observable collection
var Filename = Path.GetFileName(file.Path);
var FilePath = file.Path;
var newList = new SelectedDocumentModel()
{
FileName = Filename,
SelectedImage = imageSource,
IsLoadingVisible = false,
Path = FilePath
};
DataManager.Add(newList);
Selecting file from file manager using filepicker plugin and assign to observablecollection
var FilePath = pickedFile.FilePath;
var newList = new SelectedDocumentModel()
{
FileName = filename,
SelectedImage = imageSource,
IsLoadingVisible = false,
Path= FilePath
};
DataManager.Add(newList);
EDIT
This is what I should do using httpclient.Currently these are written using RestSharp.
var client = new RestClient("{{api_url}}/MYData");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "bearer {{token}}");
request.AddHeader("Content-Type", "application/json");
request.AlwaysMultipartFormData = true;
request.AddParameter("ids", " [{\"id\":1,\"person_id\":5}]");
request.AddParameter("title", " Test");
request.AddParameter("description", " Test");
request.AddParameter("send_text_message", " true");
request.AddParameter("text_message", " Test");
request.AddParameter("notification_type"," global");
request.AddParameter("my_files", "[
{
\"name\": \"abc.jpg\",
\"key\": \"1583307983694\"
}
]");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
What I have done by the way suggested by Lucas Zhang - MSFT.
try {
MultipartFormDataContent multiContent = new MultipartFormDataContent();
foreach (SelectedDocumentModel model in SelectedFileData)
{
byte[] byteArray = Encoding.UTF8.GetBytes(model.Path);
MemoryStream stream = new MemoryStream(byteArray);
HttpContent fileStreamContent1 = new StreamContent(stream);
fileStreamContent1.Headers.ContentDisposition = new
System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
{
Name = model.FileName,
FileName = model.FileName
};
fileStreamContent1.Headers.ContentType = new
System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
multiContent.Add(fileStreamContent1);
}
multiContent.Add(new StringContent(notificationdetails[0]), "title");
multiContent.Add(new StringContent(notificationdetails[1]), "description");
multiContent.Add(new StringContent(notificationdetails[3]), "type");
multiContent.Add(new StringContent(notificationdetails[7]), "send_text_message");
multiContent.Add(new StringContent(notificationdetails[2]), "text_message");
multiContent.Add(new StringContent(notificationdetails[8]), "send_email");
multiContent.Add(new StringContent(notificationdetails[9]), "notification_type");
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("bearer",Settings.AuthToken);
var response = await client.PostAsync(url, multiContent);
var responsestr = response.Content.ReadAsStringAsync().Result;
await DisplayAlert("Result", responsestr.ToString(), "ok");
}
catch (Exception ex)
{
await DisplayAlert("Result", ex.Message.ToString(), "ok");
}
unfortunately it not working.It not sending the data as I intend.
How can I upload each files as multipart/formdata on a button click.?Any help is appriciated.
You could use MultipartFormDataContent to add multiple images,and use ContentDispositionHeaderValue.Parameters to add the values of your Data.
Usage
var fileStream = pickedFile.GetStream();
var newList = new SelectedDocumentModel()
{
FileName = filename,
SelectedImage = imageSource,
IsLoadingVisible = false,
Path= FilePath,
Data = fileStream ,
};
MultipartFormDataContent multiContent = new MultipartFormDataContent();
foreach(var SelectedDocumentModel model in DataManager)
{
HttpContent fileStreamContent1 = new StreamContent(model.Data);
fileStreamContent1.Headers.ContentDisposition = new
System.Net.Http.Headers.ContentDispositionHeaderValue("form-data")
{
Name = "File",
FileName = "xxx.jpg"
};
fileStreamContent1.Headers.ContentType = new
System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
multiContent.Add(fileStreamContent1);
multiContent.Add(new StringContent(model.Title), "model.Title");
multiContent.Add(new StringContent(model.Description), "model.Description");
multiContent.Add(new StringContent(model.Detail), "model.Detail");
}
// Send (url = url of api) ,use httpclient
var response = await client.PostAsync(url, multiContent);

Save files in asp.net folder with reference in the database from a desktop client

ASP.NET WEB API: Hi, I would like to know to save files in asp.net web api folder with the link reference in database from desktop client. I searched it online and got some implementation still it's not workin.
Below are what I got so far. I hope someone can help me out with that.
Your contribution will really help.
My api controller code
[HttpPost]
public HttpResponseMessage PostFile()
{
HttpResponseMessage result = null;
var httpRequest = HttpContext.Current.Request;
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
var postedFile = httpRequest.Files[file];
if (postedFile != null)
{
var filePath = HttpContext.Current.Server.MapPath("~/files" + postedFile.FileName);
postedFile.SaveAs(filePath);
docfiles.Add(filePath);
}
}
result = Request.CreateResponse(HttpStatusCode.Created, docfiles);
}
else
{
result = Request.CreateResponse(HttpStatusCode.BadRequest);
}
return result;
}
My client side code
OpenFileDialog fd = new OpenFileDialog();
private void btnUpload_Click(object sender, EventArgs e)
{
bool uploadStatus = false;
fd.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp;)|*.jpg; *jpeg; *.gif; *.bmp;";
fd.Title = "Choose image";
if (fd.ShowDialog() == DialogResult.OK)
{
picUpload.Image = new Bitmap(fd.FileName);
foreach(String localfile in fd.FileNames)
{
var url = "url";
var filepath = #"\";
Random ran = new Random();
var uploadFileName = "img" + ran.Next(999).ToString();
uploadStatus = UploadConfig(url, filepath, localfile, uploadFileName);
}
}
if (uploadStatus)
{
MessageBox.Show("Successful");
}
else
{
MessageBox.Show("Failed");
}
}
bool UploadConfig(string url, string filePath, string localFileName, string UploadFileName)
{
bool isFileUploaded = false;
try
{
using (HttpClient client = new HttpClient())
{
var fs = File.Open(localFileName, FileMode.Open);
var fi = new FileInfo(localFileName);
UploadDetails uploadDetails = null;
bool fileUpload = false;
MultipartFormDataContent content = new MultipartFormDataContent();
content.Headers.Add("filePath",filePath);
content.Add(new StreamContent(fs), "\"files\"",
string.Format("\"{0}\"", UploadFileName + fi.Extension));
Task taskUpload = client.PostAsync(url, content).ContinueWith(task =>
{
if(task.Status == TaskStatus.RanToCompletion)
{
var res = task.Result;
if (res.IsSuccessStatusCode)
{
uploadDetails = res.Content.ReadAsAsync<UploadDetails>().Result;
if (uploadDetails != null)
{
fileUpload = true;
}
}
}
fs.Dispose();
});
taskUpload.Wait();
if (fileUpload)
{
isFileUploaded = true;
client.Dispose();
}
}
}
catch (Exception e)
{
isFileUploaded = false;
}
return isFileUploaded;
}

MVC 6 HttpPostedFileBase?

I am attempting to upload an image using MVC 6; however, I am not able to find the class HttpPostedFileBase. I have checked the GitHub and did not have any luck. Does anyone know the correct way to upload a file in MVC6?
MVC 6 used another mechanism to upload files. You can get more examples on GitHub or other sources. Just use IFormFile as a parameter of your action or a collection of files or IFormFileCollection if you want upload few files in the same time:
public async Task<IActionResult> UploadSingle(IFormFile file)
{
FileDetails fileDetails;
using (var reader = new StreamReader(file.OpenReadStream()))
{
var fileContent = reader.ReadToEnd();
var parsedContentDisposition = ContentDispositionHeaderValue.Parse(file.ContentDisposition);
var fileName = parsedContentDisposition.FileName;
}
...
}
[HttpPost]
public async Task<IActionResult> UploadMultiple(ICollection<IFormFile> files)
{
var uploads = Path.Combine(_environment.WebRootPath,"uploads");
foreach(var file in files)
{
if(file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
await file.SaveAsAsync(Path.Combine(uploads,fileName));
}
...
}
}
You can see current contract of IFormFile in asp.net sources. See also ContentDispositionHeaderValue for additional file info.
There is no HttpPostedFileBase in MVC6. You can use IFormFile instead.
Example: https://github.com/aspnet/Mvc/blob/dev/test/WebSites/ModelBindingWebSite/Controllers/FileUploadController.cs
Snippet from the above link:
public FileDetails UploadSingle(IFormFile file)
{
FileDetails fileDetails;
using (var reader = new StreamReader(file.OpenReadStream()))
{
var fileContent = reader.ReadToEnd();
var parsedContentDisposition = ContentDispositionHeaderValue.Parse(file.ContentDisposition);
fileDetails = new FileDetails
{
Filename = parsedContentDisposition.FileName,
Content = fileContent
};
}
return fileDetails;
}
I was searching around for quite a while trying to piece this together in .net core and ended up with the below. The Base64 conversion will be next to be done so that the retrieval and display is a little easier. I have used IFormFileCollection to be able to do multiple files.
[HttpPost]
public async Task<IActionResult> Create(IFormFileCollection files)
{
Models.File fileIn = new Models.File();
if(model != null && files != null)
{
foreach (var file in files)
{
if (file.Length > 0)
{
var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
byte[] fileBytes = null;
using (var fileStream = file.OpenReadStream())
using (var ms = new MemoryStream())
{
fileStream.CopyTo(ms);
fileBytes = ms.ToArray();
//string s = Convert.ToBase64String(fileBytes);
// act on the Base64 data
}
fileIn.Filename = fileName;
fileIn.FileLength = Convert.ToInt32(file.Length);
fileIn.FileType = file.ContentType;
fileIn.FileTypeId = model.FileTypeId;
fileIn.FileData = fileBytes;
_context.Add(fileIn);
await _context.SaveChangesAsync();
}
}
}
return View();
}
EDIT
And below is return of files to a list and then download.
public JsonResult GetAllFiles()
{
var files = _context.File
.Include(a => a.FileCategory)
.Select(a => new
{
id = a.Id.ToString(),
fileName = a.Filename,
fileData = a.FileData,
fileType = a.FileType,
friendlyName = a.FriendlyName,
fileCategory = a.FileCategory.Name.ToLower()
}).ToList();
return Json(files);
}
public FileStreamResult DownloadFileById(int id)
{
// Fetching file encoded code from database.
var file = _context.File.SingleOrDefault(f => f.Id == id);
var fileData = file.FileData;
var fileName = file.Filename;
// Converting to code to byte array
byte[] bytes = Convert.FromBase64String(fileData);
// Converting byte array to memory stream.
MemoryStream stream = new MemoryStream(bytes);
// Create final file stream result.
FileStreamResult fileStream = new FileStreamResult(stream, "*/*");
// File name with file extension.
fileStream.FileDownloadName = fileName;
return fileStream;
}

Why am I getting a "NotSupportedException" with this code?

I am trying to call a Web API method from a handheld device (Compact Framework) with this code:
// "fullFilePath" is a value such as "\Program Files\Bla\abc.xml"
// "uri" is something like "http://localhost:28642/api/ControllerName/PostArgsAndXMLFile?serialNum=8675309&siteNum=42"
SendXMLFile(fullFilePath, uri, 500);
. . .
public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
uri = uri.Replace('\\', '/');
if (!uri.StartsWith("/"))
{
uri = "/" + uri;
}
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(xmlFilepath))
{
String line;
while ((line = sr.ReadLine()) != null)
{
sb.AppendLine(line);
}
byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());
if (timeout < 0)
{
request.ReadWriteTimeout = timeout;
request.Timeout = timeout;
}
request.ContentLength = postBytes.Length;
request.KeepAlive = false;
request.ContentType = "application/x-www-form-urlencoded"; // not "text/xml" correct?
try
{
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
request.Abort();
return string.Empty;
}
}
}
Somewhere in SendXMLFile(), it is failing with "NotSupportedException" though... As it's running on a handheld device, I can't put a breakpoint in it and step through it; I could sprinkle a bunch of debug statements throughout (MessageBox.Show()), but I'd rather not do that.
The server code never even reaches the breakpoint I put on the "XDocument doc =" line below:
[Route("api/ControllerName/PostArgsAndXMLFile")]
public void PostArgsAndFile([FromBody] string stringifiedXML, string serialNum, string siteNum)
{
XDocument doc = XDocument.Parse(stringifiedXML);
Is it that the Compact framework can't call a (RESTful) Web API method for some reason? Obviously, the client (handheld/Compact Framework) compiles and runs, it just refuses to actually follow through with the runtime realities of it all.
Does my code require a small alteration for it to fit, or do I need to take a completely different tack?
Web API is not going to be able to handle your body content. You declared it as application/x-form-urlencoded, but it is actually XML formatted and your method signature is expecting it to be a XMLDataContract serialized string.
Instead of using the parameter stringifiedXML, instead, just read the body inside your method..
[Route("api/ControllerName/PostArgsAndXMLFile")]
public async void PostArgsAndFile(string serialNum, string siteNum)
{
XDocument doc = XDocument.Parse(await Request.Content.ReadAsStringAsync());
}
Or event better, use a stream directly.
[Route("api/ControllerName/PostArgsAndXMLFile")]
public async void PostArgsAndFile(string serialNum, string siteNum)
{
XDocument doc = XDocument.Load(await Request.Content.ReadAsStreamAsync());
}
This way, you can put the ContentType on the client back to application/xml as it should be.
Using Darrel's code on the server side (I'm using the second one, the Stream), this works on the Client side:
public static string SendXMLFile(string xmlFilepath, string uri, int timeout)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.ContentType = "application/xml";
request.Method = "POST";
StringBuilder sb = new StringBuilder();
using (StreamReader sr = new StreamReader(xmlFilepath))
{
String line;
while ((line = sr.ReadLine()) != null)
{
sb.AppendLine(line);
}
byte[] postBytes = Encoding.UTF8.GetBytes(sb.ToString());
if (timeout < 0)
{
request.ReadWriteTimeout = timeout;
request.Timeout = timeout;
}
request.ContentLength = postBytes.Length;
request.KeepAlive = false;
request.ContentType = "application/x-www-form-urlencoded";
try
{
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();
using (var response = (HttpWebResponse)request.GetResponse())
{
return response.ToString();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
request.Abort();
return string.Empty;
}
}
}
Which can be called like so:
private void buttonNose_Click(object sender, EventArgs e)
{
String fullFilePath = #"C:\McMurtry\LonesomeDove.XML";
String uri = #"http://localhost:21608/api/inventory/sendxml/ff/gg/42";
SendXMLFile(fullFilePath, uri, 500);
}

Passing cookies to Image.GetInstance

Using image handler to convert relative path to absolute.
protected byte[] ConvertHTMLToPDF(string HTMLCode)
{
if (Request.Url == null)
throw new Exception();
var doc = new Document(PageSize.A4);
doc.Open();
var interfaceProps = new Hashtable();
var ih = new ImageHander {BaseUri = Request.Url.ToString()};
interfaceProps.Add("img_provider", ih);
foreach (IElement element in HTMLWorker.ParseToList(new StringReader(HTMLCode), null, interfaceProps))
{
doc.Add(element);
}
var _xmlr = new XmlTextReader(new StringReader(HTMLCode));
HtmlParser.Parse(doc, _xmlr);
var stream = new MemoryStream();
PdfWriter.GetInstance(doc, stream);
doc.Close();
return stream.ToArray();
}
class:
public class ImageHander : IImageProvider
{
public string BaseUri;
public Image GetImage(string src, Hashtable h, ChainedProperties cprops, IDocListener doc)
{
string imgPath;
if (src.ToLower().Contains("http://") == false)
imgPath = HttpContext.Current.Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority + src;
else
imgPath = src;
return Image.GetInstance(imgPath);
}
}
imgPath at the end is correct. But it's not static file, it's url of action that returns image, so I need to pass cookies when requesting image. Is it possible?
Yes, it is possible, but you're gonna have to send the request yourself and not rely on the Image.GetInstance method. For example using the HttpClient you could send cookies along with the request:
var imageUrl = new Uri(imagePath);
var cookieContainer = new CookieContainer();
using (var handler = new HttpClientHandler { CookieContainer = cookieContainer })
using (var client = new HttpClient(handler))
{
cookieContainer.Add(
new Uri(imageUrl.GetLeftPart(UriPartial.Authority)),
new Cookie("CookieName", "cookie_value")
);
var response = client.GetAsync(imageUrl).Result;
response.EnsureSuccessStatusCode();
Stream imageStream = response.Content.ReadAsStreamAsync().Result;
// You've got the Stream here, read the documentation of iTextSharp
// how to create an Image instance from a Stream:
return Image.FromStream(imageStream); // ?????
// or maybe there's a method allowing you to create an Image from byte[]
byte[] imageData = new byte[imageStream.Length];
imageStream.Read(imageData, 0, imageData.Length);
return Image.FromByteArray(imageData); // ?????
}

Resources