Upload text to an asp.net generic handler in javascript - javascript

How can I upload text written by the user to an asp.net generic handler? the text is pretty lengthy.

Try some jQuery code like this:
jQuery(document).ready(function($){
$('#button-id-to-submit-info-to-the-handler').on('click', function(ev) {
ev.preventDefault();
//Wrap your msg in some fashion
//in case you want to end other things
//to your handler in the future
var $xml = $('<root />')
.append($('<msg />', {
text: escape($('#id-of-your-textarea-that-has-the-text').val())
}
));
$.ajax({
type:'POST',
url:'/path/to-your/handler.ashx',
data: $('<nothing />').append($xml).html(),
success: function(data) {
$('body').prepend($('<div />', { text: $(data).find('responsetext').text() }));
}
});
});
});
And in your handler:
public class YourHandler : IHttpHandler
{
public void ProcessRequest(HttpContext ctx)
{
//Response with XML
//Build a response template
ctx.Response.ContentType = "text/xml";
String rspBody = #"<?xml version=\""1.0\"" encoding=\""utf-8\"" standalone=\""yes\""?>
<root>
<responsetext>{0}</responsetext>
</root>";
//Get the xml document created via jquery
//and load it into an XmlDocument
XmlDocument xDoc = new XmlDocument();
using (System.IO.StreamReader sr = new StreamReader(ctx.Request.InputStream))
{
String xml = sr.ReadToEnd();
xDoc.LoadXml(xml);
}
//Find your <msg> node and decode the text
XmlNode msg = xDoc.DocumentElement.SelectSingleNode("/msg");
String msgText = HttpUtility.UrlDecode(msg.InnerXml);
if (!String.IsNullOrEmpty(msgText))
{
//Success!!
//Do whatever you plan on doing with this
//and send a success response back
ctx.Response.Write(String.Format(rspBody, "SUCCESS"));
}
else
{
ctx.Response.Write(String.Format(rspBody, "FAIL: msgText was Empty!"));
}
}
}

Looking at the code from your comment (thanks for sharing), it seems like the parameter containing your text is called data in your JavaScript and you are looking for file in your handler.
Try: context.Request.Form["data"] in your handler.

Related

Why I cannot open a CSV file using JQuery and FileContentResult

