Make IFormFile function to work with model - asp.net-core-mvc

I have a function in my controller that takes a file sent by an ajax call and saves it to a specified path. I was wondering how I could make this work with a model instead as I am hoping to send more data than just the image.
ViewModel:
public class PhotoViewModel
{
// Other strings
public IFormFile userimage { get; set; }
}
Controller: Without model (working)
[HttpPost]
public async Task<IActionResult> Post(IFormFile file)
{
var filePath = Path.GetFullPath(#"C:\Users\me\documents\" + file.FileName);
if (file.Length > 0)
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
}
return StatusCode(200);
}
Attempt at Version with Model:
[HttpPost]
public async Task<IActionResult> PhotoData(PhotoViewModel model)
{
var filePath = Path.GetFullPath(#"C:\Users\me\documents\" + model.userimage.FileName);
if (ModelState.IsValid)
{
if (model.userimage.Length > 0)
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await model.userimage.CopyToAsync(stream);
}
}
}
return StatusCode(200);
}
This attempt doesn't get me far. By setting a breakpoint I can see it fails at setting the filePath but I'm not sure how to work with the model. Any help is appreciated.

What is the error message you are getting and what is the client side code you are using to send the API request?
You will have to use a FormData object and fill the FormData object with the required properties.
var formData = new FormData();
formData.append(add PhotoViewModel properties)
formData.append(userimage, <file>);

Related

Why is this RestSharp file upload not working?

I have this ASP.NET Core Web API action method:
[HttpPost("PostDir")]
[DisableRequestSizeLimit]
public async Task<IActionResult> PostDir(string serverPath)
{
// Do stuff with file.
return Ok();
}
I don't know what to do with the file I am trying to upload or what it looks like in the action method because the action is never invoked: the client code below gets a 404 response:
public async Task PostDirAsync(string localDirPath, string serverDir)
{
var sourcePath = Path.Combine("Temp", Guid.NewGuid() + ".zip");
ZipFile.CreateFromDirectory(localDirPath, sourcePath, CompressionLevel.Fastest, true);
var rest = new RestClient("http://localhost:50424/api/File/PostDir");
var req = new RestRequest(Method.POST);
req.AddFile(Path.GetFileName(sourcePath), sourcePath);
req.AddHeader("Content-Type", "multipart/form-data");
req.AddParameter("serverPath", serverDir, ParameterType.QueryString);
var resp = rest.Execute(req);
}
What am I missing or doing wrong?

IN MVC6 return Json(rows, JsonRequestBehavior.AllowGet) ISSUE

IN MVC6 return Json(rows, JsonRequestBehavior.AllowGet); method is changed and not allowing to set JsonrequestBehavior. What is alternative in MVC6
That overload of Json method which takes JsonRequestBehavior does not exist in the aspnet core any more.
You can simply call the Json method with the object data you want to send back.
public IActionResult GetJsonData()
{
var rows = new List<string> { "Item 1","Item 2" };
return Json(rows);
}
Or even
public IList<string> GetJsonData()
{
var rows = new List<string> {"aa", "bb" };
return rows;
}
or using Ok method and having IActionResult as the return type.
public IActionResult GetJsonData()
{
var rows = new List<string> { "aa", "bb" };
return Ok(rows);
}
and let the content negotiator return the data in the requested format(via Accept header). The default format used by ASP.NET Core MVC is JSON. So if you are not explicitly requesting another format(ex :application/xml), you will get json response.
Try this
[HttpGet]
public JsonResult List()
{
var settings = new JsonSerializerSettings();
return Json(rows, settings);
}
Try this
public JsonResult GetJsonData()
{
var data= //your list values
return Json(data);
}
JsonRequestBehavior is deprecated from ASP.net core 1. Just use return Json();

Hide image using Javascript after controller action is complete MVC3

My application has been implemeted using MVC 3, .net.
I am trying to generate an excel file at the click of a button.
The call to the controller action is made using Ajax.
My main problem is: During the file generation i am trying to display an image on the screen to let the user know of the ingoing operation. I can very well display the image but i cannot hide it after the operation is completed. The codei am using is :
Javascript code:
$("input.DownloadExcelReport").click(function (e) {
e.preventDefault();
var parameter = -- code to fetch parameter value;
var outputViewUrl = (the url is created here);
showLoading(); -- This function displays the image
window.location.href = outputViewUrl;
});
Controller Action code:
public ActionResult DownExcelReportForAssortment(Guid parameter)
{
try
{
//the contents for the file generation are fetched here..
// Write contents to excel file
if (memoryStream != null)
{
var documentName = "Report.xls";
byte[] byteArrary = memoryStream.ToArray();
return File(byteArrary, "application/vnd.ms-excel", documentName);
}
}
catch (Exception ex)
{
LogManager.LogException(ex);
}
}
I do not return a Json result to the calling javascript method where i can write the code to hide the image.
I am returning a file which can be saved by the user and the action is completed.
Can somone please suggect/help me of how can i hide the image once the file generation operation is complete?
Appreciate the help...
You may checkout the following article and put this into action. So we start by defining a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
public ActionResult DownExcelReportForAssortment(Guid parameter, string tokenId)
{
// Simulate some heavy work to fetch the report
Thread.Sleep(5000);
// we fake it
byte[] byteArray = System.IO.File.ReadAllBytes(#"c:\test.xls");
var cookie = new HttpCookie("fileDownloadToken", tokenId);
Response.AppendCookie(cookie);
return File(byteArray, "application/vnd.ms-excel", "report.xls");
}
}
and in the view:
#Html.ActionLink(
"download report",
"DownExcelReportForAssortment",
"Home",
new { parameter = Guid.NewGuid(), tokenId = "__token__" },
new { #class = "download" }
)
Now the last step is to include the jquery.cookie plugin:
<script type="text/javascript" src="#Url.Content("~/scripts/jquery.cookie.js")"></script>
and write a script to subscribe to the click event of the anchor and track the download progress:
$(function () {
var fileDownloadCheckTimer;
$('.download').click(function () {
var token = new Date().getTime();
$(this).attr('href', function () {
return this.href.replace('__token__', token);
});
// Show the download spinner
$('body').append('<span id="progress">Downloading ...</span>');
// Start polling for the cookie
fileDownloadCheckTimer = window.setInterval(function () {
var cookieValue = $.cookie('fileDownloadToken');
if (cookieValue == token) {
window.clearInterval(fileDownloadCheckTimer);
$.cookie('fileDownloadToken', null);
// Hide the download spinner
$('#progress').remove();
}
}, 1000);
});
});

