Passing HTML over AJAX call to C# MVC Controller. 500 Error - javascript

So I'm getting a bit stumped by this one. I've got multiple pages making lots of successful Ajax calls to my C# controllers on the back end with a variety of data, but now I'm trying to build a simple little content management functionality, and hence update the HTML in a database with new HTML from a JS editor.
Long story short, I've taken out all the heavy Database code and narrowed it down to the fact that either my controller won't accept anything with html tags, or my ajax code is having trouble sending it.
The Ajax function is:
$.ajax({
type: "POST",
url: '#Url.Action("UpdateContent", "Admin")',
data: {
elementId: elementId,
newContent: newContent
},
dataType: "json",
success: function (data) {
if (data.result == 'true') {
infoMessage('Content Updated!', 'success');
} else {
infoMessage('Error: ' + data.result + '. Nothing has been updated!', 'error');
}
},
error: function () {
alert('There was a problem contacting the server.');
}
});
And on my Controller side, I've taken away all the code to just leave some debugging write lines.
[HttpPost]
public ActionResult UpdateContent(string elementId, string newContent)
{
System.Diagnostics.Debug.WriteLine("!" + elementId);
System.Diagnostics.Debug.WriteLine("!" + newContent);
string _result = "true";
return Json(new { result = _result });
}
Now the interesting thing is that when I have newContent in the data paramater in the Ajax request set to anything like <p>hello</p> those writelines don't even get called and the whole ajax call fails. Yet when I just use a normal string e.g. hello it works fine. I've further narrowed it down to just the opening html bracket, so even <p would fail.
With this in mind, what is happening here? And secondly, what is the correct way to send html back to the controller via Ajax so this doesn't happen?

ASP.NET has request validation enabled by default to help protect against XSS. You can disable this by adding the ValidateInput attribute to your action:
[HttpPost]
[ValidateInput(false)]
public ActionResult UpdateContent(string elementId, string newContent)
{
System.Diagnostics.Debug.WriteLine("!" + elementId);
System.Diagnostics.Debug.WriteLine("!" + newContent);
string _result = "true";
return Json(new { result = _result });
}
You'll also need to add the following to your web.config:
<httpRuntime requestValidationMode="2.0" />
A newer (and better) alternative is to use the AllowHtml attribute which you would apply to a property on your model. This is preferred because you're only allowing this prop to bypass validation instead of the entire request.
class MyModel
{
[AllowHtml]
public string MyHtml { get; set; }
}

Related

Why is XML I'm passing via AJAX to an MVC controller not getting there?

I am trying to pass an XML string from the HTML/JavaScript client side to the ASP.NET MVC server side. The problem is that the XML string never reaches the server, whereas an ordinary "non-XML" string will be successfully transferred.
The relevant JavaScript code on the client side is the following:
function TransferXmlDataToServer() {
var sXml = "<Tag>This is an XML test string.</Tag>"
$.ajax({
type: "POST",
url: '#Url.Action("TransferXMLData", "Home")',
data: { sInputXml: sXml },
dataType: "json",
success: function(sReturnValue) {
alert("Value returned from server is: " + sReturnValue);
},
error: function() {
alert("There was an error on the server side");
}
})
};
This is the corresponding function in the MVC Home controller on the server side:
public JsonResult TransferXMLData(string sInputXml) {
// The arguments' name must match those used in the View's Ajax call
return Json("Success");
}
When the TransferXmlDataToServer is invoked from the client side, the There was an error on the server side message is displayed. I have put some debugging printing statements in the TransferXMLData on the server side that are not invoked, showing that one does not even enter in this function.
On the other hand, when
sXml = "<Tag>This is an XML test string.</Tag>"
is replaced by
sXml = "This is a test string."
everything works as expected.
Additional notes:
This was tried with IE11 and Edge.
I tried to convert the XML string to Serialized Json prior to sending it to the server, to no avail.
I would greatly appreciate knowing what I am doing wrong.
Thanks a lot.
This is because by default asp.net protects against content that looks like HTML mark-up being sent to a controller action un-encoded. You need to decorate your action with the ValidateInputAttribute to let the content through:
[ValidateInput(false)]
public JsonResult TransferXMLData(string sInputXml)
{
// The arguments' name must match those used in the View's Ajax call
return Json("Success");
}

