I'm developing a web site associated to a SQL database and Azure web app. The app support authentication. For now, I'm able to login a user using Owin OAuthAuthorizationServerProvider class.
Here is the code I'm using to POST login data from my Angularjs file :
fac.login = function (user) {
var obj = {
'username': user.username, 'password': user.password,
'grant_type': 'password'
};
Object.toparams = function ObjectsToParams(obj)
{
var p = [];
for (var key in obj)
{
p.push(key + '=' + encodeURIComponent(obj[key]));
}
return p.join('&');
}
var defer = $q.defer();
$http({
method: 'post',
url: serviceBasePath + "/token",
data: Object.toparams(obj),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function (response) {
userService.SetCurrentUser(response.data);
defer.resolve(response.data);
}, function (error) {
defer.reject(error.data);
})
return defer.promise;
}
And I deal with the data and identity by overriding : Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context).
This works perfectly. I'm now trying to create a "Sign In" page based on the same structure.
I think I know how to post the data with AngularJS like this :
fac.suscribe = function (newUser) {
var obj = {
'username': newUser.username, 'surname': newUser.surname, 'firstname': newUser.firstname,
'password1': newUser.password1, 'password2': newUser.password2, 'email': newUser.email, 'guid': newUser.guid
};
Object.toparams = function ObjectsToParams(obj) {
var p = [];
for (var key in obj) {
p.push(key + '=' + encodeURIComponent(obj[key]));
}
return p.join('&');
}
var defer = $q.defer();
$http({
method: 'post',
url: serviceBasePath + "/register",
data: Object.toparams(obj),
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
}).then(function (response){
userService.SetCurrentUser(response.data);
defer.resolve(response.data);
}, function (error) {
defer.reject(error.data);
})
return defer.promise;
}
But I wonder how I can get the data to generate the post answer. Any idea on C#, preferably ?
First, You should have Model same with same property name on the server side. So that the property that you are sending in the object from angularjs will get binded to the Model Properties. Instead of having headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, change it to headers: { 'Content-Type': 'application/json' } for the Web API.
For your reference i am sharing this link
CRUD WITH ANGULARJS and ASP.NET WEB API
Related
I am a new to ASP.NET MVC. I want to call an API on a payment gateway. The API only tries to resolve Users Identity. I have written the CURL in C# but I seem to be stuck on how to proceed to get the API called and also return a JSON using AJAX.
Below is the Curl converted to C#.
[HttpPost]
public JsonResult ResolveBVN()
{
//string str = BVN;
var secretKey = "secretkey";
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretKey}");
var response = client.PostAsync("https://api.paystack.co/bvn/match", new StringContent("{ bvn: \"22146592120\",\n account_number: \"0689688306\",\n bank_code: \"044\",\n first_name: \"uthman\",\n last_name: \"jinadu\"\n }")).Result;
PaystackAPI paystackAPI = new PaystackAPI()
{
statuscode = response.IsSuccessStatusCode,
message = response.StatusCode
};
return Json(paystackAPI);
}
}
The AJAX call is below:
$("#btnGetBVN").click(function () {
if ($('#BVN').val() == '' || $('#BVN').val() == undefined) {
alert('Please Enter Customer BVN');
return false;
}
$('.spinner').css('display', 'block'); //if clicked ok spinner shown
$.ajax({
type: "POST",
url: "#Url.Action("ResolveBVN", "Transactions")",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
alert(response.status);
$('#Firstname').val(response.data.first_name);
$('#Surname').val(response.data.last_name);
// $('#Phone_Number').val(response.data.mobile);
$('.spinner').css('display', 'none');
},
failure: function (response) {
alert('BVN Does Not Exist Or Error Processing Request');
$('.spinner').css('display', 'none');
},
error: function (response) {
alert('BVN Does Not Exist Or Error Processing Request');
$('.spinner').css('display', 'none');
}
});
});
The alert message response is UNDEFINED
EDIT
I have added the Class to return the JSon to the AJAX call. I can only use the statuscode of the response.
How can I access the other part of the response? The response sample is below:
{
"status": true,
"message": "BVN lookup successful",
"data": {
"bvn": "000000000000",
"is_blacklisted": false,
"account_number": true,
"first_name": true,
"last_name": true
},
"meta": {
"calls_this_month": 1,
"free_calls_left": 9
}
}
How do I access the other parts in the class like account_Number, message and the likes.
Please use below :-
var secretKey = string.Empty;
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {secretKey}");
var response = httpClient.PostAsync("https://api.paystack.co/bvn/match", new StringContent("{ bvn: \"12345678912\",\n account_number: \"0000000000\",\n bank_code: \"087\",\n first_name: \"bojack\",\n last_name: \"horseman\"\n }")).Result;
}
Please make sure to set the correct secret key.
you should be writing this code in the the method which is being called by the ajax.Response variable will contain the response returned by the paystack api
I have a method on an API Controller where I've set the route in an attribute, but I don't seem to be able to pass a string into this. When I try to hit this with an Ajax Request from the browser the console shows the following error:
BAD REQUEST - The request could not be processed by the server due to
invalid syntax.
The string I'm passing over is huge, but unfortunately is the only way I can import the data into the legacy application I'm working with. The test URL I'm using is (brace yourselves):
http://localhost:50915/api/job/import/ALMIG³123456³2%20DAY%20ECONOMY³20170720³20170721³0³³³³22³Lara%20Croft%20Way³Derby³³³DE23%206GB³Stuff³10³1³0³25³0³³1%7CI%20Great%20Danger³0³0³0³³³0³true³0³³³³³³³1³0³0³16³Baden%20Road³Stoke-on-Trent³³³ST6%201SA³³0³0³0³³³³0³0³0³0³³0³1³0³³³³³³³³³³³Liane³07730044916³Lara³07730044916³0³d2f0acf7-50e1-4a53-96ce-4fffd00b1a96³0
And the method is defined as below, the code inside is irrelevant as I put a break point on the start of the method which is never hit:
[System.Web.Http.HttpPost]
[System.Web.Http.Route("api/job/import")]
public int TmsImport([FromBody]string import)
{
// do something...
}
Edit: Added Ajax Request
job.confirmBookings = function () {
// TMS Import
job.toConfirmRow.filter(function(obj) {
var jobRow = obj;
var strArray = [];
for (var prop in jobRow) {
if (jobRow.hasOwnProperty(prop)) {
strArray.push(jobRow[prop]);
}
}
var joinedStr = strArray.join(job.seperator);
$.ajax({
type: "POST",
crossDomain: true,
data: joinedStr,
url: job.tmsString,
contentType: "application/json;charset=utf-8",
success: function (data, status, xhr) {
console.log("TMS ID: " + data + " | " + status);
},
error: function (xhr) {
alert(xhr.responseText);
}
});
});
First format the route template correctly
[HttpPost]
[Route("api/job/import")] //Matches POST api/job/import
public int TmsImport([FromBody]string import) {
// do something...
}
Also you should post the data in the body of the request. If the payload is large then you do not want that in the URL
I don´t know why my parameter "ParametroFiltro Filtro" is getting null, the other parameters "page" and "pageSize" is getting OK.
public class ParametroFiltro
{
public string Codigo { get; set; }
public string Descricao { get; set; }
}
My ApiController Get method:
public PagedDataModel<ParametroDTO> Get(ParametroFiltro Filtro, int page, int pageSize)
My ajax call:
var fullUrl = "/api/" + self.Api;
$.ajax({
url: fullUrl,
type: 'GET',
dataType: 'json',
data: { Filtro: { Codigo: '_1', Descricao: 'TESTE' }, page: 1, pageSize: 10 },
success: function (result) {
alert(result.Data.length);
self.Parametros(result.Data);
}
});
You are trying to send a complex object with GET method. The reason this is failing is that GET method can't have a body and all the values are being encoded into the URL. You can make this work by using [FromUri], but first you need to change your client side code:
$.ajax({
url: fullUrl,
type: 'GET',
dataType: 'json',
data: { Codigo: '_1', Descricao: 'TESTE', page: 1, pageSize: 10 },
success: function (result) {
alert(result.Data.length);
self.Parametros(result.Data);
}
});
This way [FromUri] will be able to pick up your complex object properties directly from the URL if you change your action method like this:
public PagedDataModel<ParametroDTO> Get([FromUri]ParametroFiltro Filtro, int page, int pageSize)
Your previous approach would rather work with POST method which can have a body (but you would still need to use JSON.stringify() to format body as JSON).
Provide the contentType property when you make the ajax call. Use JSON.stringify method to build the JSON data to post. change the type to POST and MVC Model binding will bind the posted data to your class object.
var filter = { "Filtro": { "Codigo": "_1", "Descricao": "TESTE" },
"page": "1", "pageSize": "10" };
$.ajax({
url: fullUrl,
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(filter),
success: function (result) {
alert(result.Data.length);
self.Parametros(result.Data);
}
});
It's also possible to access POST variables via a Newtonsoft.Json.Linq JObject.
For example, this POST:
$.ajax({
type: 'POST',
url: 'URL',
data: { 'Note': note, 'Story': story },
dataType: 'text',
success: function (data) { }
});
Can be accessed in an APIController like so:
public void Update([FromBody]JObject data)
{
var Note = (String)data["Note"];
var Story = (String)data["Story"];
}
If you append json data to query string, and parse it later in web api side. you can parse complex object too. It's useful rather than post json object, espeicaly in some special httpget requirement case.
//javascript file
var data = { UserID: "10", UserName: "Long", AppInstanceID: "100", ProcessGUID: "BF1CC2EB-D9BD-45FD-BF87-939DD8FF9071" };
var request = JSON.stringify(data);
request = encodeURIComponent(request);
doAjaxGet("/ProductWebApi/api/Workflow/StartProcess?data=", request, function (result) {
window.console.log(result);
});
//webapi file:
[HttpGet]
public ResponseResult StartProcess()
{
dynamic queryJson = ParseHttpGetJson(Request.RequestUri.Query);
int appInstanceID = int.Parse(queryJson.AppInstanceID.Value);
Guid processGUID = Guid.Parse(queryJson.ProcessGUID.Value);
int userID = int.Parse(queryJson.UserID.Value);
string userName = queryJson.UserName.Value;
}
//utility function:
public static dynamic ParseHttpGetJson(string query)
{
if (!string.IsNullOrEmpty(query))
{
try
{
var json = query.Substring(7, query.Length - 7); //seperate ?data= characters
json = System.Web.HttpUtility.UrlDecode(json);
dynamic queryJson = JsonConvert.DeserializeObject<dynamic>(json);
return queryJson;
}
catch (System.Exception e)
{
throw new ApplicationException("can't deserialize object as wrong string content!", e);
}
}
else
{
return null;
}
}
In .NET Core, the HttpClient sets the transfer-encoding: chunked header by default. This can cause the .NET Web API controller parameters to be null.
To get around this, you'll need to set the ContentLength header explicitly:
var json = JsonConvert.SerializeObject(myObject);
var content = new StringContent(json, Encoding.UTF8, "application/json");
content.Headers.ContentLength = json.Length;
var response = await client.PostAsync("http://my-api.com", content);
SO answer if you already know the transfer-encoding header is the issue: How to disable Chunked Transfer Encoding in ASP.Net C# using HttpClient
Related bug which won't be fixed, which gives some insight into the problem: https://github.com/dotnet/runtime/issues/30283
I have WebApi Application and a simple consuming web client. I am sending requests to webApi using angularJS from web client. And cors is already enabled of course.
I have had problems with Post on chrome but I fixed it using param to the object sent, I thought it would be the same for Put but I got 'XMLHttpRequest cannot load URL. Invalid HTTP status code 400' on chrome whereas it's working okay on IE.
C# code :
public void UpdateLampe(int Id, Lampe lampe)
{
var context = new eDomDataContext();
var found = context.Lampes.SingleOrDefault(p => p.Id == Id);
if (found != null)
{
found.Etat = lampe.Etat;
found.Date = DateTime.Now;
context.Lampes.Attach(found);
context.Entry(found).State = EntityState.Modified;
context.SaveChanges();
}
}
//Post request (works ok)
var lampe = $.param({'TypeObject': typeObject, 'SalleId': salleId});
$http({
method: "POST",
url: "http://localhost:1770/api/Lampe",
data: lampe,
headers: {'Content-Type': 'application/x-www-form-urlencoded',}
}).success(function (data) {
alert("it works");
}).error(function () {
console.log(Error);
alert('Error reading JSON file.');
})
.then(function (response) {
return response;
});
//Put request <= still have problem
var etat = $.param({'Etat' : false});
$http({
method: "PUT",
url: "http://localhost:1770/api/Lampe/1" ,
data: etat,
headers: {'Content-Type': 'application/x-www-form-urlencoded',}
}).success(function (data) {
alert("it works");
}).error(function () {
console.log(Error);
alert('Error reading JSON file. - ');
})
.then(function (response) {
return response;
});
Is there anything with what I did?
Thank you for your help.
I found a solution here : http://ask.webatall.com/iis/18460_asp-net-web-api-put-delete-verbs-not-allowed-iis-8.html
It was all about allowing the PUT & DELETE in the web.config
It might help someone.
I need to pass an id and get the related questions.
Error message - POST http://localhost:51949/API.asmx/GetAllQuestions/0 - 500 (Internal Server Error)
The web service works fine as I have checked in other part of C# code. Now, trying to access it from angularjs. Is this the right way?
app.js:
var app = angular.module('virtualApp', []);
controller.js:
app.controller("virtualController", function ($scope, DataFactory) {
$scope.categories=[];
$scope.GetAllQuestions = function (categoryId) {
DataFactory.GetAllQuestions(categoryId)
.success(function (data) {
$scope.categories = data;
})
.error(function (error) {
alert(error.message);
});
}
$scope.GetAllQuestions(0); //to fire at page load
});
services.js:
EDIT
app.factory("DataFactory",function ($http) {
var urlBase = "http://localhost:51949/API.asmx/";
var dataFactory = {};
dataFactory.GetAllQuestionCategories = function (categoryId) {
return $http.post(urlBase + "GetAllQuestions", { categoryId: categoryId })
.success(function (data, status, headers, config) {
})
.error(function (data, status, headers, config) {
});
return dataFactory;
});
I think problem with you code is you are passing id as part of url instead of it pass id in data of ajax request
Dont pass data in url like as below
//do not attach categoryId
urlBase + "GetAllQuestions/" + categoryId
instead of it pass data in data parameter of request like as below code
data: { test: 'test' }
and url will be urlBase + "GetAllQuestions
var req = {
method: 'POST',
url: 'http://example.com',
headers: {
'Content-Type': undefined
},
data: { test: 'test' },
}
$http(req).success(function(){...}).error(function(){...});
one more thing you are calling function to get data than make use of Get method instead of Post method.