web api returning html instead of json - angularjs

I've created an asp.net core project and in the project I have an angularjs application and also a web api project. The angularjs application loads when I login via postman I get the response I expect in json. But when I try the same in angularjs I get the response in html.
I've tried quite a few settings but unable to get this working.
Tried setting the $http services header, and $httpProvider header but unable to get this working in angular js.
I set the content-type in postman to application/json and it works so not think its because the content-type is wrong in angular js.
Startup.cs file:
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvcCore()
.AddJsonFormatters();
// Add framework services.
services.AddMvc().AddJsonOptions(
options =>
options.SerializerSettings.ContractResolver = new
CamelCasePropertyNamesContractResolver()
);
The controller in web api is:
[Route("test3")]
[HttpPost]
public JsonResult Test3([FromBody]LoginUserRequest model)
{
LoginUserResponse response = new LoginUserResponse();
response.validLogin = false;
response.Message = "failed" + model.Email;
return Json(response);
}
Angular js service:
vm.getLogin = getLogin;
function getLogin(request) {
return $http.post('/webapi/account/test3',request,{
headers: { 'Content-Type': 'application/json; charset=utf-8'}
})
.then(getLoginComplete)
.catch(getLoginFailed);
}
function getLoginComplete(data, status, headers, config) {
return data.data;
}
function getLoginFailed(e) {
var newMessage = 'XHR Failed for login';
if (e.data && e.data.description) {
newMessage = newMessage + '\n' + e.data.description;
}
e.data.description = newMessage;
return {"error":true, "message":"Unable to login please try again later"};
}
Chrome network via developer tools:
Request URL:http://localhost:5000/webapi/account/test3
Request Method:POST
Status Code:200 OK
Remote Address:[::1]:5000
Referrer Policy:no-referrer-when-downgrade
Response Headers
view source
Content-Type:text/html; charset=utf-8
Date:Tue, 11 Jul 2017 19:58:46 GMT
Server:Kestrel
Transfer-Encoding:chunked
Request Headers
view source
Accept:application/json, text/plain, /
Accept-Encoding:gzip, deflate, br
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6
Connection:keep-alive
Content-Length:61
Content-Type:application/json; charset=UTF-8
Host:localhost:5000
Origin:http://localhost:5000
Referer:http://localhost:5000/login

Related

Angular $http.post 1.6.1 not passing data to WebAPI

All, I just created a new Angular package using 1.6.1 but now the data doesn't seem to pass to my WebAPI. However, when I post bits via SoapUI or something like that, everything is fine.
The Javascript looks like this:
function testapi()
{
var serviceRoot='http://server/testangular16/api/Values';
var deferred=$q.defer();
var req = {
method: 'POST',
url: serviceRoot,
data: 'PassInTheText'
};
$http(req).then(goodResponse,badResponse);
return deferred.promise;
};
function goodResponse(response)
{
console.log("Good response");
console.log(response);
}
function badResponse(response)
{
console.log("Bad response");
console.log(response);
}
and the webapi is a very simple C# controller:
// POST api/values
public HttpResponseMessage Post([FromBody]string value)
{
HttpResponseMessage rp = new HttpResponseMessage(HttpStatusCode.OK);
rp.Content = new StringContent(value);
return rp;
}
I am making it into the controller, I can set a break point and hit the parts where I can look at the value. It's always null.
Looking at the network trace, the angular part does do a preflight and I can see the 200 response back.
Request URL:http://server/testangular16/api/Values
Request Method:OPTIONS
Status Code:200 OK
Remote Address:10.7.14.209:80
**Response Headers view source**
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:content-type
Access-Control-Allow-Origin:http://localhost:8000
Cache-Control:no-cache
Content-Length:0
Date:Fri, 03 Feb 2017 18:09:04 GMT
Expires:-1
Pragma:no-cache
Server:"Management Corporation"
X-AspNet-Version:4.0.30319
**Request Headers view source**
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:mjvzrx3
Origin:http://localhost:8000
Referer:http://localhost:8000/
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
So, it looks like I'm passing CORS, but when I get to trying to pass the data in as the content of the post, it doesn't make it.
Any ideas what I'm missing?
Thanks,
Nick
Web API expects an object in the message body, you cant pass in a primitive type unless you use application/x-www-form-urlencoded as the content-type and prefix the value with an equals = sign.
So you can fix it by one of these methods
Adjust the c# parameter and turning it into a type that has a string property and then send in a json object with a matching parameter name.
Change the request to url-encoding content type and add a = to the variable value.
Send it as a part of the URL instead of the message body, you can still use the POST method.
Change to form-urlencoded
function testapi()
{
var serviceRoot='http://server/testangular16/api/Values';
var deferred=$q.defer();
var req = {
method: 'POST',
url: serviceRoot,
data: '=PassInTheText', // added =
contentType: 'application/x-www-form-urlencoded' // specify content type
};
$http(req).then(goodResponse,badResponse);
return deferred.promise;
};
It seems if I do this, it works as expected.... Thoughts?
// POST api/values
public HttpResponseMessage Post(HttpRequestMessage request)
{
var data = request.Content.ReadAsStringAsync().Result;
Console.WriteLine("Data: {0}", data);
HttpResponseMessage rp = new HttpResponseMessage(HttpStatusCode.OK);
rp.Content = new StringContent("Data back from WebAPI" + data);
return rp;
}

