Send File with extra parameters to WCF REST Service - c#

I am having a little problem here.
Currently I am using a Generic Handler to upload files to the server, but one problem that I have is that if I have extra data, like a user's name and surname, I have to do(save) that separately.
This is a problem, because if I save the name and surname, and the file upload fails, I have a record in my database that has no file associated with it.
So, now I am thinking of implementing a new web method, that will take all of this, and if that method fails, it will just roll back the SQL transaction.
What I want to do is call a web method, and pass the file with the user's name and surname and photo, and then perform the saving in the database there.
This is what I have tried:
jQuery:
$("#btnCreateRequest").click(function () {
var data = new FormData();
var photo = $("#fuPhoto")[0].files[0];
data.append("name", 'Fred');
data.append("surname", 'Moller');
data.append("photo", photo);
$.ajax({
type: "POST",
url: "Service.svc/CreateRequest",
dataType: "json",
//cache: false,
contentType: false,
processData: false,
data: data,
success: function (response2) {
//$("#PageArea").html(response2);
Popup(true, "success", "success", true);
},
error: function (response) {
Popup(true, "Error", JSON.stringify(response), true);
}
});
});
IService.cs
[OperationContract]
[WebInvoke(Method = "POST",
UriTemplate = "CreateRequest",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json,
BodyStyle = WebMessageBodyStyle.WrappedRequest)]
string CreateRequest();
Service.svc
public string CreateRequest()
{
var request = System.Web.HttpContext.Current.Request;
string name = request["name"];
string surname = request["surname"];
HttpPostedFile photo = request["photo"];
//Saving in database happens here, using above variables...
return "whatever";
}
However, I am failing miserably.
The web service gets called, but all the variables is NULL.
If I am going about this the wrong way, please point me in the right direction - any help will be appreciated!
(If something is not clear, please ask and I'll try to explain more)

Ah, no matter, I've changed my approach. Instead of trying to use a Web Service, I now use the Generic Handler for this.
Sometimes, it's better to look at it a little different.
Here is how I got this to work for me.
In my jQuery, I will have something like this:
$("#btnCreateRequest").click(function () {
var data = new FormData();
var photo = $("#fuPhoto")[0].files[0];
data.append("callingFromPage", "help");
data.append("requestType", $('#dropBugType').val());
data.append("description", $('#taDescription').val());
data.append("photo", photo);
data.append("userGUID", _cookieObject.UserObject.GlobalUniqueID);
$.ajax({
xhr: function () {
var xhr = new window.XMLHttpRequest();
xhr.upload.addEventListener("progress", function (evt) {
if (evt.lengthComputable) {
var percentComplete = evt.loaded / evt.total;
percentComplete = parseInt(percentComplete * 100);
//Indicate progress.
$('.uplPhotoProgress').css('width', percentComplete + '%');
$('.uplPhotoProgress').html('Uploading: ' + percentComplete + '%');
//Hide progress bar.
if (percentComplete === 100) {
$//('.uplProgressAttachments').css('display', percentComplete + 'none');
}
}
}, false);
return xhr;
},
url: "UploadHandler.ashx/",
data: data,
processData: false,
contentType: false,
type: "POST",
success: function (response) {
if (response === 'success') {
console.log('success');
} else {
console.log('problem...');
}
},
error: function (response) {
}
});
});
Then, in my UploadHandler.ashx (Generic Handler):
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "multipart/form-data";
context.Response.Expires = -1;
try
{
string callingFromPage = context.Request["callingFromPage"];
if (!string.IsNullOrWhiteSpace(callingFromPage))
{
switch (callingFromPage)
{
case "help":
{
string requestType = context.Request["requestType"];
string description = context.Request["description"];
HttpPostedFile photo = context.Request.Files[0];
string guid = context.Request["userGUID"];
//DO YOUR STUFF >>>
context.Response.Write("success");
break;
}
}
}
catch (Exception ex)
{
context.Response.Write("Error: " + ex.Message);
}
}
Sure, this is a simple example of what I did... but I'm happy to do it this way.

Related

Ajax call to async method returning file successfully but success/complete part of an Ajax request is not getting executed

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();
}
}