How to pass the text within an anchor tag to the controller [duplicate]

I have tried for hours to get this working, and I am really hoping one of you knows (a heck of a lot) more about this than I. When the client keys up in a textbox, I would like to call the MVC C# controller method called updateOrder(). Ideally, I would like to access form elements with a FormCollection (the form is called "createOrder").
In the controller, I have:
C#
[WebMethod]
public static void updateOrder(){
string s = "asdf";
}
The string declaration above is breakpointed. In the view, I have a method I basically copy and pasted that I found on stackoverflow:
JavaScript
function updateOrderJS() {
var $form = $('form[id="createOrder"]');
$.ajax({type : "POST",
url : $form.attr('action'),
data : $form.serialize(),
error : function(xhr, status, error) {},
success : function(response) {
updateOrder();
}
});
return false;
}
The event is simply:
JavaScript
updateOrderJS();
The updateOrderJS() method fires (checked with an alert), but the breakpoint does not.
In Asp.Net MVC, you do not need to decorate your method with WebMethod. You just create an Action (which is a method) and return a result from it. For sample:
public class CustomerController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult UpdateOrder()
{
// some code
return Json(new { success = true, message = "Order updated successfully" }, JsonRequestBehavior.AllowGet);
}
}
And in your View, you could try a javascript like this (using the $.ajax jquery method -- see the comments):
$.ajax({
url: '#Url.Action("UpdateOrder")', // to get the right path to controller from TableRoutes of Asp.Net MVC
dataType: "json", //to work with json format
type: "POST", //to do a post request
contentType: 'application/json; charset=utf-8', //define a contentType of your request
cache: false, //avoid caching results
data: {}, // here you can pass arguments to your request if you need
success: function (data) {
// data is your result from controller
if (data.success) {
alert(data.message);
}
},
error: function (xhr) {
alert('error');
}
});
In MVC, you don't need the [WebMethod] stuff - you just can have a regular controller action returning an ActionMethod (or null if you don't need a return value). The WebMethod attribute with static methods is for WebForms, not MVC.
public ActionMethod updateOrder(MyModel someModel) {
// Do something
return null;
}
Your URL in the javascript would be the URL to that action, which you can get to in Razor using #Url.Action("updateOrder", "Orders"), where "Orders" is the name of your controller.
Ensure "url" is in the format page.aspx/updateOrder.
Specify datatype: json
Ensure your updateOrderJS() is being called.
Ensure contentType: "application/json; charset=utf-8" is included.
Note: [WebMethod] is used for calling webforms methods, not MVC.
It looks like you're putting the URL of the MVC route in the action attribute of your <form> tag. I can't see what that attribute looks like because you didn't post your html, but from what I can see the value of that attribute might be wrong.
Most of the time, the URL to a specific MVC action is http://ServerDomain/Path(IfAny)/ControllerName/ActionName. For example, if you have a controller and action like this...
public class StackController
{
[HttpPost]
public ActionResult Overflow()
{
return View();
}
}
...and your ASP.NET application is deployed to www.example.com, the URL in the action attribute of your <form> tag would be http://www.example.com/Stack/Overflow.
Of course, it's possible for other settings in your ASP.NET MVC to change these URLs, such as the route setup in your global.asax's RegisterRoutes method, or perhaps if your controllers are divided into Areas. If the URL of your <form> looks correct, please post the html along with any relevant controller routing code in your ASP.NET app.
If your form is inside of a Razor view (cshtml file), you can use <form action="#Url.Action({ controller = "ControllerName", action = "ActionName" })" method="post"> to generate the correct form URL.

Call WebMethod in C# codebehind without using a server form in ASPX page

