Consume WCF Webservice with angular/javascript - javascript

I'm implementing a server with WCF and trying to reach its rest services using a client developed with Angular.
Here is the service :
public interface IConnexion
{
[OperationContract]
[WebGet(UriTemplate = "Connexion/{login}/{mdp}", ResponseFormat = WebMessageFormat.Json)]
Utilisateur Connexion(string login, string mdp);
[OperationContract]
[WebInvoke(UriTemplate = "Deconnexion/{id_user}", RequestFormat = WebMessageFormat.Json)]
void Deconnexion(string id_user);
}
And my function trying to reach the service :
app.service('serverConnexionServices', function(userService, serverConfigService) {
this.Connexion = function(login, pass)
{
var uri = this.getServerUri() + "Connexion/"+login+"/"+CryptoJS.MD5(pass);
var promises = $http.get(uri)
.success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
return data;
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
return "";
});
return promises;
};
});
my form's controller:
app.directive('loginContent', function(userService, serverConnexionServices){
return{
restrict : 'E',
templateUrl : "includes/home/login-content.html",
controllerAs: "loginController",
controller: function($scope, userService, serverConnexionServices) {
var IsSubmitEnabled = true;
this.errors = "";
this.validateLogin = function(user) { // Calling the service
this.IsSubmitEnabled = false; // To avoid more than one click while checking on the server
var retour = serverConnexionServices.TryConnection(user).then(function(promise) {
alert('promise:'+retour);
if(promise.length > 0)
{ // There is an error so we show a message to the user
this.promise= retour;
}
this.IsSubmitEnabled = true;
user = {};
});
};
}
}
});
But when I try to open my client the alert box appears before the breakpoint is raised in Visual Studio (I put the breakpoint on the first line of my "Connexion" function. So it means the server has not answered yet to the request but the $http.get() has already sent its answer. So the result object doesn't contain what the server is sending. According to Angular's documentation, the response will be sent asynchronously. But How can I force my request to wait the answer ?
My controller now gets the answer from the server but it doesn't update the view, and if I try to call manually $scope.$apply() I get the error "$digest already in progress". How can I force my view to refresh itself ? (I noticed that if I put this.errors = "aaa"; once the "then" is closed, my view is refreshed and whos "aaa", I've also checked that errors.length > 0 with an alert message)
My view :
<div ng-show="loginController.errors.length > 0" class="alert alert-danger" role="alert" style="display: inline-block;"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>{{loginController.errors}}</div>
EDIT: I can now reach my breakpoint in the implementation of Connexion in Visual Studio but still the answer from the server is not what is expected
EDIT2 : I've added my controller which needs the refresh.
EDIT3 : Ok, I updated my code, I needed to put a "then" function on my controller's call and my controller now get the answer. However my view doesn't update itself on errors. It should set the div visibility to true but the async call seems to block it. I've tried to use apply() and digest() without success. Could you help me on this ?

Related

Call Angularjs HTTP request service from jquery call or Select open