I'm trying to make an ajax call (I specifically don't want to do it using ActionLink).
I'm having a controller that is like this:
public IActionResult ExportUsers(List<string> listOfEmails)
{
/*some data processing*/
return File(result, "text/csv", "ExportCandidates.csv");
}
On the other side with ajax I do this simple call:
$.ajax({
url: '/Admin/Testcenter/GenerateInvitationPreview',
type: 'post',
data: {
//some input data to send to the controller ​
​},
​success: function (response) {
​)
​}
​});
I know there exists something for pdf files where you return a base64 file and with the response in the ajax call you just write something like pdfWindow.document.write(...) and this will open a new window with a pdf file.
Is there a way to extract the response for my CSV file and generate it so the user downloads it ?
USE NPOI Library for Excel Sheet Generation
//Generate Excel Sheet
try
{
Guid gid = Guid.NewGuid();
string ext = ".xls";
string[] Headers = { "Appointments Id", "Date of Appointment", "Doctor Name", "Patient Name", "Visit Type", "Status" };
string fileName = "AppointmentsExcelSheet_" + gid.ToString() + ext;
var serverpath = _env.ContentRootPath;
string rootpath = serverpath + "/wwwroot/ExcelSheets/" + fileName;
FileInfo file = new FileInfo(Path.Combine(rootpath, fileName));
var memorystream = new MemoryStream();
using (var fs = new FileStream(rootpath, FileMode.Create, FileAccess.Write))
{
IWorkbook workbook = new XSSFWorkbook();
ISheet excelSheet = workbook.CreateSheet("Appointments List");
IRow row = excelSheet.CreateRow(0);
var font = workbook.CreateFont();
font.FontHeightInPoints = 11;
font.FontName = "Calibri";
font.Boldweight = (short)FontBoldWeight.Bold;
for (var i = 0; i < Headers.Length; i++)
{
var cell = row.CreateCell(i);
cell.SetCellValue(Headers[i]);
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(font);
}
var result = _Appointment.GetAppoinmentsPDf();
int index = 1;
foreach (var app in result.Items)
{
//var PatientDob = Convert.ToDouble(app.PatientDOB);
row = excelSheet.CreateRow(index);
row.CreateCell(0).SetCellValue(app.AppointmentId);
row.CreateCell(1).SetCellValue(app.DateofAppointment+" "+app.TimeofAppointment);
row.CreateCell(2).SetCellValue(app.DoctorFullName);
row.CreateCell(3).SetCellValue(app.SelectedPatientName);
row.CreateCell(4).SetCellValue(app.PurposeofVisit);
if (app.IsActive == false)
{
row.CreateCell(5).SetCellValue("Inactive");
}
else
{
row.CreateCell(5).SetCellValue("Active");
}
index++;
}
workbook.Write(fs);
}
using (var filestream = new FileStream(rootpath, FileMode.Open))
{
filestream.CopyToAsync(memorystream);
}
memorystream.Position = 0;
//send filepath to JQuery function
response.Msg = "/ExcelSheets/" + fileName;
}
catch (Exception Ex)
{
//exception code
}
return Ok(reponse.Msg)
//JavaScript
function AppointmentsExcelSheet() {
//var token = Token;
//var link = path;
debugger
$.ajax({
//'Content-Type': 'application/pdf.',
type: "GET",
url: "/api/Appointments/GetAppointmentsExcelSheet",
beforeSend: function () {
$.blockUI({
message: ('<img src="/images/FadingLines.gif"/>'),
css: {
backgroundColor: 'none',
border: '0',
'z-index': 'auto'
}
});
},
complete: function () {
$.unblockUI();
},
success: function (data) {
debugger
//downloads your Excel sheet
window.location.href = data.msg;
}
});
}
The best way to do what you want to do is to not use AJAX, but use either a link click that opens a new window (since you are passing in parameters) If you could use a
<form target="_blank">
to open a form response. Inside the form can be a field or fields that contains the list of emails (it can be one field, or multiple input fields with the same name). Your action handler can accept that list, parse it, and return a File response, and the natural result of opening the new window from the form post operation is a file that opens up.

Cannot delete file because it is being used by another process, ASP.NET Core MVC