Due to issues with styling, and needing multiple forms on one single web page, I currently have a form that is outside of the normal form with runat=server.
Is it possible for me to still call a WebMethod in the C# codebehind of this web page using ajax? I want to submit the information from this form to the same connection string that I am using earlier in the page, in a different form.
Here is my current code:
$().ready(function () {
$("input[type=submit]").click(function () {
handleClick();
createJob();
});
});
function createJob() {
var txtTestValue = document.getElementById('jobTitle').value;
$.ajax({
// POST signals a data request
type: "POST",
// This directs which function in the c# code behind to use
url: "Account/help.aspx/CreateJob",
// The paramater pageIndex, page number we need to load, to pass to GetCustomers(int pageIndex)
data: txtTestValue,
// Type of data we are sending to the server (i.e. the pageIndex paramater)
contentType: "application/json; charset=utf-8",
// Type of data we expect back from the server (to fill into the html ultimately)
dataType: "text",
// If all goes smoothly to here, run the function that fills our html table
success: OnSuccess,
// On failure, error alert user (aka me so that I know something isn't working)
failure: function (response) {
alert("failure");
},
error: function (response) {
alert("error");
}
});
});
And my WebMethod in the codebehind:
[WebMethod]
public string CreateJob()
{
//rest of my database code here
}
Sorry for the confusion but it's doing everything right up until the ajax code, and then seems to ignore it (and returns that the ajax failed with an error). My code is not reaching the WebMethod and any breakpoints I set in Visual Studio are not triggered in the page header. Thanks in advance for your help!
You need to declare the method as static.
[WebMethod]
public static string CreateJob()
^^^^^
{
//rest of my database code here
}
Another issue is if input[type=submit] is ASP.Net Button control, it will post back to server. You cannot use ASP.Net Server control to make jQuery Ajax call - $.ajax.
// This code won't work if `input[type=submit]` is a server button control
$(function () {
$("input[type=submit]").click(function () {
handleClick();
createJob();
});
});
you need to use regular html input or button control with type=button instead of type=submit.
The webmethod should be static.
[WebMethod]
public static string CreateJob()
{
//rest of my database code here
}

Passing CKEDITOR.instances.editor1.getData() to HTTPPost gives error

I am reading the HTML from the CKEditor and am able to display it in the alert but for some odd reason when I get to the ajax post it gives an error. I have identified this by removing it and passing a plain string just in case. That works fine.
function GetHTML() {
var _content = CKEDITOR.instances.editor1.getData();
alert(content);
var _filename = $("#pages").val();
var url = "/CMS/UpdateHTML/";
$.ajax({
url: url,
data: {content: _content, filename: _filename },
cache: false,
type: "POST",
success: function (data) {
},
error: function (reponse) {
alert("error : " + reponse);
}
});
}
I never actually get to the controller code. It just gives an error
error : [object Object]
the code in the controller is
<HttpPost()>
Function UpdateHTML(content As String, filename As String) As ActionResult
stop
Return Json("")
End Function
I found the answer to my problem it seems that if you place the attribute in the code it works.
<ValidateInput(False)>
I saw this in an article Using CKEditor with Razor for .NET MVC 3
In the article it is mentioned how this is very important else an error will be generated.
"[HttpRequestValidationException (0x80004005): A potentially dangerous
Request.Form value was detected from the client..." exception is
thrown because there is HTML being sent to the server. The
[ValidateInput(false)] attribute will prevent this error happening,
however we are opening ourselves up to a security vulnerability.

Call javascript from MVC controller action

