I'm using Grid.MVC to display data from an entity model. On row click I am getting the value of a cell and passing it to my controller with a json/ajax function.
In my controller the int "ticketnumber" is passing just fine. The thing that I am not understanding is when I hard code the int, it is working (if I directly browse to http://localhost:58779/ticket/PDFVIEW).
The controller seems to be running through just fine, but it is not displaying the PDF..it just takes me back to my grid in my view with the ajax script. Thanks for the help.
Edit - Code:
<script>
$(function () {
pageGrids.TicketGrid.onRowSelect(function (e) {
var ticketnumber = e.row.UnsettledID;
ticketnumber = JSON.stringify({ 'ticketnumber': ticketnumber });
$.ajax({
contentType: 'application/json; charset=utf-8',
dataType: 'json',
type: 'POST',
url: '/ticket/PDFVIEW',
data: ticketnumber,
});
});
});
</script>
controller:
[ActionName("PDFVIEW")]
[HttpGet]
public ActionResult PDFVIEW(int ticketnumber)
{
var db = new ScaleTrac_VerticalEntities();
Ticket_UnsettledScaleImages tu = new Ticket_UnsettledScaleImages();
tu = db.Ticket_UnsettledScaleImages.Where(p => p.UnsettledID == ticketnumber).First();
string filename = "ScaleTick" + tu.UnsettledID + ".pdf";
{
byte[] bytes = tu.ScaleTicket;
TempData["bytes"] = bytes;
Response.Clear();
MemoryStream ms = new MemoryStream(bytes);
return new FileStreamResult(ms, "application/pdf");
}
}
You can't use AJAX to download a file in this way. Your AJAX code is getting the contents of the PDF, but your browser needs to receive it as a normal request in order to view it. You should instead render a link to the PdfView action, or use window.setLocation if you need to do it from a Javascript event handler.
Note you'll also need to change your action method to accept HttpGet.
Using what Richard said helped a lot.
My Json I changed to:
<script>
$(function pdfviewer() {
pageGrids.TicketGrid.onRowSelect(function (e) {
var ticketnumber = e.row.UnsettledID;
ticketnumber = JSON.stringify({ 'ticketnumber': ticketnumber });
$.ajax({
contentType: 'application/json; charset=utf-8',
dataType: 'json',
type: 'POST',
url: '/ticket/PDFVIEW',
data: ticketnumber,
success: function (d) {
if (d.success) {
window.location = "/Ticket/DownloadFile" + "?fName=" + d.fName;
}
},
error: function () {
alert("Error");
}
});
});
});
</script>
And in my controller I did:
[ActionName("PDFVIEW")]
public ActionResult pdf(int ticketnumber)
{
var db = new ScaleTrac_VerticalEntities();
Ticket_UnsettledScaleImages tu = new Ticket_UnsettledScaleImages();
tu = db.Ticket_UnsettledScaleImages.Where(p => p.UnsettledID == ticketnumber).First();
string filename = "ScaleTick" + tu.UnsettledID + ".pdf";
{
byte[] bytes = tu.ScaleTicket;
TempData["bytes"] = bytes;
Response.Clear();
MemoryStream ms = new MemoryStream(bytes);
var fName = string.Format("File-{0}.pdf", DateTime.Now.ToString("s"));
Session[fName] = ms;
return Json(new { success = true, fName }, JsonRequestBehavior.AllowGet);
}
}
public ActionResult DownloadFile(string fName)
{
var ms = Session[fName] as MemoryStream;
if (ms == null)
return new EmptyResult();
Session[fName] = null;
return File(ms, "application/pdf", fName);
}
Thank you very much!
Related
I made the user input part of my project as a modal (pop-up), so I need to transfer the data to the back side (controller) without refreshing the page. For this reason, I chose to use ajax, but I have a problem.
Here my Register Controller.
[HttpPost]
public JsonResult Register(RegisterViewModel formData)
{
var user = new UserRegisterDto
{
FirstName = formData.FirstName,
LastName = formData.LastName,
Email = formData.Email,
Password = formData.Password,
PhoneNumber = formData.PhoneNumber,
UserType = Data.Enums.UserTypeEnum.user
};
var response = _userService.AddUser(user);
return new JsonResult("Data is Saved");
}
Here my ajax code
$('#btnRegister').click(function() { debugger
var user = {
FirstName: $('#inputUserFirstName').val(),
LastName: $('#inputUserLastName').val(),
Email: $('#inputUserEmail').val(),
Password: $('#inputUserPassword').val(),
PasswordConfirm: $('#inputUserPasswordConfirm').val(),
PhoneNumber: $('#inputUserPhoneNumber').val()
};
$.ajax({
type: 'Post',
url: '/Auth/Register',
data: JSON.stringify(user),
contentType:'application/json; charset=utf-8;',
dataType: 'json',
success: function() {
alert("saved");
},
error: function() {
alert("no saved");
}
});
When I debugged, I saw that the formData parameter in the controller was not getting any data.
I couldn't find where I made the mistake.
You will need to JSON.stringify() your data to transfer it in the request.
Your request should look like this:
$.ajax({
type: 'Post',
url: '/Auth/Register',
data: JSON.stringify(user),
contentType:'application/json; charset=utf-8;',
dataType: 'json',
success: function() {
alert("saved");
},
error: function() {
alert("no saved");
}
});
For the controller i would do it likes this:
[Route("Auth/Register")]
[HttpPost]
public IActionResult Register([FromBody] RegisterViewModel formData)
{
var user = new UserRegisterDto
{
FirstName = formData.FirstName,
LastName = formData.LastName,
Email = formData.Email,
Password = formData.Password,
PhoneNumber = formData.PhoneNumber,
UserType = Data.Enums.UserTypeEnum.user
};
var response = _userService.AddUser(user);
return Json(new { #Success = true});
}
I have a requirement of sending invitations to candidates where a user selects the excel file, transfers it from ajax to controller and validates its size, type etc. Then user clicks on Send Invite button and sends the email invites(having excel file). Please find the below code for reference:
<button type="button" id="bulkuploadButton">Bulk Email Upload</button>
<input type="file" id="ExcelFile" name="ExcelFile" style="display:none" onchange="UploadFile();" onselect="UploadFile();" accept="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" />
Jquery:
function UploadFile() {
if (ValidateExcelFile()) {
var excelFile = document.getElementById('ExcelFile');
formData = new FormData();
if (excelFile.files.length > 0) {
for (var i = 0; i < excelFile.files.length; i++) {
formData.append('file-' + i, excelFile.files[i]);
}
}
$.ajax({
url: url here,
type: "POST",
dataType: 'json',
processData: false,
contentType: false,
data: formData,
success: function (data) {
// Further Processing
},
error: function (err) {
//Error
}
});
}
}
Controller:
[HttpPost]
public JsonResult MyController(HttpPostedFileBase excelFile)
{
if (Request.Files.Count > 0)
{
foreach (string file in Request.Files)
{
excelFile = Request.Files[file];
}
var result = //Call Model here for validation checks and return error msges
TempData["ExcelFile"] = excelFile; //Store in TempData for further processing
return Json(result);
}
return null;
}
The validations are done successfully, now its time to send invite to candidates as:
<button onclick="SendInvite">Send Invitations</button>
Jquery:
function SendInvite() {
//Check validations for other inputs on the page
//Get the excel file same as above
var excelFile = document.getElementById('ExcelFile');
formData = new FormData();
if (excelFile.files.length > 0) {
for (var i = 0; i < excelFile.files.length; i++) {
formData.append('file-' + i, excelFile.files[i]);
}
}
$.ajax({
type: "POST",
url: url here,
data: JSON.stringify({
myModel: myModel,
excelFile: formData
}),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
},
error: function (data) {
}
});
}
Controller:
public JsonResult MyController2(MyModel myModel, HttpPostedFileBase excelFile)
{
//I tried the same method to get the file but it didn't help me
if (Request.Files.Count > 0) //Here Request.Files.Count = 0, it should be = 1 instead
{
foreach (string file in Request.Files)
{
excelFile = Request.Files[file];
}
}
//I then tied to use TempData but it does not have the excel data
excelFile = TempData["ExcelFile"] as HttpPostedFileBase;
//Further processing
I am getting this error while fetching data from TempData. ContentLength is 0 and also the data attribute is null
The data in TempData should be something like this (where ContentLength !=0
and data attribute has some value):
Can anyone help me get the excel data in controller MyController2.
Change the function SendInvite() as:
function SendInvite() {
//Check validations for other inputs on the page
//Get the excel file same as above
var excelFile = document.getElementById('ExcelFile');
formData = new FormData();
formData.append("data", JSON.stringify(myModel));
for (var i = 0; i < excelFile.files.length; i++) {
var file = ExcelFile.files[i];
formData.append("excelFile", file);
}
$.ajax({
type: "POST",
url: url here,
data: formData,
contentType: "application/json; charset=utf-8",
dataType: "json",
contentType: false,
processData: false,
success: function (data) {
},
error: function (data) {
}
});
}
and in controller
public JsonResult MyController2(string data, HttpPostedFileBase[] excelFile)
{
MyModel myModel = JsonConvert.DeserializeObject<MyModel>(data);
if (Request.Files.Count > 0)
{
//Do data processing here
}
//Further processing
Check this link How to Pass Image File and Form Data From Ajax to MVC Controller
I am trying to export selected records in to a file and reload the page to update the records in a current view. I am calling web api asynchronously to get all the records. An AJAX call is executing an action in a controller successfully and returning expected data without any error but none of the 'success', 'complete' or 'error' part of ajax function is executing. There are no errors in a developer tool of the browser, no exception, nothing unusual so its getting trickier for me to investigate this issue further. Can I request your a suggestions on this please? Thanks
View :
#Html.ActionLink("Export records", "Index", null, new { Id = "myExportLinkId")
Script :
$("a#myExportLinkId").click(function (e) {
var selected = "";
$('input#myCheckBoxList').each(function () {
if (this.checked == true) {
selected += $(this).val() + ',';
}
});
if (selected != "") {
$.ajax({
url: '/MyController/MyAction',
type: 'GET',
contentType: "application/json; charset=utf-8",
dataType: "json",
data: {
'MyString': 'stringValue'
},
success: function (data) {
alert("success");
},
error: function () {
alert("error");
}
});
})
And the action/method looks like this :
[HttpGet]
public async Task<ActionResult> ExportNewOrders(string OrderIdString)
{
//code to create and store file
//actually want to send the file details as json/jsonResult but for testing only returning
//string here
return Json( "Success", "application/json", JsonRequestBehavior.AllowGet);
}
Finally I have resolved this with Promisify functionality of an AJAX call. Obviously the json response I was returning had an issue so I have replaced
return Json( "Success", "application/json", JsonRequestBehavior.AllowGet);
to
return new JsonResult(){
Data = new { success = true, guid = handle, fileName = exportFileName },
ContentType = "application/json",
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
which has fixed the bug and the success function of ajax call got executed.
But other than this there were issues to wait until the file download (which involved encryption decryption, server validations etc) completes and then refresh the page. This I have resolved by implementing an ajax call with Promisify fuctionality. You can find codepen example here and the original post here.
Here is the complete code.
View/HTML
#Html.ActionLink("Export", "yourActionName", null, new { Id = "exportRequest", #onclick = "letMeKnowMyFileIsDownloaded();" })
Script/Ajax
function letMeKnowMyFileIsDownloaded() {
return new Promise(function (resolve, reject) {
$("a#exportRequest").on("click", function () {
$.ajax({
url: this.href + "?param=whatever params you want to pass",
dataType: "json",
data: {
'param1': 'value'
},
success: function (data) {
var a = document.createElement("a");
var url = '/yourControllerName/Download?fileGuid=' + data.guid + '&filename=' + data.fileName;//window.URL.createObjectURL(data);
a.href = url;
a.download = data.fileName;
document.body.append(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
resolve(true);
},
error: function (error) {
reject(error);
}
});
});
});
}
letMeKnowMyFileIsDownloaded()
.then(function (bool) {
if (bool) {
//alert("File downloaded 👇");
window.location.reload(1);
}
})
.catch(function (error) {
alert("error");
});
I have used nuget package ClosedXML to handle excel file functionality. Using the stream to create and download the data in excel file without storing the file physically on the server.
And in the controller
//can be async or sync action
public async Task<ActionResult> Index(YourModel model)
{
//do stuff you want
var exportOrders = your_object;
//using DataTable as datasource
var dataSource = new DataTable();
//write your own function to convert your_object to your_dataSource_type
dataSource = FormatTypeToDataTable(exportOrders);
if (dataSource != null && dataSource.Rows.Count > 0)
{
//install ClosedXML.Excel from nuget
using (XLWorkbook wb = new XLWorkbook())
{
try
{
var handle = Guid.NewGuid().ToString();
wb.Worksheets.Add(dataSource, "anyNameForSheet");
string exportFileName = "yourFileName" + ".xlsx";
MemoryStream stream = GetStream(wb);
TempData[handle] = stream; exportFileName);
return new JsonResult()
{
Data = new { success = true, guid = handle, fileName = exportFileName },
ContentType = "application/json",
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
catch (Exception ex)
{
//ModelState.AddModelError("", ex.Message);
}
}
}
}
public virtual ActionResult Download(string fileGuid, string fileName)
{
if (TempData[fileGuid] != null)
{
var stream = TempData[fileGuid] as MemoryStream;
var data = stream.ToArray();
return File(data, "application/vnd.ms-excel", fileName);
}
else
{
return new EmptyResult();
}
}
My code int Client:
var formData = new FormData();
formData.append("ID", "1");
formData.append("Name", "GÃ Haha");
console.log(formData.get("ID"));
$.ajax({
type: "POST",
url: "http://localhost:13497/myapi/student",
contentType: "json",//Request header
data:formData,
dataType: "json",//Responce header
processData: false,
success: function (data) {
$.each(data, function (key, value)
{
var jsonData = JSON.stringify(value);
var objData = $.parseJSON(jsonData);
var id = objData.ID;
var fname = objData.Name;
var lname = objData.Price;
$('<tr><td>' + id + '</td><td>' + fname + '</td><td>' + lname + '</td></tr>').appendTo('#students');
});
},
error: function (errormsg) {
alert(errormsg.responseText);
}
});
My code in server:
[HttpPost]
public IEnumerable<Products> GetStudents()
{
string temp=HttpContext.Current.Request.Params["ID"];
return temp;
}
But temp return null. I'm using How can retrieve string formData js in c# but return empty and here How to read FormData into Web api but it not working.
Finally: I want to get data from FormData Client send
Please try in server side
Use form
HttpContext.Current.Request.Form["ID"] instead of Request.Params["ID"]
I have a Patient like this in AngularJS
var Patient = {
PatientID : $scope.PatientID,
FirstName: $scope.FirstName,
LastName: $scope.LastName,
Disease: $scope.Disease,
PhoneNo: $scope.PhoneNo
};
Angular Controller
var pData = new FormData();
pData.append("model", Patient);
var getData = angularService.AddPatient(pData);
Angular Service
this.AddPatient = function (patientData) {
var response = $http({
withCredentials: true,
headers: { 'Content-Type': undefined },
transformRequest: angular.identity,
method: "post",
url: "/Student/AddPatient",
data: patientData,
dataType: "json"
});
return response;
}
And my Method in MVC Controller
public String AddPatient() {
var model = Request.Form["model"];
// this giving me an object instead of JSON String
}
Please help me, how do i receive that Patient data, Read and save it in the database, and i dont want to use any loop, i mean like this
// I dont want to do this
var patientData = new FormData();
angular.forEach(Patient, function (value, key) {
patientData.append(key, value);
});