I am using ASP.Net Core with MVC for creating an app. I am using visual studio and IIS express currently.
Below is my current project structure:
*project directory
-wwwroot
-areas
-attachments
-controllers
-models
-views
I currently store images inside the attachments folder.
Previously I have written something like that inside my startup.cs
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "Attachments")),
RequestPath = "/Attachments"
});
I have also done something like this below:
appendImage(#Url.Content("~/Attachments/")+result.fileName);
I did this to display an image on my view. The image is displayed successfully.
What I am trying to achieve now is the on the UI allow the user to make a choice to delete the files inside that attachments folder
I tried the following code:
string contentRootPath = _hostingEnvironment.ContentRootPath;
string fullImagePath = Path.Combine(contentRootPath + "\\Attachments", currentItemToDelete.FileName);
if (System.IO.File.Exists(fullImagePath))
{
try{
System.IO.File.Delete(fullImagePath);
}catch(Exception e){
operationResult = "Attachment Path. Internal Server Error";
}
}
The execution does enter the if (System.IO.File.Exists(fullImagePath))
but it raises an exception when it reaches System.IO.File.Delete. The exception states that the file which resides in that path is being used by another process. And thus I cannot delete the file. The only process that is accessing the file is the web app I am creating/debugging at the same time. How do I prevent this exception from happening? Do I have to use other kind of code to delete the file ?
EDIT to include more details:
Inside my view(index.cshtml):
appendImage is a javascript function:
function appendImage(imgSrc) {
var imgElement = document.createElement("img");
imgElement.setAttribute('src', imgSrc);
if (imgSrc.includes(null)) {
imgElement.setAttribute('alt', '');
}
imgElement.setAttribute('id', "img-id");
var imgdiv = document.getElementById("div-for-image");
imgdiv.appendChild(imgElement);
}
That function is called below:
$.ajax({
url:'#Url.Action("GetDataForOneItem", "Item")',
type: "GET",
data: { id: rowData.id },
success: function (result) {
removeImage();
appendImage(#Url.Content("~/Attachments/")+result.fileName);
$("#edit-btn").attr("href", '/Item/EditItem?id=' + result.id);
},
error: function (xhr, status, error) {
}
});
After calling appendImage(); I change the href of a <a> tag. When the user clicks on the link, the user is directed to another page(edit.cshtml). In the page, the image which resides in that path is also being displayed with code like this:
<img src="#Url.Content("~/Attachments/"+Model.FileName)" alt="item image" />
In this new page(edit.cshtml), there is a delete button. Upon clicking the delete button, the execution of the program goes to the controller which is this controller function:
[HttpPost]
public string DeleteOneItem(int id)
{
//query the database to check if there is image for this item.
var currentItemToDelete = GetItemFromDBDateFormatted(id);
if (!string.IsNullOrEmpty(currentItemToDelete.FileName))
{
//delete the image from disk.
string contentRootPath = _hostingEnvironment.ContentRootPath;
string fullImagePath = Path.Combine(contentRootPath + "\\Attachments", currentItemToDelete.FileName);
if (System.IO.File.Exists(fullImagePath))
{
try
{
System.IO.File.Delete(fullImagePath);
}catch(Exception e)
{
}
}
}
return "";
}
EDIT to answer question:
Add in
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
before system.io.file.delete
you can replace your C# method DeleteOneItem with this given code. may be it might work.
[HttpPost]
public string DeleteOneItem(int id)
{
//query the database to check if there is image for this item.
var currentItemToDelete = GetItemFromDBDateFormatted(id);
if (!string.IsNullOrEmpty(currentItemToDelete.FileName))
{
//delete the image from disk.
string contentRootPath = _hostingEnvironment.ContentRootPath;
string fullImagePath = Path.Combine(contentRootPath + "\\Attachments", currentItemToDelete.FileName);
if (System.IO.File.Exists(fullImagePath))
{
try
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.IO.File.Delete(fullImagePath);
}
catch (Exception e) { }
}
}
return "";
}
try
{
System.GC.Collect();
System.GC.WaitForPendingFinalizers();
System.IO.File.Delete(fullImagePath);
}
catch(Exception e){
}

asynchronous HTTP (ajax) request works in script tag but not in js file

I have this ajax call here in a script tag at the bottom of my page. Everything works fine! I can set a breakpoint inside the 'updatestatus' action method in my controller. My server gets posted too and the method gets called great! But when I put the javascript inside a js file the ajax call doesn't hit my server. All other code inside runs though, just not the ajax post call to the studentcontroller updatestatus method.
<script>
$(document).ready(function () {
console.log("ready!");
alert("entered student profile page");
});
var statusdropdown = document.getElementById("enumstatus");
statusdropdown.addEventListener("change", function (event) {
var id = "#Model.StudentId";
var url = '#Url.Action("UpdateStatus", "Student")';
var status = $(this).val();
$.post(url, { ID: id, Status: status }, function (data) {
// do something with the returned value e.g. display a message?
// for example - if(data) { // OK } else { // Oops }
});
var e = document.getElementById("enumstatus");
if (e.selectedIndex == 0) {
document.getElementById("statusbubble").style.backgroundColor = "#3fb34f";
} else {
document.getElementById("statusbubble").style.backgroundColor = "#b23f42";
}
}, false);
</script>
Now I put this at the bottom of my page now.
#section Scripts {
#Scripts.Render("~/bundles/studentprofile")
}
and inside my bundle.config file it looks like this
bundles.Add(new ScriptBundle("~/bundles/studentprofile").Include(
"~/Scripts/submitstatus.js"));
and submitstatus.js looks like this. I know it enters and runs this code because it I see the alert message and the background color changes. So the code is running. Its just not posting back to my server.
$(document).ready(function () {
console.log("ready!");
alert("submit status entered");
var statusdropdown = document.getElementById('enumstatus');
statusdropdown.addEventListener("change", function (event) {
var id = "#Model.StudentId";
var url = '#Url.Action("UpdateStatus", "Student")';
var status = $(this).val();
$.post(url, { ID: id, Status: status }, function (data) {
// do something with the returned value e.g. display a message?
// for example - if(data) { // OK } else { // Oops }
});
var e = document.getElementById('enumstatus');
if (e.selectedIndex == 0) {
document.getElementById("statusbubble").style.backgroundColor = "#3fb34f";
} else {
document.getElementById("statusbubble").style.backgroundColor = "#b23f42";
}
}, false);
});
In the console window I'm getting this error message.
POST https://localhost:44301/Student/#Url.Action(%22UpdateStatus%22,%20%22Student%22) 404 (Not Found)
Razor code is not parsed in external files so using var id = "#Model.StudentId"; in the main view will result in (say) var id = 236;, in the external script file it will result in var id = '#Model.StudentId'; (the value is not parsed)
You can either declare the variables in the main view
var id = "#Model.StudentId";
var url = '#Url.Action("UpdateStatus", "Student")';
and the external file will be able to access the values (remove the above 2 lines fro the external script file), or add them as data- attributes of the element, for example (I'm assuming enumstatus is a dropdownlist?)
#Html.DropDownListFor(m => m.enumStatus, yourSelectList, "Please select", new { data_id = Model.StudentId, data_url = Url.Action("UpdateStatus", "Student") })
which will render something like
<select id="enumStatus" name="enumStatus" data-id="236" data-url="/Student/UpdateStatus">
Then in the external file script you can access the values
var statusbubble = $('#statusbubble'); // cache this element
$('#enumStatus').change(function() {
var id = $(this).data('id');
var url = $(this).data('url');
var status = $(this).val();
$.post(url, { ID: id, Status: status }, function (data) {
....
});
// suggest you add/remove class names instead, but if you want inline styles then
if (status == someValue) { // the value of the first option?
statusbubble.css('backgroundColor', '#3fb34f');
} else {
statusbubble.css('backgroundColor', '#b23f42');
};
});

How to add the image file from the form to the jQuery ajax request

I am working a jQuery file upload helper and I need to understand how can I append the File from the form or the Form data as a whole to the request.
I have worked with the ASP.NET code to accept image from the Request and handle the further code, but when I try to use it using jQuery $.ajax() I can't get it to work.
I have been though Stack Overflow questions, and I have tried using FormData appending the data from the input[type="file"] (input for the file element). But each time (on the server) the block that is executed that tells me there is no file with the request.
Here is the ASP.NET code (UploadFile page)
#{
var fileName = "Not running!";
if(IsPost) {
if(Request.Files.Count > 0) {
var image = WebImage.GetImageFromRequest();
fileName = Path.GetFileName(image.FileName) + " From server";
} else {
fileName = "No file attached! From Server";
}
}
Response.Write(fileName);
}
The jQuery code is as
$(document).ready(function () {
$('form input[type=submit]').click(function () {
event.preventDefault();
$.ajax({
url: '/UploadFile',
data: new FormData().append('file',
document.getElementById("image").files[0]),
type: 'POST',
success: function (data) {
$('#result').html('Image uploaded was: ' + data);
}
});
});
});
I am already scratching my head since I can't get the file content on the serverside.
How can I send the file to the server, or the entire form data to the server, anything would be welcome!
Try using handler for this and Newtonsoft.json.dll for these purpose.
For jQuery
(document).ready(function () {
$('form input[type=submit]').click(function () {
event.preventDefault();
$.ajax({
url: 'handler.ashx', // put a handler instead of direct path
data: new FormData().append('file',
document.getElementById("image").files[0]),
type: 'POST',
success: function (data) {
$('#result').html('Image uploaded was: ' + data);
}
});
});
});
In asp.net
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Web;
using Newtonsoft.Json;
public class Handler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
HttpPostedFile up = context.Request.Files[0];
System.IO.FileInfo upinfo = new System.IO.FileInfo(up.FileName);
System.Drawing.Image upimg = System.Drawing.Image.FromStream(up.InputStream);
string path = context.Server.MapPath("~/temp"); // this is the server path where you'll be saving your image
if (!System.IO.Directory.Exists(path))
System.IO.Directory.CreateDirectory(path);
string fileName;
fileName = up.FileName;
string newFilename = Guid.NewGuid().ToString();
System.IO.FileInfo fInfo = new System.IO.FileInfo(fileName);
newFilename = string.Format("{0}{1}", newFilename, fInfo.Extension);
string strFileName = newFilename;
fileName = System.IO.Path.Combine(path, newFilename);
up.SaveAs(fileName);
successmsg1 s = new successmsg1
{
status = "success",
url = "temp/" + newFilename,
width = upimg.Width,
height = upimg.Height
};
context.Response.Write(JsonConvert.SerializeObject(s));
}