ASP.NET WebApi Answer 400 Bad Request to OPTIONS on ValidateClientAuthentication, even on context.Validated()

I have an angularjs HTML client to a WebApi project. When I test the APIs via POSTMAN or other REST Client, it seems that everything is ok.
When I start using browsers with my angularjs client, browsers always start preflight requests with OPTIONS. There, my WebAPI always answers 400 Bad Request - I am still on a "/api/token" phase.
I have already attached every single point of my WebAPI project to the debugger. I have also changed several points according to several answers here in SO on how to enable CORS. Some of them I have already tried: changing web.config to add headers enabling cors on every request, adding cors to WebApi startup, enabling cors at "/token" overridden functions.
Here is what I got so for:
Angularjs TypeScript call to "/api/token":
logIn = (userName: string, userPassword: string): ng.IPromise<void> => {
var postData = {
"grant_type": "password",
"client_id": this.appConfiguration.ClientId,
"client_secret": this.appConfiguration.ClientSecret,
"username": userName,
"password": userPassword
};
return this.$http.post<models.LoggedUserModel>('http://local.web.api/api/token', $.param(postData), {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then((result) => {
this.localStorageService.set('Auth', result);
this.goHome(true);
}).catch((error) => {
console.warn(error);
});
}
Here is the only function that is called on my WebApi:
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// handle cors requests
if (!string.IsNullOrEmpty(context.OwinContext.Request.Headers.Get("Origin")))
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new string[] { "*" });
}
try
{
// retrieve clientId and clientSecret from request body
string clientId;
string clientSecret;
if (context.TryGetFormCredentials(out clientId, out clientSecret))
{
// here it comes our application specific security code....
}
else
{
// this is part of enabling CORS..
if (context.Request.Method.ToUpper() == "OPTIONS")
{
// it returns OK to preflight requests having an empty body
context.Validated();
}
}
}
finally
{
// log stuff...
}
}
If I just left OWIN Cors stuff, adding headers and calling ´context.Validated()´ it all continues the same. Here is what I get:
Firefox Network Tab:
--------------------
Request URL: http://local.web.api/api/token
Request method: OPTIONS
Remote address: 127.0.0.1:80
Status code: 400 Bad Request
Version: HTTP/1.1
Request headers:
----------------
Host: local.web.api
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.7,pt-BR;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization
Origin: http://local.web.client
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Response headers:
-----------------
Access-Control-Allow-Origin: *
Cache-Control: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Date: Tue, 22 Dec 2015 15:24:23 GMT
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
I would really appreciate some ideas of where to got.
This is brand new to me, and I do operate some other WebApi projects + angularjs.
Ok, that's is terrible but I found the issue.
I am using a http interceptor on angularjs that would automatically check for a logged user and add an Authorization header with the Bearer token when needed. Problem is I was doing it wrongly.
I created a new property in the config object, bypassToken as boolean, that would be the flag to add or not the Authorization header. Removing this actually fixed the code. Not sure why, but analyzing the request now I can see that all headers are actually sending as expected: with the Content-Type which was not being filled on the first case correctly. Weird though no warning was thrown by angularjs.
// http auth interceptor
angularApplication.factory('httpAuthInterceptor', ['$rootScope', '$injector', '$location', ($rootScope, $injector, $location): ng.IHttpInterceptor => {
var $q: ng.IQService = $injector.get('$q');
var localStorageService: ng.local.storage.ILocalStorageService = $injector.get('localStorageService');
return {
request: (config: ng.IRequestConfig): ng.IRequestConfig => {
// check if headers are present
config.headers = config.headers || {};
// the error was here! I was trying to add properties to config that I think angular was not expecting
// removing this line solved the issue
// if (!config.bypassToken) {
// check if user is logged in
var loggedUserInfo = localStorageService.get<models.LoggedUserInfoModel>('Auth');
if (loggedUserInfo) {
config.headers['Authorization'] = 'Bearer ' + loggedUserInfo.access_token;
}
return config;
},
responseError: (rejection) => {
// check if user is logged in
var loggedUserInfo = localStorageService.get<models.LoggedUserInfoModel>('Auth');
if ((rejection.status === 401) && (loggedUserInfo)) {
// if so, then the user must login againd
localStorageService.remove('Auth');
$location.path('/home');
console.error(rejection);
}
return $q.reject(rejection);
}
};
}]);
I appreciate your help.
I am only posting this here in case someone faces a similar issue.
Don't mess with the config object!