I'm new in angular and I need help to call an http request.
I had this controller
var app = angular.module('myApp',[]);
app.controller('freeUserController', function($scope, $http) {
$http({
method: 'GET',
url: 'users'
}).then(function successCallback(response) {
$scope.users = response.data.result;
// 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.
});
});
It allows to fill Select in a modal form
This Select change every time user click on confirm button(select shows free users) so I though to create a service with the above http call and use this or on confirm button ( or on inside javascript of confirm button) or when user clicks on select tho show user.
So I change angular code like this:
var app = angular.module('"modalUploadLicense"',[]);
app.controller('freeUserController', function() {
freeUserService();
});
app.service("freeUserService",function($scope, $http){
$http({
method: 'GET',
url: 'users'
}).then(function successCallback(response) {
$scope.users = response.data.result;
// 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.
});
});
But it give me an error and moreover I don't know the best way to call the service when the user list change.
This is my confirm button javascript:
$("#createLicenseButton").click(
function() {
var form = $("#addLicenseForm");
$.ajax({
type : "POST",
url : form.attr("action"),
data : form.serialize(),
// all right with rest call
success : function(data) {
//No exception occurred
if (data.status==true){
//Also the field are right(for e.g. form value)
if(data.success==true){
//il risultato sta in data.result
//window.location.reload(true);
$('#licensesTable').load(document.URL + ' #licensesTable');
angular.element(document.getElementById('freeUserController')).scope().get();
//reload only the tag with id carsTable, so only the table
//$('#carsTable').load(document.URL + ' #carsTable');
$('#addLicenseModal').modal("hide");
notifyMessage("Your license has been created!", 'success');
}
else{
//code if there are some error into form for example
}
} else {
//code exception
$('#addLicenseModal').modal("hide");
notifyMessage("Error! Your license hasn't been created!", 'error');
}
},
//error during rest call
error : function(data) {
window.location.href = "/ATS/500";
}
});
});
Whereas html Select is:
<label>Username</label> <select class="form-control select2"
style="width: 100%;" name="user" ng-model="selectedItem" ng-options="user.username as user.username for user in users track by user.username">
</select>
How can I update my Select value?thanks
First, change your service so it has a function to call:
app.service("freeUserService",['$http', function($http){
var service = this;
service.getusers = getusers;
function getusers() {
var url = "your url gets here";
return $http.get(url);
}
}]);
Then like Arnab says, you need to change your controller:
app.controller('freeUserController', ['freeUserService', '$scope', function(freeUserService, '$scope') {
$scope.fetchusers = function() {
freeUserService.getusers()
.then(handleGetUsers)
.catch(handleErrors);
}
function handleGetUsers(result){
//This is a promise, because $http only does asynchronous calls. No
//need to wrap this in a jquery thingy.
//As soon as the async function is resolved, the result data is put
// on your scope. I used $scope.users on purpose, because of your
//html
$scope.users = result.data;
}
function handleErrors(error){
console.log(error);
}
}]);
As you can see, I have put the "variable" users on the scope. I did this on purpose because of your html
<label>Username</label> <select class="form-control select2"
style="width: 100%;" name="user" ng-model="selectedItem" ng-options="user.username as user.username for user in users track by user.username">
</select>
The select looks into the scope for a variable called users. Because the variable users is on your html, angular automatically watches the variable for changes.
What I understand from your question is that every time the http call is done, you get another result, right? So Angular will automatically watch for a change, and reflect the result on your select element. if interested in more information, you should read this. I also suggest following a 'start with Angular tutorial', because going from your question, I think you are missing the basics of Angular.
The last step you need to do (I think, if i understand your question), is bind the $http function to your HTML. There is a "ng-click" directive you can use. In your case, the button then could look like this:
<button ng-click="fetchusers()" type="submit">Get me new users</button>
As you can see, I use the $scope.fetchusers() function in the ng-click directive, wich will make a new http call, getting new uses (ofcourse, if the http call gets new users every time you call it).
Plunker with modified code here.
You can use the ng-init directive to initialize the value. I ll update my plunker so that you can see how the ng-init works. You should set it right next to your ng-controller. ng-init will make the first call and give you data from the start. Then every time you press the button, new data will come, and your select will be updated. I have updated the plunk. I have added one of my own webservices. Do mind, my webservices are on a free heroku account. If you wait too long, the heroku application will go to sleep mode and the first call for data will timeout.
About multiple asynchronous calls:
Angular promises can be chained! So you can do one asynchronous call (for example doing a post to a database), wait for it to finish, then get the updated data. In your service, you could do this:
function getUsers(parameters) {
var posturl = "url to post to";
return $http.post(url, data) //the update, it returns a promise
.then(handlePost)
.catch(handleError);
}
function handlePost(result){
//the $http.get will only be executed after the previous promise has been
//resolved!
var geturl = "url to get data from";
return $http.get(url); // this is the second asynchronous call
}
It is good practice to chain promises. It would be bad practice to use a jQuery ajax call for this.
Inject freeUserService to your controller freeUserController to atleast call the service from your controller, like:
app.controller('freeUserController', ['freeUserService', function(freeUserService) {
freeUserService();
}]);
Otherwise you write like this:
var app = angular.module('myApp',[]);
app.controller('freeUserController', ['freeUserService', function($scope, freeUserService) {
var promise = freeUserService();
promise.then(function successCallback(response) {
$scope.users = response.data.result;
// 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.
});
// And bind the users variable in your template
}]);
app.service("freeUserService", ['$http', function($http){
return $http({
method: 'GET',
url: 'users' // Proper url to your api
});
}]);

Angular making pseudo-synchronous HTTP requests

