Get request origin in C# api controller - c#

Is there a way how can I can get request origin value in the api controller when I'm calling some api endpoint with ajax call?
For example I'm making this call from www.xyz.com:
$http({
url: 'http://myazurewebsite.azurewebsites.net/api/ValueCall/CheckForExistingValuers',
method: "GET",
params: { loanID: $scope.loanIdPopup }
}).success(function (data) {
}).error(function (data) {
});
Once on the api side, how can I get the www.xyz.com value?
CORS is working properly.

What you're looking for is probably the origin-header. All modern browsers send it along if you're doing a cross domain request.
In an ApiController you fetch it like so:
if (Request.Headers.Contains("Origin"))
{
var values = Request.Headers.GetValues("Origin");
// Do stuff with the values... probably .FirstOrDefault()
}

You can grab it from the API methods via current HTTP request headers collection:
IEnumerable<string> originValues;
Request.Headers.TryGetValue("Origin", out originValues)

var originValue = Request.Headers["Origin"].FirstOrDefault();
// or
StringValues originValues;
Request.Headers.TryGetValue("Origin", out originValues);

Related

Antiforgery token validation in header using Ajax and MVC

I need to implement antiforgery validation to my MVC project. However, I am having problems with the server side.
I am using #Html.AntiForgeryToken() to create the token.
Then i get the token value and include it in Ajax request.
// Get token
var cookie = $('input[name=__RequestVerificationToken]').val();
// Ajax request
return $.ajax({
url: url,
type: 'post',
headers: {
'x-system-source': headerValue,
'x-verification-token': cookie //verification token
},
data: ko.toJSON(entity),
contentType: 'application/json',
dataType: 'json'
});
Code below comes from microsoft documentation, however, I am not sure how to implement it. Should I create a custom attribute with the method below and add the attribute to every http request? If so, what would be the best way? Is it possible to create attribute for a controller level? I would also like to avoid repetitive code as much as possible. In addition, is there a way to unit test aniforgery validation feature to make sure that it works as expected.
I am new to the web development, and I would appreciate if you could provide code samples or point me in the right direction. Thanks for your time.
void ValidateRequestHeader(HttpRequestMessage request)
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (request.Headers.TryGetValues("x-verification-token", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}

Parse JSON from C# to AngularJS

I have an array of file names:
[HttpPost]
public JsonResult GetJSONFilesList()
{
string[] filesArray = Directory.GetFiles("/UploadedFiles/");
for (int i = 0; i < filesArray.Length; i++)
{
filesArray[i] = Path.GetFileName(filesArray[i]);
}
return Json(filesArray);
}
I need this in AngularJS as a list of objects so I can ng-repeat it out and apply filters. I'm unable to figure out how to get the JSON from the MVC controller to AngularJS.
I've tried the following to make it visible to the view for angular to grab, but I don't know how to make the ng-init see the function to return the list. It erros on "SerializeObject(GetJSONFilesList())" saying it doesn't exist in current context.
<div ng-controller="MyController" data-ng-init="init(#Newtonsoft.Json.JsonConvert.SerializeObject(GetJSONFilesList()),
#Newtonsoft.Json.JsonConvert.SerializeObject(Model.Done))" ng-cloak>
</div>
EDIT:
I've tried using http.get.
Test one:
alert('page load');
$scope.hello = 'hello';
$http.get('http://rest-service.guides.spring.io/greeting').
then(function (response) {
$scope.greeting = response.data;
alert($scope.greeting);
});
alert($scope.hello);
The alert in the http.get never fires, the other alerts do however.
Test two:
$http({
url: '/Home/testHello',
method: 'GET'
}).success(function (data, status, headers, config) {
$scope.hello = data;
alert('hi');
});
[HttpPost]
public string testHello()
{
return "hello world";
}
This causes the angular to break and nothing in the .js works.
Test three
alert('page load');
$scope.hello = 'hello';
$scope.GetJSONFilesList = function () {
$http.get('/Home/testHello')
.success(function (result) {
$scope.availableFiles = result;
alert('success');
})
.error(function (data) {
console.log(data);
alert('error');
});
alert('hi');
};
alert($scope.hello);
[HttpPost]
public string testHello()
{
return "hello world";
}
Alerts nothing from within it, other alerts work.
Fixed:
After some googling, I've found that using .success and .error are deprecated and that .then should be used. So by using .then this resulted in the C# being hit via debug.
Then after using console.log on the returned value found that to have anything be returned I needed to return the value from C# using "return Json(myValue, JsonRequestBehavior.AllowGet); "
And by viewing the object in the console in Chrome by using console.log, I could see my values were in the data part of the returned object.
It was stored in data as an array (as I was passing an array).
I could then get the data out of there by assigning the returned value.data to a scope and could call that in the view {{result[1]}} etc.
return Json(filesArray, JsonRequestBehavior.AllowGet);
$scope.fileList;
$http.get("/Home/GetFileList").then(function (result) {
console.log(result)
$scope.fileList = result.data;
})
Imagine that you divide your front end in three layers (MVC or MVVM) whatever you want.
When you need info from server, the best practice is to separate the logic that makes the request and the logic that manipulates the data.
More info about how to make the request you can find it reading about REST APIS in Consuming a RESTful Web Service with AngularJS.
Normally one of the layers requires the use of services and you can have your controllers and your services (the place where you get the raw data from the server and you make the request. For that you need to use the $http service from angularjs.
$http: The $http service is a core AngularJS service that facilitates communication with the remote HTTP servers via the browser's XMLHttpRequest object or via JSONP.
So basically it shows you how to make get, post and put requests. One example from the documentation is :
// Simple GET request example:
$http({
method: 'GET',
url: '/someUrl'
}).then(function successCallback(response) {
// this callback will be called asynchronously
// when the response is available
}, function errorCallback(response) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
Pay attention to the url because there is the place where you let your request knwow which method is going to be hit on the server to take the action. If your request is succesful, then you can use the parameter called response. From there, you can do whatever you want. If you decide to make that request part from your controller, you can assign it directly to a variable on your scope. Pay attention if you need to serialize the data. Something like
$scope.myResponseName = response.name ;
The first documentation link from above shows this example which does exactly what I tell you.
angular.module('demo', [])
.controller('Hello', function($scope, $http) {
$http.get('http://rest-service.guides.spring.io/greeting').
then(function(response) {
$scope.greeting = response.data;
});
});
After all the mentioned above, pay attention to what you want to display. Are you going to display the elements of an object array? The use on your HTML the ng-repeat directive. Are you going to display just a variable (No array nor object) then you use need to use an angular expression {{ }}
In summary:
By making an HTTP request, hit the correct method on server.
Make sure you are sending the JSON correctly and that the data is correct.
Retrieve the data on your response.
Assign the data to a variable on your scope and serialize the data if needed.
Display the data correctly depending if it is within an array, if it´s an object or if its just a variable.
I hope the explanation makes sense and check the documentation if you need more info.
You can build your viewmodel so that it contains the data you'd like to serialize and then pass it to angularJS in your view as follows:
<div ng-controller="MyController" data-ng-init="init(#JsonConvert.SerializeObject(myArrayData),
#Newtonsoft.Json.JsonConvert.SerializeObject(Model.Done))" ng-cloak>
and then in your angular controller have a function to receive the data as follows:
$scope.init = function (myArrayData) {
//do something with data
};
The above assumes you're trying to pass data from mvc to angularjs on page load. If you're trying to hit a controller and get data back to angularjs upon some event such as a button click, then you can write an angularjs function similar to the following (this will be an asynchronous request):
app.controller('MyController', function ($scope, $http, $window) {
$scope.ButtonClick = function () {
var post = $http({
method: "POST",
url: "/SomeController/SomeAjaxMethod",
dataType: 'json',
data: { path: $scope.Path},
headers: { "Content-Type": "application/json" }
});
post.success(function (data, status) {
//do something with your data
});
post.error(function (data, status) {
$window.alert(data.Message);
});
}
}
and your controller action would look something like:
[HttpPost]
public JsonResult SomeAjaxMethod(string path)
{
string[] filesArray = Directory.GetFiles(path);
for (int i = 0; i < filesArray.Length; i++)
{
filesArray[i] = Path.GetFileName(filesArray[i]);
}
return Json(filesArray);
}
other answers say to use .success in the angular function, .success and .error are deprecated, instead .then should be used.
Working result:
MVC:
public JsonResult GetFileList()
{
//form array here
return Json(myArray, JsonRequestBehavior.AllowGet);
}
The function needs to be of type JsonResult, and the returned value of Json using JsonRequestBehavior.AllowGet.
AngularJS:
$scope.fileList;
$http.get("/Home/GetFileList").then(function (result) {
console.log(result)
$scope.fileList = result.data;
})
This is in my AJS controller, using .then instead of .success. If you use console.log the result returned from the mvc controller and view it in the browser inspect you'll see the object with lots of other info and the values you want are in the .data section of the object.
So to access the values you need to do result.data. In my case this gives me and array. I assign this to a scope. Then in my view I can access the values by doing {{fileList[1]}} etc. This can also be used in ng-repeat e.g:
<div ng-repeat="file in fileList">
{{fileList[$index]}}
</div>
Each value in the array in the repeat can be accessed using $index which is the number of the repeat starting at 0.

Web Api 2 - How to send attribute from $http call to controller (attribute routing)

I have this $http call :
$http({
method: 'GET',
url: '/api/PhotoSubmit/GetCategories',
accept: 'application/json'
})
.success(function (result) {
$scope.categories = result;
});
... which needs to send the parameter to this HTTPGET method :
[Route("api/PhotoSubmit/GetCategories/{id}")]
[HttpGet]
public object GetCategories(int id)
{
return FileServices.GetCategoriesForUser().Select(c => new { Id = c.Id, Name = c.Name });
}
Th routing works, i'm just not sure how to access it by angular/javascript to send it to the controller (OR... how the route-call should look like in the $http call
This is the URL :
http://localhost:63203/Index.html#/photosubmit/1
I'm sure $http is similar, but I'm using $resource in a factory to hit my web api endpoint.
In services.js, I have:
var app = angular.module('app.service', ['ngResource']);
app.factory('api', ['$resource', function ($resource) {
'use strict';
return {
Categories: $resource('/api/PhotoSubmit/GetCategories/:id', {id: '#id'})
};
}]);
Then in my controller, I call it with
$scope.categories = api.Categories.get({id:"1"});
If you really want to start having fun, you can wait and use the data after the results come back using a $promise.
api.Categories.get({id:"1"})
.$promise
.then(function (results){
$scope.categories = results;
});
Update:
To get the variable into $routeParams, I'm doing the following (bear in mind, this was my first angular app, so there are better ways to code this.)
In my app.config, I have the following code to create an id parameter:
$routeProvider
...
.when('photosubmit/:id', {
templateUrl: "photo.html",
controller: "PhotoController"
})
.otherwise({ redirectTo: '/' });
Then, I get the param in the controller $scope.$routeParams = $routeParams;
I had to do this at the top so it doesn't get lost or undefined.
Next, you can access the variable you created in the route by using $scope.$routeParams.id
Id can be passed through url itself.
url: '/api/PhotoSubmit/GetCategories/1',
or you can pass this in params too.
$http({
url: '/api/PhotoSubmit/GetCategories',
method: "GET",
params: {id: 1}
});

GET 405 method not allowed

This is my jquery code to call web api
var request = {
RequestId: "123",
DeviceId: "ACU-B2-01-R1",
AccessType: "Unlock",
LoginId: "tester",
Password: "tester"
};
$.ajax({
url: 'http://localhost:55208/api/accesspanel',
type: 'POST',
data: JSON.stringify(request),
dataType: 'jsonp',
contentType: "application/json;charset=utf-8",
success: function (data) {
alert("success");
alert(JSON.stringify(data));
},
error: function (x, y, z) {
alert(x + '\n' + y + '\n' + z);
}
});
When I run this code, nothing happens. Neither the success nor error block gets fired. After checking in the debug console of chrome, this is the error record:
GET http://localhost:55208/api/accesspanel?callback=jQuery18203847100134007633_…22,%22LoginId%22:%22tester%22,%22Password%22:%22tester%22}&_=1364916423737 405 (Method Not Allowed)
send jquery.min.js:2
p.extend.ajax jquery.min.js:2
(anonymous function)
I am, however, able to call my web api method successfully using C# code, which looks like this:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:55208/");
var request = new DeviceAccessRequest
{
RequestId = Guid.NewGuid().ToString(),
DeviceId = "ACU/B2/01/R1",
AccessType ="Unlock",
LoginId = "tester",
Password = "tester" ,
};
var response = client.PostAsJsonAsync("api/accesspanel", request).Result;
if (response.IsSuccessStatusCode)
{
var deviceAccessResponse = response.Content.ReadAsAsync<DeviceAccessResponse>().Result;
}
}
And this is my web api method:
[HttpPost]
public HttpResponseMessage PostDeviceControl(DeviceAccessRequest deviceAccessRequest)
{
var deviceAccessResponse = new DeviceAccessResponse(deviceAccessRequest.RequestId)
{
Status = "OK"
};
var response = Request.CreateResponse<DeviceAccessResponse>(HttpStatusCode.OK, deviceAccessResponse);
return response;
}
The reason you are seeing a GET request in your console is because you specified dataType: 'jsonp' which works only with GET requests (the reason for that is because jQuery translates this to a <script> tag pointing to the url you specified). If you want to be doing cross domain AJAX with other verbs than GET you cannot use JSONP. If you need to use other verbs (such as POST in your case) you have 2 options:
CORS. Take a look at the following video which illustrates how you could enable CORS on your Web API. Obviously for this to work your client side browser need tio support it
Server side bridge on your domain. The idea here is to have some server side script on the domain hosting your javascript code that will send the HTTP request to the API and return the response to the client. Then you will send a regular AJAX POST request to your own domain

Getting wrong Url.PathAndQuery

I have an action link:
#Html.ActionLink("Shopping cart", "Index", "Cart", new { returnUrl = Request.Url.PathAndQuery }, null)
and code that adds items to cart:
<script type="text/javascript">
$(document).ready(function () {
$("#addToCart_#(Model.ProductID)").click(function () {
var quantity = $("#Quantity_#(Model.ProductID)").val();
var productId = "#Model.ProductID";
var dataToBeSent = { 'quantity': quantity, 'productId': productId};
$.ajax({
type: "POST",
url: '/Cart/AddToCart/',
data: dataToBeSent,
success: function (result) {
$('#cartholder').html(result);
}
});
});
});
</script>
When I'm trying to follow action link after adding item to cart, Request.Url.PathAndQuery has value /Cart/AddToCart/.
How can I get current url?
You need to use:
Request.RawUrl
This will get the URL you see in the browser. When using Url writing as with MVC the Request.Url will be the rewritten path.
Looks to me like you are setting your URL to /Cart/AddToCart/. It's right there in your AJAX request: url: '/Cart/AddToCart/'. That's it -- that's your URL (not counting the scheme and host).
You're specifying type: "POST", so your payload (your data: dataToBeSent) isn't sent as part of the URL. The data only gets sent in the URL when you use GET. When you use POST, it's in the request body, not the URL.
(And don't just change it to a GET. It would seem to work for now, but would give you headaches later. GET requests can be cached by proxy servers -- not appropriate for requests that modify state, like adding things to a shopping cart.)
So in answer to the question you asked, Request.Url.PathAndQuery is how you get the URL. It's just that the URL is not what you want. You want to get your POST data, however that's normally done in ASP.NET MVC.
System.Web.HttpContext.Current.Request.Url

Categories