Returning Multiple partial views from single Controller action?

I need to update Multiple from an Ajax call , I am confused as in how to return these Multiple views from the Controller Action method.
You can only return one value from a function so you can't return multiple partials from one action method.
If you are trying to return two models to one view, create a view model that contains both of the models that you want to send, and make your view's model the new ViewModel.
E.g.
Your view model would look like:
public class ChartAndListViewModel
{
public List<ChartItem> ChartItems {get; set;};
public List<ListItem> ListItems {get; set;};
}
Then your controller action would be:
public ActionResult ChartList()
{
var model = new ChartAndListViewModel();
model.ChartItems = _db.getChartItems();
model.ListItems = _db.getListItems();
return View(model);
}
And finally your view would be:
#model Application.ViewModels.ChartAndListViewModel
<h2>Blah</h2>
#Html.RenderPartial("ChartPartialName", model.ChartItems);
#Html.RenderPartial("ListPartialName", model.ListItems);
There is a very good example here....
http://rhamesconsulting.com/2014/10/27/mvc-updating-multiple-partial-views-from-a-single-ajax-action/
Create a helper method to package up the partial view...
public static string RenderRazorViewToString(ControllerContext controllerContext,
string viewName, object model)
{
controllerContext.Controller.ViewData.Model = model;
using (var stringWriter = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(controllerContext, viewName);
var viewContext = new ViewContext(controllerContext, viewResult.View, controllerContext.Controller.ViewData, controllerContext.Controller.TempData, stringWriter);
viewResult.View.Render(viewContext, stringWriter);
viewResult.ViewEngine.ReleaseView(controllerContext, viewResult.View);
return stringWriter.GetStringBuilder().ToString();
}
}
Create a controller action to bundle the multiple partial views....
[HttpPost]
public JsonResult GetResults(int someExampleInput)
{
MyResultsModel model = CalculateOutputData(someExampleInput);
var totalValuesPartialView = RenderRazorViewToString(this.ControllerContext, "_TotalValues", model.TotalValuesModel);
var summaryValuesPartialView = RenderRazorViewToString(this.ControllerContext, "_SummaryValues", model.SummaryValuesModel);
return Json(new { totalValuesPartialView, summaryValuesPartialView });
}
Each partial view can use its own model if required or can be bundled into the same model as in this example.
Then use an AJAX call to update all the sections in one go:
$('#getResults').on('click', function () {
$.ajax({
type: 'POST',
url: "/MyController/GetResults",
dataType: 'json',
data: {
someExampleInput: 10
},
success: function (result) {
if (result != null) {
$("#totalValuesPartialView").html(result.totalValuesPartialView);
$("#summaryValuesPartialView").html(result.summaryValuesPartialView);
} else {
alert('Error getting data.');
}
},
error: function () {
alert('Error getting data.');
}
});
});
If you want to use this method for a GET request, you need to remove the [HttpPost] decorator and add JsonRequestBehavior.AllowGet to the returned JsonResult:
return Json(new { totalValuesPartialView, summaryValuesPartialView }, JsonRequestBehavior.AllowGet);
Maybe this solution can help you:
http://www.codeproject.com/Tips/712187/Returning-More-Views-in-an-ASP-NET-MVC-Action

ASP.NET MVC3: Image loading through controller

I tried using the answer from here, but it did not work. I have the following code:
public ActionResult ShowImage()
{
using (FileStream stream = new FileStream(Path.Combine(Server.MapPath("/App_Data/UserUpload/asd.png")), FileMode.Open))
{
FileStreamResult result = new FileStreamResult(stream, "image/png");
result.FileDownloadName = "asd.png";
return result;
}
}
When I open up the page I get an error which says: "Cannot access a closed file.". I did some googling on the error, but I only found this error associated with uploading. What causes the issue here?
Try like this:
public ActionResult ShowImage()
{
var file = Server.MapPath("~/App_Data/UserUpload/asd.png");
return File(file, "image/png", Path.GetFileName(file));
}
or if you want a separate filename:
public ActionResult ShowImage()
{
var path = Server.MapPath("~/App_Data/UserUpload");
var file = "asd.png";
var fullPath = Path.Combine(path, file);
return File(fullPath, "image/png", file);
}

Resources