I have several Ajax.BeginForm on my MVC website. Meanwhile I need to handle the beforeSend event of my Ajax calls.
So the below code works for my manual jquery ajax calls, but it doesn't work with the Ajax.BeginForm helpers:
$.ajaxSetup({
'beforeSend': function (xhr) {
alert('');
}
});
Is there anyway to handle the beforeSend event on the MVC Ajax.BeginForm?
-------------------------------------------EDIT -------------------------------------
I need the before send event since I want to change the request headers :
'beforeSend': function (xhr) {
securityToken = $('[name=__RequestVerificationToken]').val();
xhr.setRequestHeader('__RequestVerificationToken', securityToken);
}
Thanks
I think you are following samples from http://richiban.wordpress.com/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/ This post does not address the support of Ajax form integration. I did some tests and found the solution.
I assume you use MVC4 with jquery-1.9.1.js, jquery.validate.unobtrusive.js and jquery.unobtrusive-ajax.js referenced.
Following is my code
#model WebApplication1.Models.DummyModel
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<script src="~/Scripts/jquery-1.9.1.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
</head>
<body>
<div id="Parent">
#using (Ajax.BeginForm(new AjaxOptions { HttpMethod = "post", OnBegin = "BeginClient" }))
{
#Html.AntiForgeryToken();
<div>First Name</div><div>#Html.TextAreaFor(m => m.FirstName)</div>
<div>Last Name</div><div>#Html.TextAreaFor(m => m.LastName)</div>
<input type="submit" value="Submit" />
}
</div>
<script type="text/javascript">
function BeginClient(xhr) {
alert("posting...");
securityToken = $('[name=__RequestVerificationToken]').val();
xhr.setRequestHeader('__RequestVerificationToken', securityToken);
}
$.ajaxSetup({
'beforeSend': function (xhr) {
securityToken = $('[name=__RequestVerificationToken]').val();
alert(securityToken);
xhr.setRequestHeader("__RequestVerificationToken", securityToken);
}
});
</script>
</body>
</html>
Basically you need to leverage onBegin event, see http://johnculviner.com/ajax-beginform-ajaxoptions-custom-arguments-for-oncomplete-onsuccess-onfailure-and-onbegin/ there is clear explanation what is the parameters for each event.
Then in your global attribute class, your code looks like
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class ValidateAntiForgeryTokenOnAllPostsAttribute : AuthorizeAttribute
{
/// <summary>
/// Executes authorization based on anti-forge token.
/// </summary>
/// <param name="filterContext">MVC pipeline filter context.</param>
public override void OnAuthorization(AuthorizationContext filterContext)
{
var request = filterContext.HttpContext.Request;
// Only validate POSTs
if (request.HttpMethod == WebRequestMethods.Http.Post)
{
// Ajax POSTs and normal form posts have to be treated differently when it comes to validating the AntiForgeryToken
if (request.IsAjaxRequest())
{
var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
var cookieValue = antiForgeryCookie != null
? antiForgeryCookie.Value
: null;
AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
}
else
{
new ValidateAntiForgeryTokenAttribute().OnAuthorization(filterContext);
}
}
}
}
By doing this way you can still force to use anti-forgery token with Ajax form.
Hope this helps.
For Ajax.BeginForm you can use AjaxOptions.OnBegin:
#using (Ajax.BeginForm("actionName", "controllerName", new AjaxOptions() {
OnBegin = "requestBeginHandler"})) {
...markup here...
}
Update. To add new request header you can do something like this:
function requestBeginHandler(ajaxContext) {
var request = ajaxCOntext.get_request();
securityToken = $('[name=__RequestVerificationToken]').val();
request.get_headers()['__RequestVerificationToken'] = securityToken;
}
Related
So I have a "discount" html page, where a user is prompted to enter a promo code, by using an Ajax GET request from the buttons OnClick, I am able to transfer this promo code to my spring controller, where I manipulate the data appropriately.
For some reason I am unable to "return" a new page from this controller, I do not get any noticeable errors on my server side but on my client side I get this error:
I am not sure if this is related or relevant.
I was wondering is my logic behind this flawed or am I not implementing the correct syntax to return a new page after the AJAX call.
Note: The AJAX request works fine as I am able to get a system.out.print to the console at the bottom of the controller with the relevant info. that I passed.
Here is my html code:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1"></meta>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"></link>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script type="text/javascript">
function myFunction(){
var code = document.getElementById("code").value;
var price = document.getElementById("price").value;
$.ajax({
type: "GET",
url: "/calculateDiscount",
data: {
code: code
}, // parameters
contentType: "application/json; charset=utf-8",
datatype: 'json'
//alert(status);
});
}
</script>
</head>
<body>
<div>
<center>
<h3>Total Price: $<text th:text="${totalPrice}" id="price"/> </h3>
<input type="text" name="firstname" id="code">
<button onclick="myFunction()">Calculate Discount</button>
<a style="color:blue" th:href="#{/welcome}">HomeScreen!</a>
<br />
<!-- <a style="color:blue" th:if="${myteam != null}" th:href="#{/leaveteam/{id}(id=${myteam?.id})}">Leave Team?!</a>
-->
</center>
</div>
</body>
</html>
Controller:
#RequestMapping(value="/calculateDiscount", method=RequestMethod.GET)
#ResponseBody
public String CalculateDiscount(Model model, #RequestParam("code") String code, RedirectAttributes redirectAttributes) {
///need to calculate price if codes correct then return page with card info then after proceed call purchasebooks controller!
System.out.println("Price: " + code );
Authentication loggedInUser = SecurityContextHolder.getContext().getAuthentication();
String email = loggedInUser.getName();
UserLogin user = uR.findByUserName(email);
int totalPrice = 0;
if (code.equals("Discount1010"))
{
Set<Book> books = user.getBooks();
for (Book b : books)
{
totalPrice = totalPrice + b.getPrice();
}
int discountPrice = (int) (totalPrice * .80);
model.addAttribute("totalPrice", totalPrice);
System.out.println("Price: " + discountPrice );
}
else {
Set<Book> books = user.getBooks();
for (Book b : books)
{
totalPrice = totalPrice + b.getPrice();
}
System.out.println("Price: " + totalPrice );
model.addAttribute("totalPrice", totalPrice);
}
return "payment";
}
The page I am trying to return:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1"></meta>
<title>Insert title here</title>
</head>
<body>
<h3>Total Price: $<text th:text="${totalPrice}" id="price"/> </h3>
</body>
</html>
Any more info needed let me know.
K.
EDIT: In response to one of the answers below, I do have csrf disabled.
Here is my WebSecurityConfig class:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserLoginRepository userLoginRepository;
//http.authorizeRequests().antMatchers("/", "/home", "/registeruser").permitAll().antMatchers("/admin").hasRole("ADMIN")
#Autowired
DataSource dataSource;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/home", "/registeruser").permitAll().antMatchers("/admin").hasRole("ADMIN")
.anyRequest().authenticated().and().formLogin().loginPage("/login").permitAll().and().logout()
.permitAll();
http.exceptionHandling().accessDeniedPage("/403");
http.csrf().disable();
//disable csrf to allow communication (we also dont need for this fyp as its not live)
}
#Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/fonts/**", "/images/**", "/css/**");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource)
.usersByUsernameQuery("select user_name,password,user_status from user_login where user_name=?")
.authoritiesByUsernameQuery("select user_name, password from user_login where user_name=?");
}
#Bean
public static NoOpPasswordEncoder passwordEncoder() {
return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance();
}
}
Update: #ResponseBody annotation was added to the controller method, problem still persists
I guess this is CSRF problem. You have Spring Security implemented (I can see
SecurityContexHolder class) and probably csrf enabled - this is default setting. If you want to disable it just use this
Java configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
XML:
<http>
<!-- ... -->
<csrf disabled="true"/>
</http>
But if you want to keep csrf enabled, you need to pass csrf token to ajax header. To do this, include csrf to meta tag:
<head>
<meta name="_csrf" th:content="${_csrf.token}"/>
<meta name="_csrf_header" th:content="${_csrf.headerName}"/>
And then include csrf to Ajax request:
var token = /*[[${_csrf.token}]]*/ '';
var header = /*[[${_csrf.headerName}]]*/ '';
$(document).ajaxSend(function(e,xhr,options) {
xhr.setRequestHeader(header, token);
});
I am sending an static html with some dynamic content to user email id using c# and JQuery.
Below is the JavaScriot file from where I am calling th method SendEmail.
$(".EmailInvoice").click(function () {
$.ajax({
type: 'POST',
url: siteUrl + '/invoiceEmail.asmx/SendEmail',
data: JSON.stringify({ }),
contentType: "application/json; charset=utf-8",
dataType: "json",
async: true,
success: function (data, status) {
},
failure: function (data) {
},
error: function () {
alert("error");
}
});
Below is the invoiceEmail.asmx file
using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Web;
using System.Net.Mail;
using System.Web.Services;
using System.Web.Hosting;
namespace meltwish
{
/// <summary>
/// Summary description for invoiceEmail
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[System.Web.Script.Services.ScriptService]
public class invoiceEmail : System.Web.Services.WebService
{
public static string PopulateBody(string userName, string title, string url, string description)
{
string body = string.Empty;
using (StreamReader reader = new StreamReader(HostingEnvironment.MapPath("~/EmailTemplate.html")))
{
body = reader.ReadToEnd();
}
body = body.Replace("{UserName}", userName);
body = body.Replace("{Title}", title);
body = body.Replace("{Url}", url);
body = body.Replace("{Description}", description);
return body;
}
public static void SendHtmlFormattedEmail(string recepientEmail, string subject, string body)
{
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress(ConfigurationManager.AppSettings["username"]);
mailMessage.Subject = subject;
mailMessage.Body = body;
mailMessage.IsBodyHtml = true;
mailMessage.To.Add(new MailAddress(recepientEmail));
SmtpClient smtp = new SmtpClient();
smtp.Host = ConfigurationManager.AppSettings["Host"];
smtp.EnableSsl = Convert.ToBoolean(ConfigurationManager.AppSettings["EnableSsl"]);
System.Net.NetworkCredential NetworkCred = new System.Net.NetworkCredential();
NetworkCred.UserName = ConfigurationManager.AppSettings["UserName"];
NetworkCred.Password = ConfigurationManager.AppSettings["Password"];
smtp.UseDefaultCredentials = true;
smtp.Credentials = NetworkCred;
smtp.Port = int.Parse(ConfigurationManager.AppSettings["Port"]);
smtp.Send(mailMessage);
}
//object sender, EventArgs e
[WebMethod]
public static string SendEmail()
{
//string body = this.PopulateBody("John",
string body = PopulateBody("John",
"Fetch multiple values as Key Value pair in ASP.Net AJAX AutoCompleteExtender",
"http://www.aspsnippets.com/Articles/Fetch-multiple-values-as-Key-Value-pair-" +
"in-ASP.Net-AJAX-AutoCompleteExtender.aspx",
"Here Mudassar Ahmed Khan has explained how to fetch multiple column values i.e." +
" ID and Text values in the ASP.Net AJAX Control Toolkit AutocompleteExtender"
+ "and also how to fetch the select text and value server side on postback");
SendHtmlFormattedEmail("wajedkh#gmail.com", "New article published!", body);
//this.SendHtmlFormattedEmail("wajedkh#gmail.com", "New article published!", body);
return "sajjad";
}
}
}
This is the HTMl file that is added to the project. The name is EmailTemplate.html
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<!-- Server CDN Files -- Start -->
<!--<link class="temp" href="http://klcdn.meltwish.com/styles/store/1.0.2/store.css" rel="stylesheet" />-->
<link href="http://localhost:60339/styles/store/1.0.2/store.css" rel="stylesheet" />
</head>
<body>
<img src = "http://www.aspsnippets.com/images/Blue/Logo.png" /><br /><br />
<div style = "border-top:3px solid #22BCE5"> </div>
<span style = "font-family:Arial;font-size:10pt">
Hello <b>{UserName}</b>,<br /><br />
A new article has been published on ASPSnippets.<br /><br />
<a style = "color:#22BCE5" href = "{Url}">{Title}</a><br />
{Description}
<br /><br />
Thanks<br />
ASPSnippets
</span>
</body>
</html>
This i have added in the Web.Config file.
<appSettings>
<add key="Host" value="smtp.gmail.com"/>
<add key="EnableSsl" value="true"/>
<add key="UserName" value="hussainsajjad9991#gmail.com"/>
<add key="Password" value="xxxxx"/>
<add key="Port" value="587"/>
</appSettings>
Actually whenever I have trying to call the javascript ajax method it is going to the error content.
Help me....
Following C# Code Work For me
[System.Web.Services.WebMethod]
public static string SendEmail()
{
using (MailMessage mm = new MailMessage("From", "To"))
{
mm.Subject = "Subject ";
mm.Body = "<html><head></head><body> Content</body></html>";
mm.IsBodyHtml=true;
SmtpClient smtp = new SmtpClient();
smtp.Host = "smtp.gmail.com";
smtp.EnableSsl = false;
NetworkCredential NetworkCred = new NetworkCredential("From", "password");
smtp.UseDefaultCredentials = false;
smtp.Credentials = NetworkCred;
smtp.Port = 587;
smtp.Timeout = 2000000;
smtp.Send(mm);
return "Success";
}
}
And Use Ajax Code
$.ajax({
type: "POST",
url: siteUrl + '/invoiceEmail.aspx/SendEmail',
data: "{}",
contentType: "application/json; charset=utf-8",
datatype: "jsondata",
async: "true",
success: function (t) { alert(t); },
error: function (t) { alert(t); } })
Let's say I've the following sample code (JavaScript):
// Client A
var conn = new XSockets.WebSocket([wsUri]);
conn.on(XSockets.Events.open, function (clientInfo) {
conn.publish("some:channel", { text: "hello world" });
});
// Client B (subscriber)
var conn = new XSockets.WebSocket([wsUri]);
conn.on(XSockets.Events.open, function (clientInfo) {
conn.on("some:channel", function(message) {
// Subscription receives no message!
});
});
Client B never receives a message. Note that this is a sample code. You might think that I don't receive the message because Client B got connected after Client A sent the message, but in the actual code I'm publishing messages after both sockets are opened.
The server-side XSocketsController is working because I'm using it for server-sent notifications.
What am I doing wrong? Thank you in advance!
It looks like you have mixed up the pub/sub with the rpc, but I cant tell for sure if you do not post the server side code as well.
But what version are you using? 3.0.6 or 4.0?
Once I know the version and have the server side code I will edit this answer and add a working sample.
EDIT (added sample for 3.0.6):
Just wrote a very simple chat with pub/sub.
Controller
using XSockets.Core.Common.Socket.Event.Interface;
using XSockets.Core.XSocket;
using XSockets.Core.XSocket.Helpers;
namespace Demo
{
public class SampleController : XSocketController
{
/// <summary>
/// By overriding the onmessage method we get pub/sub
/// </summary>
/// <param name="textArgs"></param>
public override void OnMessage(ITextArgs textArgs)
{
//Will publish to all client that subscribes to the value of textArgs.#event
this.SendToAll(textArgs);
}
}
}
HTML/JavaScript
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="Scripts/jquery-2.1.1.js"></script>
<script src="Scripts/XSockets.latest.min.js"></script>
<script>
var conn;
$(function() {
conn = new XSockets.WebSocket('ws://127.0.0.1:4502/Sample');
conn.onopen = function(ci) {
console.log('open', ci);
conn.on('say', function(d) {
$('div').prepend($('<p>').text(d.text));
});
}
$('input').on('keydown', function(e) {
if (e.keyCode == 13) {
conn.publish('say', { text: $(this).val() });
$(this).val('');
}
});
});
</script>
</head>
<body>
<input type="text" placeholder="type and hit enter to send..."/>
<div></div>
</body>
</html>
Regards
Uffe
Hi regarding https://github.com/shichuan/javascript-patterns/blob/master/general-patterns/function-declarations.html I define my JS function like this
<script language="javascript">
var clearMessage = function ClearMessage() {
$("#result").html("");
};
</script>
And I try to call it in OnBegin method from MVC ajax,
#using (Ajax.BeginForm(new AjaxOptions() { HttpMethod = "post", OnBegin = "ClearMessage" }))
But I getting error that function not exit,
how to call my function that described by this best practice ? (without var clearMessage evering working correct)
Never seen such syntax. Don't even know if it is valid javascript.
Try defining your function like this:
<script type="text/javascript">
var ClearMessage = function() {
$("#result").html("");
};
</script>
or like this (which is pretty much the same):
<script type="text/javascript">
function ClearMessage() {
$("#result").html("");
};
</script>
For jQuery template:
http://api.jquery.com/category/plugins/templates/
I want to be able to dynamically load the templates from a server, rather than predefining it on the page.
The demos I saw on the projects are using predefined templates. After some research I found out that it is possible.
I try doing this and it doesn't work:
<script src="child.html" type="text/x-jquery-tmpl"></script>
I tried doing this and it doesn't work:
$(function () {
$.get("child.html", function (data) {
//Add template
$.template("tmplChild", data);
});
//template binds before async call is done
$.tmpl("tmplChild").appendTo("body");
});
And finally, I have get it down to the following hack:
so.html (This is the main page):
<html>
<head>
<title></title>
</head>
<body>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.3/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.js"></script>
<script type="text/javascript" src="so.js"></script>
<script type="text/javascript">
$(function () {
initTemplates(templateReady);
});
function templateReady() {
$.tmpl("tmplChild").appendTo("body");
}
</script>
</body>
</html>
child.html (This is the child template)
<h1>Child Loaded</h1>
so.js (This is my hack for ajaxly loading the js templates)
function initTemplates(callback) {
var templateUrl = "child.html";
var templateName = "tmplChild";
initTemplate(templateUrl, templateName, callback);
}
function initTemplate(url, name, callback) {
var opts =
{
type: "GET",
url: url,
dataType: ($.browser.msie) ? "text" : "xml",
success: function (data) {
xmlCallback(data, name, callback);
},
error: function (x) {
xmlCallback(x.responseText, name, callback);
}
}
$.ajax(opts);
}
function xmlCallback(data, name, callback) {
if (typeof data != "string") {
if (window.ActiveXObject) {
var str = data.xml;
data = str;
}
// code for Mozilla, Firefox, Opera, etc.
else {
var str = (new XMLSerializer()).serializeToString(data);
data = str;
}
}
//only takes strings!
$.template(name, data);
callback();
}
And here's what I don't like about it.
This doesn't work on Chrome
It seems like a lot of code just to load some template
I lost the ability to use $(document).ready(). I must now put all my code in this templateReady() method to be "template safe".
Is there a way around this?
Thanks,
Chi
Just load the template body as simple text and forget about putting it in a dummy <script> block. You can use $.tmpl(body, params) to populate the template and turn it into a string for appending to the DOM.
The whole thing with "not really script" <script> blocks is just a convenience useful in some situations.
edit — example:
$.get("/some/url/for/a/template", function(templateBody) {
var expandedTemplate = $.tmpl(templateBody, { param1: 0, param2: "Hello World" });
});
If the goal is to fetch a unique template each time you get data via ajax, then you might try fetching the template at the same time and include it in your data, that is if you have the luxury of modifying the returned object (anonymous object in .Net). Then you can store the template anywhere you want and you only need 1 ajax call for both the data and the template.
Refer here:
https://www.npmjs.com/package/jlate
use CDN:
<script src="https://cdn.jsdelivr.net/combine/npm/lodash,npm/jlate#0.0.2/jlate/JLate.min.js"></script>
HTML Code:
<body>
<div>
<jlate id="my_temp" src="template/jlate_title.html" type="template">
Loading...
</jlate>
</div>
</body>
Javascript:
$$("#my_temp").jlate({ title: "sample title"});