Good day everyone,
I am facing a slight problem.
Up until last week our mobile application connected to an in-house Web Api, which in turn connected to web services run and maintained by our partners.
Problem is, we would like the remove our Web Api as the middle man, and connect directly from our Cordova app (Javascript) to the Restful service.
Below is the C# code I am trying to emulate, any and all help would be appreciated:
(At this point I'm sure everything is right, except the authentication but I might be wrong)
QUESTION:
How can I achieve this in Javascript (If it is at all possible)
public static AuthenticateResult CheckLogin(LoginModel login)
{
var serviceClient = new WebClient();
var proxy = serviceClient.Proxy;
proxy.Credentials = new NetworkCredential("username_goes_here", "password_goes_here");
serviceClient.Headers["Content-type"] = "application/json";
try
{
var requestHeader = new UnauthenticatedRequestHeader
{
Code = ConstantModel.PartnerCode,
Partner = ConstantModel.PartnerName
};
var authenticateRequest = new AuthenticateRequest
{
Username = login.Username,
Password = login.Password,
Handset = "iPhone Emulator"
};
var serviceRequest = new
{
header = requestHeader,
request = authenticateRequest
};
var jsonizedServiceRequest = JsonConvert.SerializeObject(serviceRequest);
var requestBytes = Encoding.UTF8.GetBytes(jsonizedServiceRequest);
var requestStream = new MemoryStream(requestBytes);
var ms = requestStream.ToArray();
var responseBytes = serviceClient.UploadData("Url_goes_here", "POST", ms);
var jsonizedServiceResponse = Encoding.UTF8.GetString(responseBytes);
var authResult = JsonConvert.DeserializeObject<AuthenticateResponse>(jsonizedServiceResponse);
return authResult.AuthenticateResult;
}
catch (Exception ex)
{
return null;
}
}
What I have so far in Javascript is (this returns a Bad Request error):
btnTestClick: function () {
var header = {
Code: 'guid_goes_here',
Partner: 'partnerid_goes_here'
};
var request = {
Username: 'username_goes_here',
Password: 'password_goes_here',
Handset: 'iPhone Emulator'
};
var myrequest = {
header: header,
request: request
};
var string = JSON.stringify(myrequest);
var data = tobytearray(string);
$.ajax({
type: "POST",
url: "url_goes_here",
crossDomain: true,
data: data,
contentType: 'application/octet-stream;',
dataType: "json",
username: 'auth_username_goes_here',
password: 'auth_password_goes_here',
processData: false,
success: function (result) {
debugger;
},
error: function (jqXHR, textStatus, errorThrown) {
alert("error");
},
beforeSend: function (xhr) {
},
});
function tobytearray(str) {
var bytes = [];
for (var i = 0; i < str.length; ++i) {
bytes.push(str.charCodeAt(i));
}
return bytes;
}
}
What I see from your examples is the difference in the dataType used in the 2 examples.
In the C# example you use serviceClient.Headers["Content-type"] = "application/json"; and in the javascript implementation you use contentType: 'application/octet-stream;'.
octet-stream should be used for attachments and not JSON objects.
The webservice could be validating the request on the content-Type and if the test result is that your request is invalid it can return (and should return) a HTTP 400 - Bad Request.
I don't know the webservice where you shoot your requests at and what validations it does but try changing that contenttype in the javascript implementation to contentType: 'application/json;'.
Related
I've got working code in JQuery Ajax, however I've been told I have to use Native JS code to use it, and I'm not very familiar with using native JS for ajax, and most of the internet examples are basic ones. Basically, I have this object:
var Narudzba =
{
SifraNarudzbe: "AAA",
DatumNarudzbe: "",
Osigurano: document.getElementById("checkOsiguranje").value,
BrzaDostava: document.getElementById("checkBrza").value,
KlijentId: document.getElementById("klijentid").value,
Adresa: AdresaVar,
StatusNarudzbeID: 2,
Primaoc: PrimaocVar,
VrijemeIsporuke: null,
CijenaNarudzbe: UkupnaCijena,
NacinPlacanja: parseInt(document.getElementById("NacinPlacanja_Select").value)
};
Which I'm trying to post to my Controller. Here's how my working code in Jquery Ajax looks:
$.ajax({
url: "/klijentarea/klijent/SnimiNarudzbu",
data: Narudzba,
type: 'POST',
success: function (data) {
for (var i = 0; i < stavke_niz.length; i++) {
stavke_niz[i].NarudzbeId = parseInt(data);
}
stavke_niz = JSON.stringify(stavke_niz);
$.ajax({
url: "/klijentarea/klijent/SnimiStavke",
type: "POST",
dataType: "json",
data: stavke_niz,
contentType: 'application/json',
success: function (data) {
if (data === true) {
var id = document.getElementById("klijentid").value;
window.location.href = '/KlijentArea/Klijent?id=' + id;
}
}
});
}
});
Basically, it creates an order (Narudzba) with all sorts of details, posts it to this controller:
[HttpPost]
public int SnimiNarudzbu(Narudzbe Narudzba)
{
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var stringChars = new char[8];
var random = new Random();
for (int i = 0; i < stringChars.Length; i++)
{
stringChars[i] = chars[random.Next(chars.Length)];
}
var finalString = new String(stringChars);
Narudzba.SifraNarudzbe = finalString;
Narudzba.DatumNarudzbe = DateTime.Now;
ctx.Primaoci.Add(Narudzba.Primaoc);
ctx.Naruzbee.Add(Narudzba);
ctx.SaveChanges();
int newid = Narudzba.Id;
return newid;
}
Then I use the returned new ID, and assign it to all the objects inside stavke_niz, which is an array of order listings which gets created elsewhere in the code, and require OrderID before being added to database (I can add that code as well if necessary). Then the array with the updated OrderIDs gets sent to this controller:
[HttpPost]
public string SnimiStavke(IEnumerable<StavkaNarudzbe> stavke_niz)
{
if (stavke_niz != null)
{
ctx.StavkeNarudzbi.AddRange(stavke_niz);
ctx.SaveChanges();
return "true";
}
return "false";
}
Which successfully accepts the JSON posted with AJAX and adds the stuff to the database. Now, when I try to post in Native, like so:
var xhr = new XMLHttpRequest();
xhr.onload = function () {
if (xhr.status === 200 && this.readyState === 4)
{
alert(this.getAllResponseHeaders());
}
};
xhr.open('POST', '/klijentarea/klijent/SnimiNarudzbu', true);
xhr.send(Narudzba);
All of the values inside "Narudzba" are null, despite the object clearly having all the right values before being posted to controller. Help would be greatly appreciated.
You are missing Content-Type setting in your xhr request.
xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
This should solve your problem.
Hope this helps!
I am trying to create a Google Classroom course using the Google Classroom API and a service account. I am currently experimenting using JavaScript and I have everything set up and working to get a list of course. I set up a JWT and request an authentication token which I receive.
{"access_token":"----ACCESS TOKEN HERE----------","token_type":"Bearer","expires_in":3600}
When I use this to retrieve a user's course list (via GET) there is no problem. I receive back a proper response with a list of courses which I then display in a table.
When I try to use the same process to try to create a course (via POST), I get a 401 error:
{
"error": {
"code": 401,
"message": "The request does not have valid authentication credentials.",
"status": "UNAUTHENTICATED"
}
}
This is the code I use to authenticate:
function authenticate(callback) {
function b64EncodeUnicode(str) {
str = JSON.stringify(str);
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode('0x' + p1);
}));
}
// constuct the JWT
var jwtHeader = {
"alg":"RS256",
"typ":"JWT"
}
jwtHeader = JSON.stringify(jwtHeader);
//construct the Claim
var jwtClaim = {
"iss":"psclassroomsync#psclassroomsync.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/classroom.courses https://www.googleapis.com/auth/classroom.rosters",
"sub":"myemail#address.com", //this is an admin account I shouldn't really need this but tried with and without it
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp":(Math.round(new Date().getTime()/1000) + 60 * 10),
"iat":Math.round(new Date().getTime()/1000)
}
jwtClaim = JSON.stringify(jwtClaim);
//construct the signature
var key="-----BEGIN PRIVATE KEY-----Removed-----END PRIVATE KEY-----\n";
var jwtSign = b64EncodeUnicode(jwtSign);
var sJWT = KJUR.jws.JWS.sign("RS256", jwtHeader, jwtClaim, key);
var jwt = jwtHeader + "." + jwtClaim + "." + sJWT;
//request Token
var grantType = "urn:ietf:params:oauth:grant-type:jwt-bearer";
var tokenRequest = "grant_type=" + grantType + "&assertion=" + sJWT;
var postURL = "https://www.googleapis.com/oauth2/v4/token"
request = $j.ajax({
url: postURL,
type: "post",
data: tokenRequest,
success: callback
});
}
This is the code I use to GET the course list. (this works)
$j("#getClasses").click(function(event){
function getClasses(callback){
authenticate(function(data){
console.log(JSON.stringify(data));
var access_token = data["access_token"];
var apiUrl = 'https://classroom.googleapis.com/v1/courses'
var myData = 'teacherId=~(teacheremail)&access_token='+access_token;
var files = $j.ajax({
url: apiUrl,
type: "get",
data: myData,
success: function (data) {
var retreivedClasses = JSON.stringify(data);
for(var i = 0; i < data['courses'].length; i++){
nextObject = data['courses'];
$j('#classListTable').append('<tr><td>' + nextObject[i]['name'] + '</td><td>' + nextObject[i]['courseState'] + '</td><td>' + nextObject[i]['enrollmentCode'] + '</td></tr>');
}
//$j('#classList').text(retreivedClasses);
}
});
});
}
getClasses();
});
This is the code that I use to create a course via POST. I've hard coded a few of the variables for testing but still gives the 401 error.
$j("#createClass").click(function(event){
function createClass(callback){
authenticate(function(data){
console.log(JSON.stringify(data));
var access_token = data["access_token"];
var tokenInfo = $j.ajax({
url: 'https://www.googleapis.com/oauth2/v3/tokeninfo',
type: 'get',
data: "access_token="+access_token
});
var apiUrl = 'https://classroom.googleapis.com/v1/courses'
var myData = 'access_token='+access_token + '&ownerId=myemail#address.com&name=myClass'
console.log(myData);
var newGoogleClassroom = $j.ajax({
url: apiUrl,
type: "post",
data: myData,
success: function (data) {
var apiResponse = JSON.stringify(data);
$j('#classCreated').text(apiResponse);
}
});
});
};
createClass();
});
Finally, this is what I get when I get the token info. It looks fine to me i.e. proper scopes: (but I am new at this)
{
"azp": "removed",
"aud": "removed",
"scope": "https://www.googleapis.com/auth/classroom.courses https://www.googleapis.com/auth/classroom
.rosters",
"exp": "1474512198",
"expires_in": "3600",
"access_type": "offline"
}
I'd be grateful for any help.
Doug
P.S. I get the security implications of this code. It is in a secure environment for experimentation only. It won't see the light of day.
Based from this forum which is also receiving a 401 error, try to revoke the old oauth. As stated in this related thread, the 401 Unauthorized error you experienced may be related to OAuth 2.0 Authorization using the OAuth 2.0 client ID.
Suggested action: Refresh the access token using the long-lived refresh token. If this fails, direct through the OAuth flow.
I have a simple program that is scraping a web site for some items. I am using Angular $http service to call the below C# method to get the markup from the page and then handling everything else with JS. Everything is working perfectly fine with the exception of a minor annoyance: a bunch of 404 errors.
The 404 errors are being displayed in the developer tools once the http get call completes. It's almost like the javascript is trying to interpret the HTML and then fails on all the get requests for the images in the browser:
What I'm trying to figure out is how to get the 404 errors to go away or fail silently (not display in the console). I'm not finding anything in my research but am assuming there is some way to handle this whether it be on the server or client side
C#
public static string GetPageSource()
{
JObject result = new JObject();
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://awebpage.html");
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
result["data"] = reader.ReadToEnd();
result["success"] = true;
reader.Close();
response.Close();
}
catch (Exception ex)
{
result["data"] = ex.Message;
result["success"] = false;
}
return JsonConvert.SerializeObject(result);
}
JS
$scope.getPageSource = function () {
var ajaxProcessor = Utils.ajaxMessage('Scraping Beer Menu From Source');
ajaxProcessor.start();
$http({
method: 'POST',
url: 'AJAX/MenuHandler.aspx/GetPageSource',
contentType: 'application/json; charset=utf-8',
dataType: 'json',
data: {}
}).then(function (response) {
ajaxProcessor.stop();
var result = $.parseJSON(response.data.d);
if (result.success === false) {
Utils.showMessage('error', result.data);
} else {
var beerMenu = new BeerMenu(result.data, $scope.loggedInUser, function (beerMenu) {
$scope.buildDisplayMenu(beerMenu);
});
}
}, function (err) {
ajaxProcessor.stop();
console.log(err);
Utils.showMessage('error', err.data.Message);
});
};
UPDATE
Thanks to #dandavis, my issue is narrowed down to calling $.parseHTML within the buildDisplayMenu function (which calls buildCurrentMenu). Is there anyway to make it ignore the images or any get request?
buildCurrentMenu: function () {
var html = $.parseHTML(this.pageSource);
var menuDiv = $(html).find('.TabbedPanelsContent')[0];
var categories = $(menuDiv).find('h2');
var categegoryItems = [];
var beerArray = [];
for (var i = 0; i < categories.length; i++) {
...
}
return beerArray;
}
The resolution is to remove any img tags (or any other tag that should be ignored) from the page source before calling $.parseHTML
this.pageSource = this.pageSource.replace(/<img[^>]*>/g, "");
I use jquery (ajax) to connect to a web service which returns string , it is not working with me. it always go to error function. here is my web service :
[HttpGet]
[ActionName("GetImage")]
public string GetImage(string base64String, string imgName,string reqTitle , string reqSubject, string reqStatus,string Creator , DateTime creationdate )
{
try
{
using (PhMobAppEntities context = new PhMobAppEntities())
{
ClaimsApproval _ca = new ClaimsApproval();
_ca.imageBasestrg = base64String;
_ca.imageName = imgName;
_ca.Creator = Creator;
_ca.CreationTime = creationdate;
_ca.ReqStatus = reqStatus;
_ca.ReqTitle = reqTitle;
_ca.ReqSubject = reqSubject;
context.ClaimsApprovals.Add(_ca);
context.SaveChanges();
return "Success";
}
}
catch (DbEntityValidationException ex)
{
var errorMessages = ex.EntityValidationErrors
.SelectMany(x => x.ValidationErrors)
.Select(x => x.ErrorMessage);
var fullErrorMessage = string.Join("; ", errorMessages);
var exceptionMessage = string.Concat(ex.Message, " The validation errors are: ", fullErrorMessage);
throw new DbEntityValidationException(exceptionMessage, ex.EntityValidationErrors);
}
}
and here is my js code :
$("#sendphoto").click(function () {
var url = "http://41.128.183.109:1212/api/Data/GetImage";
var data = {
imgName: "test"
};
$.ajax({
url: url,
type: 'Get',
data: data,
success: function (data) {
alert("Success");
},
error: function (data) {
alert("Please Check Your Internet Connection");
}
});
});
It is running ok when i tested my web service in advanced rest client ,please advice .
I tried connecting to your web service and I get the following response:
{"$id":"1","Message":"No HTTP resource was found that matches the request URI 'http://41.128.183.109:1212/api/Data/GetImage'."}
I think what you have is an internal problem with your c# code, probably with your routing. Your javascript call is probably working fine, but you are passing only one parameter, "test" while you have many more in your declaration.
What http response code are you getting?
I'm creating mvc 4 application where I call a function in controller from a js file using ajax.
When I call the function from ajax, its calling the respective function properly. But neither success nor error function is not firing . Could someone help me out to correct my mistake?
I would like to read the data from database convert it to json format and write it into a .js file and thereafter success function to be fired off. Help me to solve this. Thanks in advance.
Here is my Code.
$.ajax({
//url: '#Url.Action("getJsonData","Home")',
url: "Home/getJsonHugeData1",
//data: "{}",
type: "GET",
//contentType: 'application/json',
//dataType: "json",
success: function () {
alert();
alert('success getJsonHugeData');
loaddata(data);
},
error:function(){
alert('error');
}
});
Controller:
public JsonResult getJsonHugeData()
{
var users = GetUsersHugeData();
string json = "var dataSource=";
json += JsonConvert.SerializeObject(users.ToArray());
System.IO.File.WriteAllText(Server.MapPath("/Scripts/NewData.js"), json);
return Json(users, JsonRequestBehavior.AllowGet);
}
private List<UserModel> GetUsersHugeData()
{
var usersList = new List<UserModel>();
UserModel user;
List<dummyData> data = new List<dummyData>();
using (Database1Entities dataEntity = new Database1Entities())
{
data = dataEntity.dummyDatas.ToList();
}
for (int i = 0; i < data.Count; i++)
{
user = new UserModel
{
ID = data[i].Id,
ProductName = data[i].ProductName,
Revenue = data[i].Revenue,
InYear = data[i].InYear.Year
};
usersList.Add(user);
}
}
I believe your browser will block the file downloaded via ajax, this is because JavaScript cannot interact with disk. If you want to get this working, you will have to do so using a form post.
#using (Html.BeginForm("Action", "Controller", FormMethod.Post, new { id = "DownloadForm" }))
{
... form data would be here if you had any...
<button type="submit">Download</button>
}
You would then return a FileStreamResult with the contents of the file to be downloaded.
public ActionResult Action(FormModel model)
{
// Do work to get data for file and then return your file result to the browser.
return new FileStreamResult(new MemoryStream(fileData), "text/csv") // set the document type that is valid for your file
{
FileDownloadName = "users.csv"
};
}
I ran all of your code except for the following since you didn't provide the UserModel and dummydata classes in your question:
private List<UserModel> GetUsersHugeData()
{
var usersList = new List<UserModel>();
UserModel user;
List<dummyData> data = new List<dummyData>();
using (Database1Entities dataEntity = new Database1Entities())
{
data = dataEntity.dummyDatas.ToList();
}
for (int i = 0; i < data.Count; i++)
{
user = new UserModel
{
ID = data[i].Id,
ProductName = data[i].ProductName,
Revenue = data[i].Revenue,
InYear = data[i].InYear.Year
};
usersList.Add(user);
}
}
The end result was that you had a typo in your ajax 'url' parameter. Also, if you are going to check for errors, set your function to
function(jqxhr, status, error) {
alert(error);
}
to check the error being thrown.