Parameter in my C# controller read as null from the AJAX call

I'm trying to take input from Users through a checkbox and store it in a table in my SQL DB, I've created all the link properly and my post AJAX call works well because I was able to receive information in my DB. The problem is the parameter received in my controller is receiving a null value which is storing a null value in my table, I know that my checkbox is pulling the right information because im printing it before hand but I feel like my AJAX setup may not be stringifying it properly.
$("#submitButton").click(function() {
var results = {};
$questions = $('#optionData');
for (i = 1; i < 6; i++) {
if ($questions.find('#option' + i).prop('checked')) {
results['option' + i] = $questions.find('#option' + i).val();
}
newResult = JSON.stringify(results)
};
console.log(newResult);
$.ajax({
url: "/Home/SaveData",
type: "POST",
dataType: 'json',
contentType: "application/json; charset=utf-8",
data: (newResult),
success: function(data) {
if (data == null) {
alert("Something went wrong");
}
},
failure: function(data) {
alert(data.dataText);
},
error: function(data) {
alert(data.dataText);
}
});
});
[HttpPost]
public ActionResult SaveData(string Options)
{
dataInsertion dataInsertion = new dataInsertion
{
// questionID = object.QuestionId,
options = Options,
// },
// companyID = object.companyID
};
try
{
if (ModelState.IsValid)
{
DB.dataInsertions.Add(dataInsertion);
DB.SaveChanges();
// RedirectToAction("Home");
}
}
catch (Exception e)
{
Console.WriteLine("error" + e);
}
return Json(new { sucess = "true" });
}

Displaying PDF from byte[] in MVC 4

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!

asp.net | values sent trough ajax received as null in handler

I am trying to send the 'file' attachment to handler(and send it with email)
This is the code I am using to send it to handler(JS)
When I debug it I see the right values including the file(debug in java-script).
function sendCv_click() {
var settings = {
'data': getData("sendCv"),
'url': "Handlers/SendCV.ashx",
'contentType': 'false',
'processData': 'false'
};
sendCV(settings);
};
function getData(){
data = {
'fullName': $('#txt_sendCv_fullName').val(),
'cvFile':$('#fu_sendCv_upload')[0].files[0],
'email': $('#txt_sendCv_email').val(),
'checkBox': $('#sendCv_chkBox:checked').length
}
function sendCV(settings) {
$.ajax({
type: "POST",
contentType: settings.contentType,
processData: settings.processData,
data: settings.data,
url: settings.url,
dataType: "json",
success: function(data) {
...
},
error: function(data, xhr) {
...
});
}).always(function() {
...
});
}
}
How can I get them in the handler page?
like that I get them as Null, why?
public void ProcessRequest(HttpContext context)
{
string fullName = context.Request.Form.Get("fullName"); //It's Null
string email = context.Request.Form.Get("email");//It's Null
string chkBox_ad = context.Request.Form.Get("checkBox"); //It's Null
/////how can i get the file here ??
bool mailSent = Mail.SendCV(fullName, email, chkBox_ad);
context.Response.ContentType = "text/plain";
if (mailSent)
{
context.Response.Write("true");
}
else
{
context.Response.Write("false");
}
}
This might work...
var postedFile = context.Request.Files[0];
var parser = new MultipartParser(context.Request.InputStream);
if (parser.Success) {
byte[] content = parser.FileContents;
string filename = parser.Filename;
}
MultipartParser is opensource class - see http://multipartparser.codeplex.com/SourceControl/latest#MultipartParser.cs

Posting JSON object to asp.net server

