Uploading file from iOS to MVC controller - ios

I have a very simple file upload method on my MVC controller which works very well when uploading images from the browsers on my PC.
Uploading Code :
[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase file, string encodedId)
However, if I try to upload an image from my iPhone I get error as
No route in the route table matches the supplied values
I tried removing the parameters from the method and instead accessing the data from the Request object:
Modified Code :
[HttpPost]
public ActionResult FileUpload()
{
var file = HttpContext.Request.Files[0];
string encodedId = HttpContext.Request.Form["EncodedId"];
This results in the same error.
I cant't ascertain what the iPhone is sending to the server as I don't have any kind of development tools on my iPhone.

I name my File which i am sending as File and get it via following code.
[HttpPost]
[Route("UploadAttachment")]
public IHttpActionResult UploadAttachment()
{
try
{
HttpPostedFile File = HttpContext.Current.Request.Files.Count > 0 ?
HttpContext.Current.Request.Files.Get("File") : null;
if (File != null)
{
Uploader uploader = new Uploader();
var Result = uploader.uploadToServer(File);
return Ok(Result);
}
else
{
return BadRequest("File is Required");
}
}
catch (Exception ex)
{
return InternalServerError(ex);
}
}

Related

Cannot get a response from a Web API call

I have the following in the TreeController controller in a small web API:
[HttpGet("GetDirectories")]
public IActionResult GetDirectories()
{
var baseDir = _config["QuickShare:BaseDir"];
if (string.IsNullOrWhiteSpace(baseDir))
{
throw new InvalidOperationException("'QuickShare:BaseDir' is not configured");
}
var ret = GetDirectories(baseDir); ;
return Json(ret);
}
private List<DirectoryInfo> GetDirectories(string parentDir)
{
var dirInfo = new DirectoryInfo(parentDir);
return dirInfo.GetDirectories("*", SearchOption.TopDirectoryOnly).ToList();
}
When I try and call this action from Postman, I get told
Could not get any response There was an error connecting to
http://localhost:59243/api/Tree/GetDirectories.
Now the default, test, controller that comes with the project template is unchanged:
[Route("api/[controller]")]
public class ValuesController : Controller
{
// GET api/values
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] {"value1", "value2"};
}
...
}
And when I have the API running in Visual Studio, I can get a proper response from the Values controller, but not from the TreeController, yet they are almost exactly the same. And, when I call the Tree/GetDirectories` action, a breakpoint in that action method is hit, and I can single step through the very few lines that my method has, and they all execute fine.
The problem only becomes apparent when that last line of the action executes:
return Json(ret);
Then I get shown that Postman Could not get any response despite no exception being raised; while debugging the code, it looks like everything should work fine, and the requests to the Values controller work fine.
Your action method should return either the specific result type (JsonResult when you return Json ) or IActionResult.
Example:
[HttpGet("GetDirectories")]
public JsonResult GetDirectories()
{
var baseDir = _config["QuickShare:BaseDir"];
if (string.IsNullOrWhiteSpace(baseDir))
{
throw new InvalidOperationException("'QuickShare:BaseDir' is not configured");
}
var ret = GetDirectories(baseDir);
return Json(ret);
}
OR
[HttpGet("GetDirectories")]
public IActionResult GetDirectories()
{
var baseDir = _config["QuickShare:BaseDir"];
if (string.IsNullOrWhiteSpace(baseDir))
{
throw new InvalidOperationException("'QuickShare:BaseDir' is not configured");
}
var ret = GetDirectories(baseDir) ;
return Ok(ret);
}
You can get more help from Microsoft Documentation: Formatting Response Data

Return View not refreshing browser

I am having a problem with return this.View("Index",model) (after the database processing) refreshing the browser when I upload an 80Mb file. The code works fine on smaller files. The code also works when I upload an 80Mb file with the debugger attached to w3wp.exe and manually step through it. I have tried multiple browsers and have the same problem across all of them.
[HttpPost]
public ActionResult Index(ImportDataViewModel model)
{
string importFileLoc = string.Empty;
if (Request.Files.Count != 0)
{
importFileLoc = this.SaveTempFile(Request.Files[0]);
}
if (!this.ValidateImportModel(model))
{
model.SystemNames = this.GetSystemNames().SetSelected(model.SelectedSystem);
return this.View(model);
}
// Do Database and other data processing here
if (!ModelState.IsValid || model.ContainsWarnings)
{
model.SystemNames = this.GetSystemNames(model.SelectedSystem);
return this.View("Index", model);
}
return this.RedirectToAction("Index");
}

Stream file using ASP.NET MVC FileContentResult in a browser with a name?

Is there a way to stream a file using ASP.NET MVC FileContentResult within the browser with a specific name?
I have noticed that you can either have a FileDialog (Open/Save) or you can stream the file in a browser window, but then it will use the ActionName when you try to save the file.
I have the following scenario:
byte[] contents = DocumentServiceInstance.CreateDocument(orderId, EPrintTypes.Quote);
result = File(contents, "application/pdf", String.Format("Quote{0}.pdf", orderId));
When I use this, I can stream the bytes, but a OPEN/SAVE file dialog is given to the user. I would like to actually stream this file in a browser window.
If I just use the FilePathResult, it shows the file in a browser window, but then when I click on "Save" button to save the file in PDF, it shows me the Action Name as the name of the file.
Has anyone encountered this?
public ActionResult Index()
{
byte[] contents = FetchPdfBytes();
return File(contents, "application/pdf", "test.pdf");
}
and for opening the PDF inside the browser you will need to set the Content-Disposition header:
public ActionResult Index()
{
byte[] contents = FetchPdfBytes();
Response.AddHeader("Content-Disposition", "inline; filename=test.pdf");
return File(contents, "application/pdf");
}
Actually, the absolutely easiest way is to do the following...
byte[] content = your_byte[];
FileContentResult result = new FileContentResult(content, "application/octet-stream")
{
FileDownloadName = "your_file_name"
};
return result;
This might be helpful for whoever else faces this problem. I finally figured out a solution. Turns out, even if we use the inline for "content-disposition" and specify a file name, the browsers still do not use the file name. Instead browsers try and interpret the file name based on the Path/URL.
You can read further on this URL:
Securly download file inside browser with correct filename
This gave me an idea, I just created my URL route that would convert the URL and end it with the name of the file I wanted to give the file. So for e.g. my original controller call just consisted of passing the Order Id of the Order being printed. I was expecting the file name to be of the format Order{0}.pdf where {0} is the Order Id. Similarly for quotes, I wanted Quote{0}.pdf.
In my controller, I just went ahead and added an additional parameter to accept the file name. I passed the filename as a parameter in the URL.Action method.
I then created a new route that would map that URL to the format:
http://localhost/ShoppingCart/PrintQuote/1054/Quote1054.pdf
routes.MapRoute("", "{controller}/{action}/{orderId}/{fileName}",
new { controller = "ShoppingCart", action = "PrintQuote" }
, new string[] { "x.x.x.Controllers" }
);
This pretty much solved my issue.
Previous answers are correct: adding the line...
Response.AddHeader("Content-Disposition", "inline; filename=[filename]");
...will causing multiple Content-Disposition headers to be sent down to the browser. This happens b/c FileContentResult internally applies the header if you supply it with a file name. An alternative, and pretty simple, solution is to simply create a subclass of FileContentResult and override its ExecuteResult() method. Here's an example that instantiates an instance of the System.Net.Mime.ContentDisposition class (the same object used in the internal FileContentResult implementation) and passes it into the new class:
public class FileContentResultWithContentDisposition : FileContentResult
{
private const string ContentDispositionHeaderName = "Content-Disposition";
public FileContentResultWithContentDisposition(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
: base(fileContents, contentType)
{
// check for null or invalid ctor arguments
ContentDisposition = contentDisposition;
}
public ContentDisposition ContentDisposition { get; private set; }
public override void ExecuteResult(ControllerContext context)
{
// check for null or invalid method argument
ContentDisposition.FileName = ContentDisposition.FileName ?? FileDownloadName;
var response = context.HttpContext.Response;
response.ContentType = ContentType;
response.AddHeader(ContentDispositionHeaderName, ContentDisposition.ToString());
WriteFile(response);
}
}
In your Controller, or in a base Controller, you can write a simple helper to instantiate a FileContentResultWithContentDisposition and then call it from your action method, like so:
protected virtual FileContentResult File(byte[] fileContents, string contentType, ContentDisposition contentDisposition)
{
var result = new FileContentResultWithContentDisposition(fileContents, contentType, contentDisposition);
return result;
}
public ActionResult Report()
{
// get a reference to your document or file
// in this example the report exposes properties for
// the byte[] data and content-type of the document
var report = ...
return File(report.Data, report.ContentType, new ContentDisposition {
Inline = true,
FileName = report.FileName
});
}
Now the file will be sent to the browser with the file name you choose and with a content-disposition header of "inline; filename=[filename]".
I hope that helps!
The absolute easiest way to stream a file into browser using ASP.NET MVC is this:
public ActionResult DownloadFile() {
return File(#"c:\path\to\somefile.pdf", "application/pdf", "Your Filename.pdf");
}
This is easier than the method suggested by #azarc3 since you don't even need to read the bytes.
Credit goes to: http://prideparrot.com/blog/archive/2012/8/uploading_and_returning_files#how_to_return_a_file_as_response
** Edit **
Apparently my 'answer' is the same as the OP's question. But I am not facing the problem he is having. Probably this was an issue with older version of ASP.NET MVC?
I adapted it in ASP.NET Core with REST API.
public class FileContentWithFileNameResult : FileContentResult
{
public FileContentWithFileNameResult(byte[] fileContents, string contentType, string fileName)
: base(fileContents, contentType)
{
FileName = fileName;
}
public string FileName { get; private set; }
public override Task ExecuteResultAsync(ActionContext context)
{
var response = context.HttpContext.Response;
response.Headers.Append("Content-Disposition", $"inline; filename={FileName}");
response.Headers.Append("Access-Control-Expose-Headers", "Content-Disposition");
response.Headers.Append("X-Content-Type-Options", "nosniff");
return base.ExecuteResultAsync(context);
}
}
public FileContentResult GetImage(int productId) {
Product prod = repository.Products.FirstOrDefault(p => p.ProductID == productId);
if (prod != null) {
return File(prod.ImageData, prod.ImageMimeType);
} else {
return null;
}
}

simple image upload in aspnet mvc

i'm building a simple school portal, i have stucked at uploading an image into my application, i.e a user should upload school image to my server, i have directory for images as ./Content/Images -- all uploading images should be uploaded to this directory. i have following code
input type="file" id="SchoolImageUrl" name="SchoolImageUrl" class="required"
using this m'getting a browse button, i have no idea how to upload that image to server and how would be my action controller ? i have following controller for creating school
public ActionResult SchoolCreate(_ASI_School schoolToCreate, FormCollection collection)
{
if (!ModelState.IsValid)
return View();
try
{
// TODO: Add insert logic here
schoolToCreate.SchoolId = Guid.NewGuid().ToString();
schoolToCreate.UserId = new Guid(Request.Form["currentUser"]);
schoolToCreate.SchoolAddedBy = User.Identity.Name;
HttpPostedFileBase file = Request.Files["SchoolImageUrl"];
file.SaveAs(file.FileName);
//schoolToCreate.SchoolImageUrl = Reuseable.ImageUpload(Request.Files["SchoolImageUrl"], Server.MapPath("../Content"));
//schoolToCreate.SchoolImageUrl = Path.GetFullPath(Request.Files[0].FileName);
schoolToCreate.SchoolImageUrl = collection["SchoolImageUrl"];
UpdateModel(schoolToCreate);
_schoolRepository.CreateSchool(schoolToCreate);
//_schoolRepository.SaveToDb();
return RedirectToAction("DepartmentCreate", "Department", new { userId = schoolToCreate.UserId, schoolId = schoolToCreate.SchoolId });
}
catch
{
return View("CreationFailed");
}
}
here im geting object referece error
Does your Html.BeginForm include this:
new { enctype = "multipart/form-data" }
Otherwise the file data won't be sent in the POST request.
Take a look at this post
HttpPostedFileBase file = Request.Files["SchoolImageUrl"];
may be causing it. Did you debug to check if it's getting a null value?

Ashx file creating images in MVC ASP.net

I am dynamically creating images and need to show those images to users.
For that i have created a ashx file but the problem is this ashx file is never getting called not sure why path issue or need add any tags in web.config ..
while debugging its not going .. might be its not finding
please advise.
EDIT: When i directly hit the ashx url its going and showing some results
EDIT 1: Got to know that session is null in the context any reason ?
or MVC asp.net don't require ashx handlers please advise.
/// <summary>
/// Summary description for $codebehindclassname$
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class GetImage : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
Log.Info(" In theGetImage");
context.Response.Clear();
byte[] imageByteArray = System.Convert.FromBase64String(context.Session["FrontJpegBase64"].ToString().Replace(' ', '+'));
// System.IO.MemoryStream imageMemoryStream = new System.IO.MemoryStream(imageByteArray);
try
{
using (System.Drawing.Image img = System.Drawing.Image.FromStream(new System.IO.MemoryStream(imageByteArray)))
{
img.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
}
}
catch (System.Exception ex)
{
}
finally
{
// img.Close();
context.Response.Flush();
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
in the controller, you need to create a function that return a FileResult
in vb.net
Function img() As FileResult
Dim bmp As Bitmap = Nothing
Dim dll As New Chess.cChessBoard
dll.drawBoardPNG(bmp)
Dim imgStream As New IO.MemoryStream
bmp.Save(imgStream, ImageFormat.Png)
imgStream.Position = 0
Return File(imgStream.ToArray, "image/png")
End Function
in the view, you only need to call
<img src="/test/chess/img" />

Resources