I want to construct a mechanism that would access a database via POST requests. So far, I do received the desired data, but am have issues with the timing. Here are three pieces of code that I'm using (simplified to keep the focus of the question).
First, a factory handling the HTTP request vis-à-vis a servlet:
var My_Web = angular.module('My_Web');
My_Web.factory('DB_Services', function($http , $q) {
var l_Result ;
var DB_Services = function(p_Query) {
var deferred = $q.defer();
var url = "http://localhost:8080/demo/servlets/servlet/Test_ui?";
var params = "data=" + p_Query ;
var Sending = url + params ;
$http.post(Sending).
success(function(data, status, headers, config) {
deferred.resolve(data);
}).
error(function(data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
}
return DB_Services;
});
Second, a general purpose function handling the promise (or so I meant) exposed to all the controllers that would need to extract data from the remote DB:
$rootScope.Get_Data_from_DB = function(p_Query) {
DB_Services(p_Query).then(function(d) {
console.log("In Get_Data_from_DB; Received data is: " + JSON.stringify(d));
$scope.data = d;
});
};
Third, one example within one of the controllers:
$scope.Search_Lookups = function () {
console.log ("search for lookup data...") ;
var l_Lookup_Type = document.getElementById("THISONE").value ;
var l_Send_Request_Data = '{"Requestor_ID":"4321" , "Request_Details" : { "Data_type" : "' + l_Lookup_Type + '" } }' ;
console.log("Sending Request: " + l_Send_Request_Data) ;
l_Data = $rootScope.Get_Data_from_DB(p_Query) ;
console.log ("Received response: " + l_Data) ;
Deploy_data(l_Data) ;
}
The function Deploy_data(l_Data) is responsible of dismembering the received data and put the relevant pieces on screen.
What happens is that I get on the console the string Received response: undefined and immediately after the result of the retrieval as In Get_Data_from_DB; Received data is: (here I get the data).
The Received response: undefined is printed from the invoking function (third piece of code), whereas the output with the actual data is received and printed from within the second piece of code above. This means that the invocation to Deploy_data would not receive the extracted data.
Once again, the same mechanism (i.e. the factory $rootScope.Get_Data_from_DB) would be vastly used by many controllers.
I thought of using $scope.$watch but I'm not sure because the same user might be triggering several queries at the same time (e.g. request a report that might take few seconds to arrive and, in the meantime, ask for something else).
I think I found a solution (at least it appears to be ok for the time being). The global function Get_Data_from_DB accepts a second parameter which is a callback of the invoking controller.
The invoking controller creates a private instance of the Get_Data_from_DB function and triggers a request providing the callback function.
I'll need to test this with parallel queries, but that is still a long way to go...

ASP.NET MVC & Angular: After session expires, Angular Factory returns HTML of Login Page instead of JSON object

If the user is on a page for a long time and the session ends, if they proceed to make an AJAX call after the session is already expired.. instead of receiving the JSON object, it instead receives the HTML of the login page.
Ideally I'm trying to make it so that it will redirect to a log in page.
Is there any way i can detect this?
I already have an ActionFilterAttribute that works for non-AJAX calls like so:
public class VerifySessionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var userId = filterContext.HttpContext.Session["UserId"];
var userName = filterContext.HttpContext.Session["UserName"];
if (userId == null || userName == null)
{
filterContext.Result = new RedirectResult(string.Format("/Account/Login"));
return;
}
base.OnActionExecuting(filterContext);
}
}
But that doesn't get hit for the scenario above during AJAX calls.
I've also tried an Interceptor.. something like this:
app.factory('httpAuthInterceptor', function ($q) {
return {
'responseError': function (response) {
// NOTE: detect error because of unauthenticated user
if ([401, 403].indexOf(response.status) >= 0) {
// redirecting to login page
//$state.go('home');
$window.location.href = '/Account/Login';
return response;
} else {
return $q.reject(rejection);
}
}
};
})
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('httpAuthInterceptor');
});
But in the same scenario it doesn't seem to hit there as well during the expired session / AJAX call
Is there anything I can do to detect this? When the session is expired I just want to redirect to the login page.. Thanks for any help
EDIT: here's how I make my calls
app.factory('HeadlinesFactory', ['$http', function ($http) {
var HeadlinesFactory = {};
HeadlinesFactory.getShowsForClient = function (clientId) {
return $http({
method: 'POST',
url: '/Show/GetShowsForClient',
data: { clientId: JSON.stringify(clientId) }
});
};
//etc
EDIT2: how all my controllers look like. Except my Account Controller where I put the VerifySession in front of everything except the Login page to prevent loop redirects:
[Authorize]
[CustomFilters.VerifySession]
public class ShowController : Controller
{ ... }
Ajax requests will not process redirect requests for security reasons. In addition, since you are returning a redirect result, a 401/403 status code is not thrown but rather a 302 is returned.
What you could do is expand your filter to conditionalize logic based on whether or not the request is an ajax request. In addition, based on your comments, it seems like creating a new Authorize attribute instead would be the right way to go since that way you can simply replace the default Authorize attribute with your own logic.
public class VerifySessionAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.HttpContext.Response.StatusCode = 401;
filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect =
true;
}
else
{
filterContext.Result = new RedirectResult(string.Format("/Account/Login"));
return;
}
}
}
}
This would allow your Angular interceptor to pick up the request and handle it appropriately.
Since IsAjaxRequest looks explicitly for the "X-Requested-With": "XMLHttpRequest" and AngularJS no longer provides that header with Ajax requests, you can add a configuration to the $httpProvider to always include the header.
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
}]);