i am trying to post some json data to to my asp.netserver on my localhost. The page to receive the code should be the master page, however i tried that and got "Error 403: Forbidden" so i tried my hands on a web service instead and now i am having a whole load of other issues. My main issue is that i could do this rather simply in PHP but i have no idea how to go about this in ASP.NET.
This is my js file:
// Get User Login Credentials
function authenticate() {
$(document).ready(function () {
var user = $('.login-box form #txtLoginUsername').val().trim();
var pass = $('.login-box form #txtLoginPass').val().trim();
// alert(user + " : " + pass);
$.ajax({
type: "POST",
url: "postback.asmx/Verify",
data: {
user: user,
pass: pass
},
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function() {
if (response)
{
alert('Works');
}
else {
$(".ui-widget").slideDown(1000, function () {});
}
}
});
});
}
Now i call this function on a button click event, i do not add my server code because it comprises of several lines of code i picked up from the net and tried to mash up to get my page to work, which it didn't. I would like to know a simple appropriate method of getting JSON objects from a post and return a value/array from my server.
Please i do not wish to use any asp.net server controls for certain reasons i am unable to disclose, but i have been restricted from using such controls.
You can´t put your WebMethod in an masterPage. Ajax is client side and you are getting the same error if you tried to acess site.master in your browser.
"Description: The type of page you have requested is not served because it has been explicitly forbidden. The extension '.master' may be incorrect. Please review the URL below and make sure that it is spelled correctly. "
You can implement your WebMethod in other file .aspx and call by ajax.
I wrote an little example.
cs
[WebMethod(enableSession: true)]
public static void Verify(string user, String pass)
{
throw new Exception("I´m here");
}
js
function authenticate() {
$(document).ready(function () {
var user = $('#txtLoginUsername').val().trim();
var pass = $('#txtLoginPass').val().trim();
// alert(user + " : " + pass);
var data = {};
data.user = user;
$.ajax({
type: "POST",
url: "default.aspx/Verify",
data: JSON.stringify({
user: user,
pass: pass
}),
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function () {
if (response) {
alert('Works');
}
else {
$(".ui-widget").slideDown(1000, function () { });
}
}
});
});
}
pay attention how Json is passing to data
data: JSON.stringify({
user: user,
pass: pass
}),
To call webservice, try pass json this way.
When you call web service there are same error message in browser´s console?
I think this is will help you.
You can use JSON.stringify() method as explained in follow
var jsonData=your Jason data;
Data:JSON.stringify(jsonData)
courtsey:
http://www.dotnetlines.com/forum/tabid/86/forumid/6/postid/72/scope/posts/Default.aspx#72
You can do like this.
[WebMethod]
public string Verify(string user,string pass)
{
//DataTable dt = YourMethod_ReturningDataTable();
//retrun dt.toJson();
//But in your case
bool IsAllowedtoLogin = true;
return IsAllowedtoLogin.toJson();
}
For this (toJson) method you have create a static class.This will convert even datatable to json format.
public static string toJson(this DataTable dataTable)
{
string[] StrDc = new string[dataTable.Columns.Count];
string HeadStr = string.Empty;
for (int i = 0; i < dataTable.Columns.Count; i++)
{
StrDc[i] = dataTable.Columns[i].Caption;
HeadStr += "\"" + StrDc[i] + "\" : \"" + StrDc[i] + i.ToString() + "¾" + "\",";
}
HeadStr = HeadStr.Substring(0, HeadStr.Length - 1);
StringBuilder Sb = new StringBuilder();
Sb.Append("{\"" + dataTable.TableName + "\" : [");
for (int i = 0; i < dataTable.Rows.Count; i++)
{
string TempStr = HeadStr;
Sb.Append("{");
for (int j = 0; j < dataTable.Columns.Count; j++)
{
TempStr = TempStr.Replace(dataTable.Columns[j] + j.ToString() + "¾", dataTable.Rows[i][j].ToString());
}
Sb.Append(TempStr + "},");
}
Sb = new StringBuilder(Sb.ToString().Substring(0, Sb.ToString().Length - 1));
Sb.Append("]}");
return Sb.ToString();
}
Note that data parameters are case sensitive. i.e user , pass .
$.ajax({
type: "POST",
url: "default.aspx/Verify",
data: "{'user':'"+yourvariable+"','pass':'"+yourvariable+"'}",
dataType: "json",
contentType: "application/json; charset=utf-8",
success: function (data) {
data = JSON && JSON.parse(data.d) || $.parseJSON(data.d);
if (data == "true") {
alert('Works');
}
else {
$(".ui-widget").slideDown(1000, function () { });
}
}
});

Categories

Resources