I am using Window.onpopstate method in ajax for SPA, before that I used window.history but I got an error like
"jquery-1.10.2.js:8720 Failed to load location:
http://localhost:22102/Coach/AddCoaches, state:
{"url":"/Coach/AddCoaches"}: Cross origin requests are only supported
for protocol schemes: http, data, chrome, chrome-extension, https."
my ajax call is
<script>
$('#loadingImage').hide();
$('.jq-navigation-link').click(function () {
var url = $(this).data('url');
loadPartial(url)
})
function loadPartial(url)
{
$('#renderPartial').html("");
$('#loadingImage').show();
$.ajax({
url: url + "?ispartial=" + true,
type: "GET",
success: function (data) {
$('#loadingImage').hide();
$('#renderPartial').html(data);
}
})
window.history.pushState({ url: url }, '', url);
}
window.onpopstate = function (event) {
debugger
if (event.state) {
var url = "location: " + document.location + ", state: " + JSON.stringify(event.state);
load(url);
}
};
</script>
<script type="text/javascript">
$('body').delegate(".btnUrl", "click", function (e) {
e.preventDefault();
var url = $('.btnUrl').data('url');
//var test = $('.form').serialize();
$('#loadingImage').show();
$.ajax({
async: true,
url: url,
type: 'POST',
data: $('.form').serialize(),
dataType: "json",
success: function (data) {
if (data.Success) {
$('#loadingImage').hide();
loadPartial(data.Url);
}
else {
$('#loadingImage').hide();
loadPartial(data.Url);
}
}
})
})
function load(url) {
$('#renderPartial').html("");
$('#loadingImage').show();
$.ajax({
url: url,
type: "GET",
success: function (data) {
$('#loadingImage').hide();
$('#renderPartial').html(data);
}
})
}
</script>
Error clearly says it is Cross origin requests. Your Web application is using port 8720 and you web API is using port 22102. Browser is considering requests as different origin and for security reason is blocking data for another site request.
For resolving this, you need to enable CORS on your application OR need to host Web application & Web API at same port or same IIS application.
For Enabling cors try:
install nuget package:
Install-Package Microsoft.AspNet.WebApi.Cors
In App_Start/WebApiConfig.cs, add following code in Register method before map routing :
config.EnableCors();
In API Controller, [EnableCors] attribute to the class:
[EnableCors(origins: "http://yoursitehere", headers: "*", methods: "*")]
public class TestController : ApiController
{
// Controller methods not shown...
}
OR
Adding the header through web.config
<httpProtocol>
<customHeaders>
<clear />
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
For more details refer:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/enabling-cross-origin-requests-in-web-api
https://forums.asp.net/post/5795304.aspx
Related
I created a test web application that is calling my MVC application. I can call the POST fine with Postman and wanted to try and call it from a web browser but I am getting a 405 error. ANy help would be great.
Failed to load resource: the server responded with a status of 405 (Method Not Allowed)
Test HTML Project
$.ajax({
type: "POST",
url: "URL",
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type': 'application/json'
},
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
crossDomain: true,
success: function (response) {
console.log('message: ' + "success" + JSON.stringify(json));
},
failure: function (error) {
console.log('message Error' + JSON.stringify(error));
}
});
MVC Application
public class PublicController : ApiController
{
[System.Web.Http.HttpPost]
public IHttpActionResult MethodTest(string key, string action)
{
}
}
web.config
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET,POST,PUT,DELETE,OPTIONS" />
</customHeaders>
</httpProtocol>
you have to fix your ajax.remove headers and contenttype and fix dataType and add data
$.ajax({
type: "POST",
url: "http://localhost:60876/WebApi/public/SkipAuthenticationAndLogin"
data:{
key:"key",
userName:"name",
succesUrl:"url"
},
dataType: "json",
success: function (response) {
console.log('message: ' + "success" + JSON.stringify(response));
},
failure: function (error) {
console.log('message Error' + JSON.stringify(error));
}
});
and remove post from action
public IHttpActionResult MethodTest(string key, string userName, string successUrl)
{
}
I want to post data in the Mssql Database using Asp.netCore Api and Html Form. I have Added This script to post data.but All the values are coming null
Jquery script in Html File
<script type="text/javascript">
var valdata = $("#formData").serialize();
$(document).ready(function () {
$("#btnsubmit").click(function (e) {
let formData = {};
$("#formData").serializeArray().map((x) => { formData[x.name] = x.value; });
$.ajax({
url: "https://localhost:44389/Register",
contentType: "application/json; charset=utf-8",
type: 'POST',
dataType: 'json',
data: valdata,
success: function (data) {
alert(data);
},
failure: function (data) {
alert("Failure: " + data);
},
error: function (data) {
alert("Error: " + data);
}
});
});
});
</script>
.net Core Api
[HttpPost]
[Route("Register")]
public void RegisterExecute([FromBody]CustmRegistration Register)
{
try
{
userInterface.InsertCustomer(Register);
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
but All the values are coming null
Where are these values null? my suggestion is to start debugging a bit more thoroughly.
Have you tried your api function trough postman or a tool likewise?
Settting breakpoints can be nice to look into your program's data at runtime.
if these values are null in your database it would be nice to see what userInterface.InsertCustomer(Register); does.
Once you know if your .net part is working start debugging your ajaxc call. take a look at the network section of the developer tools form the browser you are using.
If you have collected more data, people can help you more easelly.
1.When you use .serialize(), it generates the data in a query string format which needs to be sent using the default contentType which is application/x-www-form-urlencoded; charset=UTF-8, not as JSON. Either remove the contentType option or specify contentType: application/x-www-form-urlencoded; charset=UTF-8 can work.
2.Also you need move the serialize method into onclick event.
3.Be sure change [FromBody] to [FromForm].
Here is a whole working demo:
View:
#model CustmRegistration
<form id="formData">
<!--more code-->
<input type="button" id="btnsubmit"value="create" />
</form>
#section Scripts
{
<script type="text/javascript">
$(document).ready(function () {
$("#btnsubmit").click(function (e) {
var valdata = $("#formData").serialize(); //move to here...
$.ajax({
url: "/home/Register",
//contentType: "application/json; charset=utf-8",
type: 'POST',
dataType: 'json',
data: valdata,
success: function (data) {
alert(data);
},
failure: function (data) {
alert("Failure: " + data);
},
error: function (data) {
alert("Error: " + data);
}
});
});
});
</script>
}
Controller:
[HttpPost]
[Route("Register")]
public void RegisterExecute([FromForm]CustmRegistration Register)
{ //...}
I got CORS issue when I am trying to make post request to c# web api.
Below is the error:
Access to XMLHttpRequest at 'api url in different domain' from origin
'client url' has been blocked by CORS policy: Response to preflight
request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
The same API call with GET request is working.
Both sites are deployed with windows authentication enabled.
I am using Angular io, 1.7.** with typescript. Below is how I call the api with post request in typescript.
let httpHeader = new HttpHeaders();
httpHeader = httpHeader.set('Content-Type', 'application/json');
this.http.post(this.apiUrl, this.bodyObject,
{
headers: httpHeader,
withCredentials:true
}).pipe(map(response => {
return response;
})).subscribe(result => {
console.log(result);
}, function (err) {
console.log(err);
});
I first thought that it might be api cors issue and tested with below jquery code and it is working.
<script>
$.ajax({
url:apiUrl,
type: 'post',
data: {
serviceName: "Country"
},
xhrFields: {
withCredentials: true
},
dataType: 'json',
success: function (data) {
console.info(data);
},
error: function (err) {
console.error(err);
}
});
</script>
So I think, I have something to do with my angular code. Can you guy highlight me what could be the issue.
try to add this in $.ajax
headers: {
'Access-Control-Allow-Origin': '*',
'Content-Type':'application/json'
},
crossDomain: true,
In my .net core razor page project, i would like to call server side methods from a cshtml input without reloading the page. I'm still a newbie with razor pages.
.cshtml :
input type="submit" id="AddCart" asp-page-handler="AddToCart" hidden
Some JS to .click() the input.
.cs :
public async void OnPostAddToCart()
{
//code
}
So far i did not find a way to prevent the page reload and still access my server-side methods.
Thanks
EDIT :
Looking at the link provided by brad, i managed to make it work.
I added #Page "{handler?}" to write the url without the handler (not sure if it matters for ajax),
I set my ajax url to "thePage/theMethod",
I decorated my razor controller class with [ValidateAntiForgeryToken]
And mentioned the anti forgery token in ajax :
$.ajax({
url: "/mainPage/AddToCart",
type: "POST",
contentType: "application/json; charset=utf-8",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function () {
alert("success");
},
complete: function () {
alert("complete")
},
failure: function () {
alert("failure");
}
});
First ,change the naming of your Handler method like below :
public async void OnPostAddToCartAsync()
{
//code
}
Refer to Handler Methods in Razor Pages for more details on the nameing convention .
Second ,If you want to use ajax in Razor Pages , the URL pattern should be like "/mainPage?handler=AddToCart" .One thing to note down is, Razor Pages are designed to be protected from (CSRF/XSRF) attacks. Hence, Antiforgery token generation and validation are automatically included in Razor Pages. I believe that is the problem here. Your page may have antiforgery token present on the page if you have form tag in your HTML. But you need to pass the same in your Ajax request.
Add antiforgery token using #Html.AntiForgeryToken(), if not
present.
Modify your Ajax request to send the same in request header like
below:
<input type="button" id="AddCart" onclick="clickbtn()" value="Submit"/>
function clickbtn() {
$.ajax({
url: "/Test?handler=AddToCart",
type: 'POST',
beforeSend: function (xhr) {
xhr.setRequestHeader("X-XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
success: function ()
{
alert("success");
},
complete: function ()
{
alert("complete")
},
failure: function ()
{
alert("failure");
}
});
}
Since the script sends the token in a header called X-XSRF-TOKEN,
configure the antiforgery service to look for the X-XSRF-TOKEN
header:
services.AddAntiforgery(option => option.HeaderName = "X-XSRF-TOKEN");
Read this post Handle Ajax Requests in ASP.NET Core Razor Pages to know more about making ajax request with ASP.NET Core razor pages.
If you do not want to reload the page you must use ajax or XMLHttpRequest , (the former being based on the latter).
<script>
window.onload=function()
{
window.click=function()
{
$.ajax({
url: '[baseUrl/OnPostAddToCart]',
data: JSON.stringify(postData), //your data
type: 'POST',
contentType: 'application/json',
dataType: 'json',
success: function (result) {
alert(result); //do something if successful
},
complete: function(){
//do something on complete
},
failure: function (err) {
alert(err); // Display error message
}
});
}
}
</script>
<input onclick="click()" type="button"/>
Using XMLHttpRequest:
window.click=function()
{
var xhr = new XMLHttpRequest();
xhr.open("POST", "[Your URL]");
xhr.onload=function()
{
if(xhr.status==200)
resolve(xhr.response);
else
reject("error:"+xhr.status);
}
var data=JSON.stringify({some_data});
xhr.send(data);
}
Controller method
public class MyController:Controller
{
[HttPost]
[Route("/OnPostAddToCart")]
public async Task AddToCart(object data)
{
}
}
P.S For more information on ajax
I've found examples of have multiple handlers on a page and the associated naming convention (ie OnPostXXX) and 'asp-post-hanlder' tag helper. But how can I call one of these methods from an AJAX call.
I have an older example with a typical MVC view and controller but how does this work with a Razor Page?
For example if I take the base application and modify the About.cshtml page to the following:
#page
#model AboutModel
#{
ViewData["Title"] = "About";
}
<h2>#ViewData["Title"]</h2>
<h3>#Model.Message</h3>
<input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
#section Scripts {
<script type="text/javascript">
function ajaxTest() {
console.log("Entered method");
$.ajax({
type: "POST",
url: '/About', // <-- Where should this point?
contentType: "application/json; charset=utf-8",
dataType: "json",
error: function (xhr, status, errorThrown) {
var err = "Status: " + status + " " + errorThrown;
console.log(err);
}
}).done(function (data) {
console.log(data.result);
})
}
</script>
}
And on the model page About.cshtml.cs
public class AboutModel : PageModel
{
public string Message { get; set; }
public void OnGet()
{
Message = "Your application description page.";
}
public IActionResult OnPost() {
//throw new Exception("stop");
return new JsonResult("");
}
}
The OnPost is not called from the Ajax call.
Razor Pages automatically generates and validates Antiforgery tokens to prevent CSRF attacks. Since you aren't sending any token within your AJAX callback, the request fails.
To solve this problem you will have to:
Register the Antiforgery-Service
Add the token to your request
Add the antiforgery token to your page either by adding a <form> or by directly using the #Html.AntiForgeryToken HtmlHelper
1. Register the Antiforgery-Service in your Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
}
2. Modify your AJAX callback
In the AJAX callback we add additional code to send the XSRF-TOKEN with our request header.
$.ajax({
type: "POST",
url: '/?handler=YOUR_CUSTOM_HANDLER', // Replace YOUR_CUSTOM_HANDLER with your handler.
contentType: "application/json; charset=utf-8",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
dataType: "json"
}).done(function (data) {
console.log(data.result);
})
3. Add the antiforgery token to your page
You can accomplish this by adding a <form>:
<form method="post">
<input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
</form>
or by using the #Html.AntiForgeryToken:
#Html.AntiForgeryToken()
<input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
In both cases Razor Pages will automatically add a hidden input field which contains the antiforgery token once the page is loaded:
<input name="__RequestVerificationToken" type="hidden" value="THE_TOKEN_VALUE" />
Please see this related section of the documentation
https://learn.microsoft.com/en-us/aspnet/core/mvc/razor-pages/?tabs=visual-studio
The associations of URL paths to pages are determined by the page's location in the file system. The following table shows a Razor Page path and the matching URL
/Pages/Index.cshtml maps to / or /Index
/Pages/Contact.cshtml maps to /Contact
Everything works well, but some changes have to be made:
1)Open Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
services.AddMvc();
}
2)Open HomeController.cs:
[ValidateAntiForgeryToken]
public IActionResult OnPost()
{
return new JsonResult("Hello Response Back");
}
3)Open About.cshtml:
#{
ViewData["Title"] = "About";
}
<h2>#ViewData["Title"]</h2>
<h3>#ViewData["Message"]</h3>
<p>Use this area to provide additional information.</p>
<form method="post">
<input type="button" value="Ajax test" class="btn btn-default" onclick="ajaxTest();" />
</form>
<script src="~/lib/jquery/dist/jquery.js"></script>
<script type="text/javascript">
function ajaxTest() {
$.ajax({
type: "POST",
url: 'onPost',
contentType: "application/json; charset=utf-8",
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
dataType: "json"
}).done(function (data) {
console.log(data.result);
})
}
</script>
It should be noted that "onPost" was added inside the controller, so in AJAX the correct "url" should be indicated. Then:
url: 'onPost',
After looking at the answers above I got JSON ajax to work with .NET Core 2.1 Razor pages using Visual Studio 2017 Preview 2:
Startup.cs
services.AddAntiforgery(o => o.HeaderName = "XSRF-TOKEN");
PostJson.cshtml
#page
#model myProj.Pages.PostJsonModel
#{
ViewData["Title"] = "PostJson";
}
<input type="button" value="Post Json" class="btn btn-default" onclick="postJson();" />
<script>
function ajaxRazorPostJson(o) {
return $.ajax({
type: "POST",
data: JSON.stringify(o),
url: 'postJson',
contentType: "application/json; charset=utf-8",
beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); },
dataType: "json"
});
}
function postJson() {
ajaxRazorPostJson({ reqKey: "reqVal" }).done(data => alert(data));
}
</script>
PostJson.cshtml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Newtonsoft.Json.Linq;
namespace myProj.Pages
{
public class PostJsonModel : PageModel
{
public IActionResult OnPost([FromBody] JObject jobject)
{
// request buffer in jobject
return new ContentResult { Content = "{ \"resKey\": \"resVal\" }", ContentType = "application/json" };
// or ie return new JsonResult(obj);
}
}
}
Browser
http://localhost:44322/postJson
Accepted solution worked in local developing machine, but failed then deployed in Debian server behind Nginx reverse proxy (not found 404 error).
This is a working example with payload data:
<script type="text/javascript">
$('#btnPost').on('click', function () {
var payloadData; /*asign payload data here */
$.post({ /* method name in code behind, and full path to my view*/
url: '#Url.Action("OnPostAsync", "/Turtas/Inventorius/InventoriausValdymas")',
beforeSend: function (xhr) {
xhr.setRequestHeader("XSRF-TOKEN",
$('input:hidden[name="__RequestVerificationToken"]').val());
},
data: JSON.stringify({ payloadData }),
contentType: "application/json; charset=utf-8",
dataType: "json"
})
})
</script>
VS 2017; .Net Core 2.2 Razor Pages; jQuery 3.3.1
I'm adding this for posterity.
Wrangling the same problem, I discovered the following code which may be added to Startup.cs:
services.AddRazorPages().AddRazorPagesOptions(options =>
{
options.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
});
No more anti forgery tokens required.
The answer works for me. I would only add that if we have customized methods on the page like:
public IActionResult OnPostFilter1()
{
return new JsonResult("Hello Response Back");
}
Then we should specify the handler name in the url:
url: 'OnPost?handler=filter1',
The following works with ASP.NET Core MVC 3.1 using the headers setting:
$.ajax({
type: "POST",
url: '/Controller/Action',
data: {
id: 'value'
},
headers: {
RequestVerificationToken:
$('input:hidden[name="__RequestVerificationToken"]').val()
},
error: function (xhr, status, errorThrown) {
var err = "Error: " + status + " " + errorThrown;
console.log(err);
}
}).done(function (data) {
console.log(data.result);
});
Including the ValidateAntiForgeryToken attribute on the controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<JsonResult> Action(string id)
{
var result = $"You sent '{id}'";
return Json(new { id, result });
}