Angular http request get error: No 'Access-Control-Allow-Origin' header is [duplicate]

This question already has an answer here:
"No 'Access-Control-Allow-Origin' header is present on the requested resource" error for response from http://www.google.com/
(1 answer)
Closed 7 years ago.
I get error below when I send request to my api:
XMLHttpRequest cannot load http://api.myapp.example.com/v1/resources. No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://myapp.example.com' is therefore not allowed access.
As I know angular http request doesn't need to add any header. Why is it? It seems my web knowledge isn't.I couldn't understand why this error has occurred. Please help me If you know anything about this situation.
My query:
$http.get('http://api.ingliz.tili.uz/v1/resources').success(function(data, status, headers) {
console.log("success")
console.log(data);
console.log(status);
$scope.resources = data
}).error(function(data, status) {
console.log("error")
console.log(data);
console.log(status);
})
request in console:
General
Remote Address:127.0.0.1:80
Request URL:http://api.myapp.example.com/v1/resources
Request Method:GET
Status Code:200 OK
Response Header
Connection:Keep-Alive
Content-Length:240
Content-Type:application/json; charset=UTF-8
Date:Sun, 16 Aug 2015 08:04:08 GMT
Keep-Alive:timeout=10, max=100
Link:<http://api.myapp.example.com/v1/resources?page=1>; rel=self
Server:Apache/2.4.10 (Win32)
X-Pagination-Current-Page:1
X-Pagination-Page-Count:1
X-Pagination-Per-Page:20
X-Pagination-Total-Count:1
Request Header
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,ru;q=0.6,bg;q=0.4,zh-CN;q=0.2,zh;q=0.2,uz;q=0.2
Cache-Control:max-age=0
Connection:keep-alive
Host:api.myapp.example.com
Origin:http://myapp.example.com
Referer:http://myapp.example.com/
I tried with:
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
but this is helpless.
Configure your server to accept Cross Origin Requests
PHP
header("Access-Control-Allow-Origin: *");
ASP.NET Web API 2
1) Add the Microsoft.AspNet.WebApi.Cors NuGet package to your project.
2 ) Add this code to your configuration:
public static void Register(HttpConfiguration config)
{
// New code
config.EnableCors();
}
3) Add the [EnableCors] attribute to your Web API controller or controller method:
[EnableCors(origins: "http://example.com", headers: "*", methods: "*")]
public class TestController : ApiController
{
// Controller methods not shown...
}
You must set header in your server side.
If your server side in php, add this line to your code:
header("Access-Control-Allow-Origin: *");