YUI Dialog using ajax request - want to execute javascript returned from Java but out of scope

I have a YUI dialog that submits a form to a Java servlet. The servlet returns html and javascript. I take the response and put it into a div on the page and then eval the javascript that is within the div.
My problem is that I get an error in the firebug console saying "YAHOO is not defined" as soon as the servlet returns.
I do not include the YUI js files in the servlet as I didn't think I would need them, I would expect the files included in the head of the main page would be sufficient.
If I remove all references to YUI from the javascript returned by my servlet then everything works well.
What should I do to stop getting this error as soon as my servlet returns?
My Servlet returns something along the lines of:
<div id="features">some html to display</div>
<script id="ipadJS" type='text/javascript'>
var editButton1 = new YAHOO.widget.Button('editButton1', { onclick: { fn: editButtonClick, obj: {id: '469155', name : 'name 1'} } });
var editButton2 = new YAHOO.widget.Button('editButton2', { onclick: { fn: editButtonClick, obj: {id: '84889', name : 'name 2'} } });
</script>
Here is the code that I used to create the dialog, i use the handleSuccess function to put my response from my servlet into the page (note that even though im not actively putting the javascript into the page it still throws the 'YAHOO not defined' error.):
YAHOO.namespace("ipad");
YAHOO.util.Event.onDOMReady(function () {
// Remove progressively enhanced content class, just before creating the module
YAHOO.util.Dom.removeClass("createNewFeature", "yui-pe-content");
// Define various event handlers for Dialog
var handleSubmit = function() {
this.submit();
};
var handleCancel = function() {
this.cancel();
};
var handleSuccess = function(o) {
var response = o.responseText;
var div = YAHOO.util.Dom.get('features');
div.innerHTML = response;
};
var handleFailure = function(o) {
alert("Submission failed: " + o.status);
};
// Instantiate the Dialog
YAHOO.ipad.createNewFeature = new YAHOO.widget.Dialog("createNewFeature",
{ width : "450px",
fixedcenter : true,
visible : false,
constraintoviewport : true,
buttons : [ { text:"Submit", handler:handleSubmit, isDefault:true },
{ text:"Cancel", handler:handleCancel } ]
});
// Validate the entries in the form to require that both first and last name are entered
YAHOO.ipad.createNewFeature.validate = function() {
var data = this.getData();
return true;
};
YAHOO.ipad.createNewFeature.callback = { success: handleSuccess,
failure: handleFailure,
upload: handleSuccess };
// Render the Dialog
YAHOO.ipad.createNewFeature.render();
var createNewFeatureShowButton = new YAHOO.widget.Button('createNewFeatureShow');
YAHOO.util.Event.addListener("createNewFeatureShow", "click", YAHOO.ipad.clearFeatureValues, YAHOO.ipad.clearFeatureValues, true);
var manager = new YAHOO.widget.OverlayManager();
manager.register(YAHOO.ipad.createNewFeature);
});
I don't know your use case exactly, but if you just need to create some buttons on the fly based on server response, than it would IMO be better to return JSON or XML data with the variable data and then create the buttons. Something like
var reply = eval('(' + o.responseText + ')');
var editButton1 = new YAHOO.widget.Button('editButton1',
{ onclick: { fn: editButtonClick,
obj: {id: reply[id], name : reply[name]}
} })
And if you really want to append a script node, then the following approach should work:
var response = o.responseText;
var snode = document.createElement("script");
snode.innerHTML = response;
document.body.appendChild(snode);

Categories