How to call a controller directly using ajax - json

Let say I have 2 project ClientSide and ServerSide. I need to call a function in a controller of ServerSide from ClientSide. Can it be done directly using Ajax?
This is my Ajax code (it will work if the controller is put in the same project):
var url = 'api/values/insert';
$.ajax({
type: method,
url: url,
data: JSON.stringify(data),
contentType: 'application/json',
success: function (data) {
window.location.href = "/index";
}
});
The local host for my ClientSide is https://localhost:44356, and the one for my ServerSide is https://localhost:44329. I have tried adding the local host into the url but it's still not working.
var url = 'https://localhost:44329/api/values/insert';
Is there any other method could help me solve this problem? I am appreciated for all the suggestion and answers.
For more specific information if needed, I am using .NET 2.1
UPDATE:
This is my controller code in ServerSide. If I put the controller in ClientSide, it works without any modification needed, so I believe the problem is about the connection between Ajax and the controller.
namespace RazorAPI.Controllers
{
[Produces("application/json")]
[Route("api/[controller]")]
public class ValuesController : Controller
{
private readonly IDataService _dataService;
public ValuesController(IDataService dataService)
{
_dataService = dataService;
}
// POST: api/values/insert
[HttpPost]
[Route("[action]")]
public void Insert([FromBody]Data data)
{
//This call another function in ServerSide
_dataService.Create(data);
}
}

After working around with it, I found out the problem is because of CORS issue. This is how I fix it.
In Startup.cs file of ServerSide project, add the following code to Configure method:
app.UseCors("AllowAllHeaders");
Add the following code to ConfigureService method:
services.AddCors(options =>
{
options.AddPolicy("AllowAllHeaders",
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
Now use the url include local host to ServerSide:
var url = 'https://localhost:44329/api/values/insert';
This works for me but it will allow acess from any domain. If you need it to be only accessed by specific origin, change the code in Configure into:
app.UseCors("AllowSpecificOrigin");
And for the code in ConfigureService:
services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin",
builder =>
{
builder.WithOrigins("localhost")
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
Thank you for all the help!

Related

ASP MVC Areas and JSON POST

I have a project with areas and would like to post a view model as JSON to a controller method.
This is what I have, with performance being generated in the default area and passed to the view in area SeatSelection:
$("#addToCartButton").click(function () {
var json = #Html.Raw(Json.Encode(performance));
$.ajax({
url: 'https://#(Request.Url.Host)/SeatSelection/Home/AddToCart',
type: 'POST',
dataType: 'json',
data: json,
contentType: 'application/json; charset=utf-8',
success: function (data) {
alert(data);
}
});
});
And the action method for testing:
[System.Web.Http.Route("SeatSelection_AddToCart")]
[System.Web.Http.HttpPost]
public JsonResult AddToCart(PerformanceViewModel performance)
{
return Json(performance.Name);
}
I created the following route:
context.MapRoute(
"SeatSelection_AddToCart",
"SeatSelection/Home/AddToCart",
new { action = "AddToCart", controller = "Home", id = UrlParameter.Optional },
namespaces: new string[] { "myProject.Areas.SeatSelection.Controllers" }
);
But all I get is a internal server error 500. I also tried to use [FromBody] and setting a breakpoint to the method, but it is not invoked. I can't figure out what's wrong or missing, please help.
UPDATE
This is the json / performance:
PerformanceID=00000000-0000-0000-0000-000000000000&Name=Performance+15&StartDate=%2FDate(1360364400000)%2F&EndDate=%2FDate(1500328800000)%2F&LatestDateBookable=%2FDate(1450911600000)%2F&Organizer=Organizer+15&Location=Location+15&Availability=75&IsFull=false&IsBookable=true&HasPrice=true&BookableSeats=11&BookedSeats=94&Description=Description+of+Performance+15&Price=443
I found an error: "invalid json primitive: performanceid"
First of all, I would recommend you to use #Url.Action helper method instead of generating url like this: https://#(Request.Url.Host)/SeatSelection/Home/AddToCart.
Secondly, always validate params which comes from the browser. return Json(performance.Name) looks suspicious. What is performance will be null? This might be a problem of your internal server error 500.
If this is not a problem then try to send string instead of JSON to the server and validate and parse JSON on the server side.
You can use Url.Action method like this. I suppose SeatSelection is an area in your project.
$.ajax({
url: '#Url.Action("AddToCart", "Home", new { Area = "SeatSelection"})',

Ajax call to JsonResult in Controller fails with 404 error, "resource not found"

Here is my ajax code in my "ManageUserRoles.cshtml":
//HIT THE DATABASE FOR USERNAME GIVING IT THIS USERNAME
function isUserValid(thisUser) {
$.ajax({
url: "/Roles/isUserValid/" + thisUser,
type: 'POST',
success: handleResultResponseUserName,
error: function (xhr) { alert("Error..."); }
});
}
//handles data back from ajax call
//RESET INPUT IF NO USER IF FOUND IN USER'S TABLE
function handleResultResponseUserName(ResponseObject) {
if (ResponseObject == "no user with this number") {
$('#frmGetRoles').find('input[name="UserName"]').val(null);
}
else {
//DO NOTHING
}
}
Here is my JsonResult in my RolesController:
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult isUserValid(string username)
{
var name = string.Empty;
var CheckUserExists = (from c in _db.AspNetUsers
where (c.UserName.Equals(username))
select c);
var results = new JsonResult();
if (CheckUserExists.Any())
{
name = CheckUserExists.First().UserName;
}
else
{
name = "no user with this name in database";
}
return Json(name, JsonRequestBehavior.DenyGet);
}
I've got almost exact code working in a different application and I cut and pasted into a new one where I am trying to use it for Roles management.
The json reference is there, and in web.config. But when I put a breakpoint inside the JsonResult, it never stops there and an error is returned from the client javascript (404 resource not found). There is no other json stuff being used in this new app . . .yet.
I can hit f5 and it returns:
http://localhost/StoreMasterSecure/Roles/ManageUserRoles
which is the view that has the button that runs the ajax. It all gets to the ajax call and then nothing happens and Chrome Developer Tools console shows 404 error.
Even if I type in the URL the path, I get the resource not found 404 page:
http://localhost/StoreMaster/Roles/isValidUser/xxxx#xxx.com
(isValidUser is the JsonResult in the controller, in same controller that ManageUserRoles ActionResult exists and works)
To ensure you url's are correctly generated, use the Url.Action() method and pass the data using the ajax data option. Change your ajax to
$.ajax({
url: '#Url.Action("isUserValid", "Roles")', // change this
data: { username: thisUser }, // add this
type: 'POST',
success: handleResultResponseUserName,
error: function (xhr) { alert("Error..."); }
});
You also need to remove the [ValidateAntiForgeryToken] attibute from your controller method since you not passing the token.
Side note: MVC comes with a RemoteAttribute to handle this scenario. Refer How to: Implement Remote Validation in ASP.NET MVC which means you do not need your script.

Handle json array CAKEPHP

Here's my javascript snipet
<script type="text/javascript">
$(document).ready(function() {
$('form#FormId button.btn').click(function(event){
$.ajax({
type: "POST",
url: "/controller/edit",
data: $("#FormId").serialize(),
success: function(response) {
alert(response.message);
alert(response['message']);
}
});
});
});
Here's my controller action
public function edit() {
$this->autoRender = false; // We don't render a view in this example
$this->request->onlyAllow('ajax'); // No direct access via browser URL
echo json_encode(array('message'=>'Welcome','type'=>'success'));
exit;
}
Both alerts on the javascript are returning "undefined" how to handle?
So nobody is getting this correct.
You need to use the JSON view
See how to enable with this section
class PostsController extends AppController {
public $components = array('RequestHandler');
public function index() {
$this->request->onlyAllow('ajax');
$this->set(array(
'data' => array('message'=>'Welcome','type'=>'success'),
'_serialize' => 'data',
));
}
}
Cake will now automatically set the correct headers, serialize as JSON and not render the layout.
As a side note, your code alert(response.message); does not work beacuse response is a string. your header is text/html not application/json. Try console.log(response) and you will see it is just a string.
I get this to work using the following code in the controller
public function edit()
{
$this->RequestHandler->respondAs('json'); // Very important without this it will not work
$this->autoRender = false;
$data = array('message'=>'Welcome','type'=>'success');
return json_encode($data);
}
try add
dataType: 'json',
to your ajax method.
if it not work, try this:
add
$this->response->type('text/plain');
to your index method.
ie brower did not know json format text.
and what broswer did you used for this test? use F12 open the developer kit to check what the server response, is it a objct
From my experience echoing content doesn't work. You should instead return the json_encoded data.
This will make your edit() function look like this:
public function edit()
{
$this->autoRender = false;
$this->request->onlyAllow('ajax');
return json_encode(array('message' => 'Welcome', 'type' => 'success'));
}
To make sure it works; just alert the whole response object to see what is returned.

Trouble with loading json files into template.html using angular factories

I am trying to understand how to use factories and struggling to understand a few things.
I want to load json file into template but I am hitting the wall
myApp.factory('getUsersFactory',['$http',function($http){
return {
getUsers: function(callback){
$http({method: 'JSONP', url: "users.json?query=?callback=JSON_CALLBACK&query="+ $scope.searchString}).success(callback);
}
}
}]);
myApp.factory('Tester', function($resource) {
return $resource('users.json');
});
myApp.controller('PersonCtrl', function ($scope, Tester, getUsersFactory) {
// Teens are from static json file
$scope.users = Tester.query();
// Adults are from REST API
$scope.teens = getUsersFactory.query();
});
If you will have look in my example you will see that I am trying to load from users.json file content to main.html
I would like to be able to load multiple json files into main.html
PLUNKER example here
Could you please advice me with example how to do this correctly.
You need to change your getUsersFactory factory, because you don't have there $scope:
myApp.factory('getUsersFactory',['$http',function($http){
return {
getUsers: function(searchStr, callback){
$http({method: 'JSONP', url: "users.json?query=?callback=JSON_CALLBACK&query="+ searchStr}).success(callback);
}
}
}]);
As you can see, i added one more parameter - searchStr.
You need to call function getUsers() of your factory getUsersFactory. Actually problem is next: function query() is not defined in your factory getUsersFactory.
Actually seems it works even if call $scope.teens = getUsersFactory.getUsers(); - without params.
So, answer to your question - use function of factory which you defined: getUsersFactory.getUsers()
Changed plunk: http://plnkr.co/edit/xIzd8Zyg0hzMgbPCzEfj?p=preview

TDD and configuration variables

I'm learning TDD (in Javascript), and I wanted to know, what is the right way to use configuration variables? Should I make a separate class and have them be member variables of the class, and pass an instance of the class to every object that needs it, or make a list of global variables and just use those? What are the benefits / setbacks of each method?
For example, I have to get data from a URL as follows:
function getData (remoteDataDelegate) {
remoteDataDelegate.getData(userInfoURL)
}
where userInfoURL is a configuration variable that I set elsewhere to the URL for a page on my site.
This is an example of how I do it:
function NewConfiguration() {
var config = {};
config.carriersSelector = NewCarriersSelector();
config.paymentMethodsSelector = NewPaymentMethodsSelector();
return config;
}
Usage:
function NewOrderModel(request, searchRequest) {
var configuration = NewConfiguration();
// ... other variables code
var that = {
getContentSuccess: function(cb) {
// .. setup code
$.ajax({
type: 'GET',
url: request.page,
dataType: 'json',
data: request.data,
async: request.async,
success: function(data) {
if (data.status === 'success') {
cb(data.html, activeCustomer, step, configuration);
}
if (data.status == 'flash') {
flash(data.flash);
}
},
complete: request.complete
});
},
}
You will notice that the configuration is not being injected. for me, in this sample code the configuration never changes. Now my request objects change so they get injected, so I can mock those out or redirect the pages.
Global variables are usually set by the setUp method of your TestCase.