Getting Form Data From Outcoming HTTP POST response in Angular js

I am trying to develop payment module with angularjs and asp.net web api.
I am using an payment api (iyzico).
With that api I create shopping token request and this request return an js script response and a shopping token.
I load this js file and payment form is generated by returning js file.
After generating payment form, I entered my credit card infos and send these infos to payment api then payment api return response but I could not get this response from page (This response come when page is loading).
Http Get method for generating shopping token in payment.js
function loadDetails() {
$http.get( '/API/api/profile/GetPaymentToken').then(function (results) {
$scope.paymentData = jQuery.parseJSON(results.data);
$scope.code_snippet = $sce.trustAsHtml($scope.paymentData.code_snippet);
var paymentScriptUrl = "https://www.iyzico.com/frontend/form/v1/widget.js?mode=test&token=" + $scope.paymentData.transaction_token;
$.ajax({
url: paymentScriptUrl,
dataType: "script",
cache: true,
success: function (data, textStatus, jqXHR) {
var f = new Function(data);
f();
iyzi_jQuery(this).iyziPayment({
host: 'https://iyziconnect.com/pay-with-transaction-token/',
mode: 'test',
assetsURL: 'https://www.iyzico.com/frontend/form/v1/',
installment: '0',
language: 'tr'
});
},
error: function (jqXHR, status, err) {
console.log("");
}
});
},
function (response) { // optional
_helper.error.handleError(toaster, response.data, response.status);
})
}
Token Generator in Web.Api, it is called in payment.js
[Authorize]
[HttpGet]
[Route("GetPaymentToken")]
public async Task<IHttpActionResult> GetPaymentToken()
{
System.Diagnostics.Debugger.Break();
WebRequest request = WebRequest.Create("https://api.iyzico.com/v2/create");
request.Method = "POST";
var rand = new Random();
var external_id = rand.Next(0, 100000000);
string postData = "api_id=my_id"
+ "&secret=my_secret"
+ "&external_id=" + external_id.ToString()
+ "&mode=test"
+ "&type=CC.DB"
+ "&return_url=http://localhost:2020/payment2" //returning url
+ "&amount=10020"
+ "&currency=TRY"
+ "&descriptor=PAYMENT_DESCRIPTION"
+ "&customer_contact_ip=CUSTOMER_IP"
+ "&customer_language=tr"
+ "&installment=false";
byte[] byteArray = System.Text.Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
System.IO.Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
WebResponse response = request.GetResponse();
dataStream = response.GetResponseStream();
System.IO.StreamReader reader = new System.IO.StreamReader(dataStream);
string responseFromServer = reader.ReadToEnd();
reader.Close();
dataStream.Close();
response.Close();
return Ok(responseFromServer);
After getting shopping token I enter my credit card infos and send form to external payment api and external api return information to my return url (http://localhost:2020/payment2) about my payment is successful or failed .
I can see returning responce from external api at chrome developer tools > network actions but I can not get that form data from mycontroller js file. returning response is at below
Remote Address:[::1]:2020
Request URL:http://localhost:2020/payment2
Request Method:POST
Status Code:200 OK
Response Headers
view source
Cache-Control:private
Content-Length:11337
Content-Type:text/html
Date:Fri, 03 Apr 2015 08:45:22 GMT
Server:Microsoft-IIS/8.5
X-Powered-By:ASP.NET
Request Headers
view source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip, deflate
Accept-Language:en-GB,en-US;q=0.8,en;q=0.6,tr;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Content-Length:532
Content-Type:application/x-www-form-urlencoded
Cookie:countrySCJS=TR; ootdcuSCJS=34602; ootdchSCJS=10742; ctxjs1420m06d05=7b2273756363657373223a302c226c6f675f616374697665223a317d; ASPSESSIONIDQCDBDRBQ=BKGJHHKCKDDLJCBBPMPJJHFH; ASPSESSIONIDQAADBTBR=AMPJDALCPFGILMAOKEDMMGBP; ASPSESSIONIDSCAADQAR=GKKFJCCDLILKPNHAEHBHHLHJ
Host:localhost:2020
Origin:null
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.101 Safari/537.36
Form Data
view source
view URL encoded
**json:{"response":{"state":"failed","date_time":"15-04-03 08:43:24","error_code":"800.100.154","error_message":"transaction marked as invalid","error_message_tr":""},"transaction":{"transaction_id":"MTQyODA1MDU4NAnrin0vdEV06f4hWARX","external_id":"23583443","reference_id":"____________20150403084323.653059Kq","state":"rejected","connector_type":"Isbank","installment_count":0}}**
How can I get that json named array?
You have to sacrifice your your single page application for callback.
Get callback to your REST address
Process the POST parameters
Generate (return text/html) a simple SUCCESS of FAIL page. Let this page contain the result and link to appropriate page (main page url or payment page url)
Link should open your single page angularjs and your controller should display
appropriate page according to URL.

jersey Rest Response in Angular Js

I have jersey framework implemented for Rest services version 2.5
I have implemented Get, it works fine and response shows as JSON object in url when I have tried.
When I have tried the same url in angular JS using http.post and $ resource, success comes as 200k but there is no response.
web app deployed in local on glassfish server and jersey rest services deployed in websphere 7
Rest controller
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/{id}")
public Response assignAppointment(#PathParam("id") String id) {
Appointment app = new Appointment();
app.setId(id);
app.setTechName("fffff");
// return Response.status(200).entity(app).build();
return Response.ok(app).build();
}
in Angular JS
$http.get('http://mylocal.com/ntschedulerp/rest/appointment/'+$scope.appt.apptId,
{
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
}}).then(function(appoinmentData)
{
$scope.assignmentForm = "Controller";
$scope.techName=appointmentData.data.techName;
$scope.response1=appointmentData.status;
});
response is empty but status code is 200. but when tried direct url it shows json object i browser. but while accessing from web app, the response is empty..checked in firebug
The issue got resolved. The issue occurred because of the response headers does not accept cross requests.
CORS http request.
Since I have rest server and web app in different servers, angular js does not directly accept the response which does not have specific headers.
To resolve this issue, Both server and client should have headers embedded.
I have resolved as follows
we need add these headers to the response
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Methods': ['OPTIONS', 'GET', 'POST'],
'Access-Control-Allow-Headers' : 'Content-Type'
On client side, add the magic statement
$http.defaults.useXDomain = true;
before calling $http method in controller, I am using angular js 1.2 version, earlier versions, it might need to do like this..not tested but found some where
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
on server side, I am using jersey framework (2.5),
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/{id}")
public Response assignAppointment(#PathParam("id") String id) {
Appointment app = new Appointment();
app.setId(id);
app.setTechName("xxxx");
ResponseBuilder response=Response.status(200).entity(app);
response.header("Access-Control-Allow-Origin", "*");
response.header("Access-Control-Allow-Methods", "Cache-Control, Pragma,
Origin, Authorization, Content-Type, X-Requested-With");
response.header("Access-Control-Allow-Headers", "GET, PUT, OPTIONS,
X-XSRF-TOKEN");
return response.build();
}
one can use,
#Context HttpServletResponse
as method argument in rest methods, if using older versions.

Resources