Can I call javascript function from MVC controller action (not from view page) and get return value? How?
I need to make request to server from code (.cs) using javascript like here (but this is aspx page)
function getInitData() {
var code; code = 'return {' ;
code += 'me: API.getProfiles({uids: API.getVariable({key: 1280}), fields: "photo"})[0]';
code += '};'
VK.Api.call('execute', { 'code': code }, onGetInitData);
}
For those that just used a standard form submit (non-AJAX), there's another way to fire some Javascript/JQuery code upon completion of your action.
First, create a string property on your Model.
public class MyModel
{
public string JavascriptToRun { get; set;}
}
Now, bind to your new model property in the Javascript of your view:
<script type="text/javascript">
#Model.JavascriptToRun
</script>
Now, also in your view, create a Javascript function that does whatever you need to do:
<script type="text/javascript">
#Model.JavascriptToRun
function ShowErrorPopup() {
alert('Sorry, we could not process your order.');
}
</script>
Finally, in your controller action, you need to call this new Javascript function:
[HttpPost]
public ActionResult PurchaseCart(MyModel model)
{
// Do something useful
...
if (success == false)
{
model.JavascriptToRun= "ShowErrorPopup()";
return View(model);
}
else
return RedirectToAction("Success");
}
You can call a controller action from a JavaScript function but not vice-versa. How would the server know which client to target? The server simply responds to requests.
An example of calling a controller action from JavaScript (using the jQuery JavaScript library) in the response sent to the client.
$.ajax({
type: "POST",
url: "/Controller/Action", // the URL of the controller action method
data: null, // optional data
success: function(result) {
// do something with result
},
error : function(req, status, error) {
// do something with error
}
});
Yes, it is definitely possible using Javascript Result:
return JavaScript("Callback()");
Javascript should be referenced by your view:
function Callback(){
// do something where you can call an action method in controller to pass some data via AJAX() request
}
It is late answer but can be useful for others.
In view use ViewBag as following:
#Html.Raw("<script>" + ViewBag.DynamicScripts + "</script>")
Then from controller set this ViewBag as follows:
ViewBag.DynamicScripts = "javascriptFun()";
This will execute JavaScript function.
But this function would not execute if it is ajax call.
To call JavaScript function from ajax call back, return two values from controller and write success function in ajax callback as following:
$.ajax({
type: "POST",
url: "/Controller/Action", // the URL of the controller action method
data: null, // optional data
success: function(result) {
// do something with result
},
success: function(result, para) {
if(para == 'something'){
//run JavaScript function
}
},
error : function(req, status, error) {
// do something with error
}
});
from controller you can return two values as following:
return Json(new { json = jr.Data, value2 = "value2" });
There are ways you can mimic this by having your controller return a piece of data, which your view can then translate into a JavaScript call.
We do something like this to allow people to use RESTful URLs to share their jquery-rendered workspace view.
In our case we pass a list of components which need to be rendered and use Razor to translate these back into jquery calls.
If I understand correctly the question, you want to have a JavaScript code in your Controller. (Your question is clear enough, but the voted and accepted answers are throwing some doubt)
So: you can do this by using the .NET's System.Windows.Forms.WebBrowser control to execute javascript code, and everything that a browser can do. It requires reference to System.Windows.Forms though, and the interaction is somewhat "old school". E.g:
void webBrowser1_DocumentCompleted(object sender,
WebBrowserDocumentCompletedEventArgs e)
{
HtmlElement search = webBrowser1.Document.GetElementById("searchInput");
if(search != null)
{
search.SetAttribute("value", "Superman");
foreach(HtmlElement ele in search.Parent.Children)
{
if (ele.TagName.ToLower() == "input" && ele.Name.ToLower() == "go")
{
ele.InvokeMember("click");
break;
}
}
}
}
So probably nowadays, that would not be the easiest solution.
The other option is to use Javascript .NET or jint to run javasctipt, or another solution, based on the specific case.
Some related questions on this topic or possible duplicates:
Embedding JavaScript engine into .NET
Load a DOM and Execute javascript, server side, with .Net
Hope this helps.
The usual/standard way in MVC is that you should put/call your all display, UI, CSS and Javascript in View, however there is no rule to it, you can call it in the Controller as well if you manage to do so (something i don't see the possibility of).
Since your controller actions execute on the server, and JavaScript (usually) executes on the client (browser), this doesn't make sense. If you need some action to happen by default once the page is loaded into the browser, you can use JavaScript's document.OnLoad event handler.
<script>
$(document).ready(function () {
var msg = '#ViewBag.ErrorMessage'
if (msg.length > 0)
OnFailure('Register', msg);
});
function OnSuccess(header,Message) {
$("#Message_Header").text(header);
$("#Message_Text").text(Message);
$('#MessageDialog').modal('show');
}
function OnFailure(header,error)
{
$("#Message_Header").text(header);
$("#Message_Text").text(error);
$('#MessageDialog').modal('show');
}
</script>

Categories

Resources