UI freezes with multiple http calls in AngularJS

Please find below the angularjs factory method to call http request:
var HttpService = angular.module("HttpService",[]);
HttpService.factory("HttpServiceFactory",['$http', '$q', '$location', '$rootScope' ,function($http, $q, $location, $rootScope){
return {
getData: function(url, headers, bOnErrorRedirect, bShowInPageError, params){
var headerParam = {'Accept':'application/json'};
if(headers !== undefined || headers !== null){
headerParam = $.extend(headerParam, headers);
}
var updatedParams = {'TimeStamp':new Date().getTime()};
updatedParams = $.extend(params, updatedParams);
var deferred = $q.defer();
$http.get(url,{
headers: headerParam,
params : updatedParams
}).success(function(successResponse){
if(successResponse){
var responseJSON = angular.fromJson(successResponse);
if(responseJSON && responseJSON.messages && responseJSON.messages.length){
//Process Error
}else{
deferred.resolve(successResponse);
}
}else{
deferred.resolve(successResponse);
}
}).error(function(errorResponse , status){
//Process Error
console.error("status here:: "+status);
});
return deferred.promise;
}
}
}]);
And I am calling this method in controller with all required dependencies as below:
HttpServiceFactory.getData(args.sURL,null,false,true,args.oQueryParams).then(function(response){
scope.bDataLoading = false;
// process data
})
.catch(function(oResponse) {
scope.bDataLoading = false;
scope.bDisplayError = true;
// process error
});
Here everything works fine. But the issue is when I've multiple http calls on a page, the UI freezes and does not allow to interact till the request has been processed.
For example, on a page I am displaying 2 angular-ui-grid based on user's selected criteria by input box and calendar control. In such case, the UI freezes until both grids have been displayed or error message has been displayed.
During http service call, user can not do anything but simply wait to finish the request.
How do I resolve the issue of UI freezing ? Is it a true async behavior ? If not, what am I missing to achieve correct async behavior ?

$resource delete function not working as expected?

I have built a simple application in Angular consuming a simple API I created myself using Laravel. The application is hosted here. The API is hosted here. Now I can log in to the application at which point the API returns a simple auth_token which is sent as the URL parameter in every subsequent request that is sent to the server.
There is only one user in the system:
Email: admin#admin.com
Password: admin12345
You can log into the application using these credentials at which point the application will set a cookie using the $cookieStore service and will use the token in this cookie for every subsequent request. After using the application, a user can log out from the application, where a DELETE request is sent to the server and on the success method, the cookie is deleted from the browser.
Unfortunately there is some issue with the code I suppose. The DELETE request is working as expected and it deletes the auth_token on the server and returns 200 OK. But the success method is not called. I am not sure what I am doing wrong. It might be just a syntax problem.
app.js
function AppCtrl ($scope, $cookieStore, $location, Auth) {
$scope.setActive = function (type) {
$scope.destinationsActive = '';
$scope.flightsActive = '';
$scope.reservationsActive = '';
$scope[type + 'Active'] = 'active';
};
$scope.authenticate = function (credentials) {
Auth.save(credentials, function(data){
$cookieStore.put('auth_token', data.auth_token);
$scope.isLoggedIn = true;
$location.path('destinations');
$scope.message = null;
}, function(data){
$scope.message = "Email/Password combination incorrect!";
});
};
$scope.logout = function () {
//var auth_token = $cookieStore.get('auth_token');
Auth.delete({
'auth_token': $cookieStore.get('auth_token')
}, function(data){
$scope.isLoggedIn = false;
$cookieStore.remove('auth_token');
});
};
if($cookieStore.get('auth_token')){
$scope.isLoggedIn = true;
}else{
$scope.isLoggedIn = false;
}
}
The logout function is called when the log out button is pressed. What am I doing wrong here?
Note: The application is not working on Chrome for some reason (Use Firefox). If you can shed some light on that, it would be very helpful.
Both the repositories are public if you wish to have a look:
AngulAir Application: http://gitlab.learningtechasia.com:8901/rohan0793/angulair.git
AngulAirAPI: http://gitlab.learningtechasia.com:8901/rohan0793/angulairapi.git
Here is your solution
$scope.logout = function () {
//var auth_token = $cookieStore.get('auth_token');
Auth.delete(
{'auth_token': $cookieStore.get('auth_token')}, // parameters
{},//postData, which you don't need for this
function(data){
$scope.isLoggedIn = false;
$cookieStore.remove('auth_token');
},
// error callback
function (httpResponse) {
// do what you want for error handling here
}
);
};
Note:-> (Below points solved the problem)
Only the 2nd option(postdata) in $resource.delete API was missing. We should give it as a blank {} if it is not required for API.
And delete method should return 204 Status Code in order to execute success callback.

Categories