here is my signalr piece on backend
public class ChatHub : Hub
{
public void AddMessage(string userName, string message)
{
Clients.All.receivedNewMessage(userName, message);
}
}
and on frontend
app.controller('chatController', ['$scope', function ($scope) {
var _message = function(id, message, username, date)
{
// this.id = id;
this.message = message;
this.username = username;
// this.date = date;
}
$scope.username = "test";
$scope.message = "";
$scope.messages = [];
//auto proxy start
$.connection.hub.url = "http://localhost:*****/signalr/";
var myChatHub = $.connection.chatHub;
$.connection.hub.logging = true;
myChatHub.client.receivedNewMessage = function (username, message) {
var newMessage = new _message( name, message);
$scope.messages.push(_message);
$scope.$apply();
};
$.connection.hub.start().done(function () {
$scope.addMessage = function () {
myChatHub.server.addMessage($scope.username, $scope.message);
};
});
}]);
and libs
<script src="scripts/jquery-3.1.0.js"></script>
<script src="scripts/jquery.signalR-2.2.1.min.js"></script>
<script src="http://localhost:*****/signalr/hubs"></script>
I used web tools on chrome, everything looked fine to me. I debugged the js and on jquery.signalR-2.2.1.min.js it showed me:
SignalR: Connection must be started before data can be sent. Call
.start() before .send()
and I don't know how to fix it
Change:
$.connection.hub.start().done(function () {
$scope.addMessage = function () {
myChatHub.server.addMessage($scope.username, $scope.message);
};
});
To:
$scope.addMessage = function () {
myChatHub.server.addMessage($scope.username, $scope.message);
};
$.connection.hub.start().done(function () {
$scope.addMessage($scope.username, $scope.message);
});
The function declaration should NOT exist within the start().done context.
Related
public class Home
{
string CustEmail { get;set;}
string CustName { get; set;}
int id { get; set;}
}
Model
[HttpPost]
public void CreateCustomer(Home cust)
{
if (ModelState.IsValid)
{
}
}
Controller
angular.module('myFormApp', []).controller('CustomerController', function ($scope, $http, $location, $window) {
debugger;
$scope.cust = {};
$scope.message = '';
$scope.result = "color-default";
$scope.isViewLoading = false;
//get called when user submits the form
$scope.submitForm = function () {
$scope.isViewLoading = true;
console.log('Form is submitted with:', $scope.cust);
//$http service that send or receive data from the remote server
var cust = {
CustEmail: $scope.cust.CustEmail,
CustName: $scope.cust.CustName,
id: 1,
};
$http(
{
method: 'POST',
url: '/Home/CreateCustomer',
data: cust,
}).then(function (data, status, headers, config) {
$scope.errors = [];
if (data.success === true) {
$scope.cust = {};
$scope.message = 'Form data Submitted!';
$scope.result = "color-green";
$location.path(data.redirectUrl);
$window.location.reload();
}
else {
$scope.errors = data.errors;
}
})
$scope.isViewLoading = false;
}
}).config(function ($locationProvider) {
//default = 'false'
$locationProvider.html5Mode(true);
});
I get the data in the proper format in front-end and the post-back call is also working but I cannot get value in MVC controller. I don't know what am I doing wrong. I have tried using the individual item in controller then it's working fine but i want it through model only.
The .then method of a promise only exposes one value, not four values.
$http(
{
method: 'POST',
url: '/Home/CreateCustomer',
data: cust,
̶}̶)̶.̶t̶h̶e̶n̶(̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶d̶a̶t̶a̶,̶ ̶s̶t̶a̶t̶u̶s̶,̶ ̶h̶e̶a̶d̶e̶r̶s̶,̶ ̶c̶o̶n̶f̶i̶g̶)̶ ̶{̶
}).then(function (response) {
var data = response.data;
var status = response.status;
var headers = response.headers;
var config = response.config;
$scope.errors = [];
if (data.success === true) {
$scope.cust = {};
$scope.message = 'Form data Submitted!';
$scope.result = "color-green";
$location.path(data.redirectUrl);
$window.location.reload();
}
else {
$scope.errors = data.errors;
}
})
For more information, see
AngularJS $http Service API Reference - returns
UPDATE
You can add a .catch block to console log any errors:
$http(
{
method: 'POST',
url: '/Home/CreateCustomer',
data: cust,
̶}̶)̶.̶t̶h̶e̶n̶(̶f̶u̶n̶c̶t̶i̶o̶n̶ ̶(̶d̶a̶t̶a̶,̶ ̶s̶t̶a̶t̶u̶s̶,̶ ̶h̶e̶a̶d̶e̶r̶s̶,̶ ̶c̶o̶n̶f̶i̶g̶)̶ ̶{̶
}).then(function (response) {
var data = response.data;
var status = response.status;
var headers = response.headers;
var config = response.config;
$scope.errors = [];
if (data.success === true) {
$scope.cust = {};
$scope.message = 'Form data Submitted!';
$scope.result = "color-green";
$location.path(data.redirectUrl);
$window.location.reload();
}
else {
$scope.errors = data.errors;
}
console.log("OK:", response.data);
}).catch(function(response) {
console.log("ERROR:", response);
});
i am trying to display server side errors on login form.
i am trying to change state when data is avaliable.
but its not working. can anybody help
or is there any better way to do it.
Future<dynamic> apiRequest(map) async {
String url = 'https://localhost/api/login';
var response = await http.post(Uri.encodeFull(url),
body: map, headers: {"Accept": "application/json"});
var res = json.decode(response.body);
return res;
}
void _submit() async {
if (this._formKey.currentState.validate()) {
_formKey.currentState.save(); // Save our form now.
var map = {
'email_id': '',
'password': '',
};
var hello = await apiRequest(map);
setState(() {
email_id_error = hello["errors"]["email_id"];
});
} else {
setState(() {
_autovalidate = true;
});
}
}
new Text(email_id_error),
response from server
{status_code: 4003, errors: {password: [can't be blank], email_id: [can't be blank]}}
you can try this
void _submit() async {
if (this._formKey.currentState.validate()) {
_formKey.currentState.save(); // Save our form now.
var map = {
'email_id': '',
'password': '',
};
var hello = await apiRequest(map);
if(hello.statusCode ==4003){
setState(() {
email_id_error = hello.responseBody["errors"]["email_id"];
});
}
} else {
setState(() {
_autovalidate = true;
});
}
}
I have a SignalR hub proxy in angularjs factory like this.
var app = angular.module('app');
app.factory("signalRHubProxy", ['$rootScope', "$timeout", function ($rootScope, $timeout) {
function signalRHubProxyFactory(serverUrl, hubName) {
var connection = $.hubConnection(serverUrl);
var proxy = connection.createHubProxy(hubName);
connection.disconnected(function () {
$timeout(function () {
connection.start();
}, 5000)
});
return {
on: function (eventName, callback) {
proxy.on(eventName, function (result) {
$rootScope.$apply(function () {
if (callback) {
callback(result);
}
});
});
connection.start();
},
stop: function () {
connection.stop();
},
connection: connection
};
}
return signalRHubProxyFactory;
}]);
I used connection timeout because sometimes server does not listen, so I can retry.
I am using this factory in my controller:
app.controller("directiveController", function($scope, signalRHubProxy){
var signalRProxy = signalRHubProxy(
"url",
"hubname");
signalRHubProxy.on("datapush", function(data){
});
$scope.$destroy(function(){
signalRHubProxy.stop();
??? how to kill signalr hub
})
})
But when I remove my directive, signalR still works.
I believe when you call stop(), it calls disconnected event, which will just start the connection again. You might need to check if the disconnection was intentional (with a simple boolean variable), then just avoid restarting the connection:
app.factory("signalRHubProxy", ['$rootScope', "$timeout", function ($rootScope, $timeout) {
function signalRHubProxyFactory(serverUrl, hubName) {
var connection = $.hubConnection(serverUrl);
var proxy = connection.createHubProxy(hubName);
var manualStop = false;
connection.connected(function () {
manualStop = false; // reset variable if connected
});
connection.disconnected(function () {
if (manualStop)
return;
$timeout(function () {
connection.start();
}, 5000)
});
return {
on: function (eventName, callback) {
proxy.on(eventName, function (result) {
$rootScope.$apply(function () {
if (callback) {
callback(result);
}
});
});
connection.start();
},
stop: function () {
manualStop = true;
connection.stop();
},
connection: connection
};
}
return signalRHubProxyFactory;
}]);
Also, make sure $scope.$destroy is being called.
Some people recommend calling $.connection.hub.stop(); instead of connection.stop();, although I don't really know whether it has some significant difference.
I have angular service where i got methods which are called from server when user connect or disconnect from my app
(function () {
//'use strict';
app.service('PrivateChatService', ['$rootScope', '$location', function PrivateChatService($rootScope, $location){
var online_users = [];
var proxy = $.connection.chatHub;
return {
addOnlineUser:
proxy.client.newOnlineUser = function (user) {
var newUser = ({
connectionId: user.ConnectionId,
UserName: user.UserName
});
online_users.push(newUser);
$.connection.hub.start()
},
removeOfflineUser: proxy.client.onUserDisconnected = function (id, user) {
var index = 0;
//find out index of user
angular.forEach(online_users, function (value, key) {
if (value.connectionId == id) {
index = key;
}
})
online_users.splice(index, 1);
$.connection.hub.start()
},
}
}])})();
Here i got controller method which i want to be fired when server calls newOnlineUser
PrivateChatService.newOnlineUser(function (user) {
$scope.online_users.push(newUser);
console.log("newOnlineUser finished");
});
So my question is. Is it possible to make with generated proxy or i have to use non-generated proxy access to those methods with which i am not very familiar.
With generated proxy as i show above it never reach my controller method to update my data in controller scope
Since nobody responded, what i find somehow odd. I found out this is working. I am not sure if this is good aproach since nobody answered and i didnt find any information how should this be solved.
app.service('PrivateChatService', ['$rootScope', '$location', function PrivateChatService($rootScope, $location){
var online_users = [];
var connection = $.hubConnection();
var proxy = connection.createHubProxy('chatHub');
function signalrCall(eventName, callback) {
proxy.on(eventName, function (user) {
var args = arguments;
$rootScope.$apply(function () {
callback.apply(proxy, args)
})
});
connection.start();
}
return {
addOnlineUser: function (eventName, callback) {
signalrCall(eventName, callback);
},
getActiveUsers: function (eventName, callback) {
signalrCall(eventName, callback);
},
removeOfflineUser: function (eventName, callback) {
signalrCall(eventName, callback);
}
}
}])
angular controller methods
PrivateChatService.addOnlineUser("newOnlineUser", function (user) {
var newUser = ({
connectionId: user.ConnectionId,
UserName: user.UserName
});
$scope.online_users.push(newUser);
console.log("newOnlineUser finished");
});
PrivateChatService.getActiveUsers("getOnlineUsers", function (onlineUsers) {
angular.forEach($scope.online_users, function (scopeValue, scopeKey) {
//loop through received list of online users from server
angular.forEach(onlineUsers, function (serverListValue, serverListKey) {
if (!(serverListValue.ConnectionId == scopeValue.connectionId)) {
var newUser = ({
connectionId: serverListValue.ConnectionId,
UserName: serverListValue.UserName
});
$scope.online_users.push(newUser);
}
})
})
console.log("getOnlineUsers finished");
});
PrivateChatService.removeOfflineUser("onUserDisconnected", function (user) {
var index = 0;
//find out index of user
angular.forEach($scope.online_users, function (value, key) {
if (value.connectionId == user) {
index = key;
}
})
$scope.online_users.splice(index, 1);
});
I try to implement a logIn in Meteor 0.9.2.1 with LDAPJS and Meteor methods. The code for the server-side is:
var Future = Meteor.npmRequire('fibers/future');
var ldap = Meteor.npmRequire('ldapjs');
LDAP = {};
LDAP.ldap = ldap;
LDAP.serverIP = 'xxx';
LDAP.serverPort = 'xxx';
LDAP.searchOu = 'ou=xxx,dc=xxx,dc=xxx';
LDAP.searchQuery = function(user) {
return{
filter: '(uid=username)',
scope: 'sub'
}
};
LDAP.checkAccount = function (options) {
LDAP.client = ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
options = options || {};
var dn = [];
future = new Future;
if (options.hasOwnProperty('username') && options.hasOwnProperty('password')) {
LDAP.client.search(LDAP.searchOu, LDAP.searchQuery(options.username), function (err, search) {
search.on('searchEntry', function(entry){
//console.log('entry: ' + JSON.stringify(entry.object));
dn.push(entry.object.uid);
dn.push(entry.object.userPassword)
});
search.on('error', function (err) {
throw new Meteor.Error(500, "LDAP server error");
});
search.on('end', function () {
if (dn.length === 0) {
future['return'](false);
return false;
}
var testBind = LDAP.ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
testBind.bind(dn[10], options.password, function (err) {
future['return'](!err);
});
client.unbind(function (err) {
assert.ifError(err);
future['return'](!err);
});
});
});
} else {
throw new Meteor.Error(400, "Missing Parameter");
}
};
var loginHandler = function (username, password) {
Accounts.registerLoginHandler("ldapjs",function(loginRequest) {
if (LDAP.checkAccount(loginRequest)) {
var user = Meteor.users.findOne({ username: loginRequest.username });
if(err){
console.log(err)
}
return {
userId: uid
}
}
});
};
Meteor.methods({
setSignIn: function(username, password) {
loginHandler(username,password)
}
});
My Problem is, that when I want to log in it starts with the loginHandler. But than the console throws back that Object has no method checkAccount. I changed today a lot and I'm already totally confused.
You need to instantiate the empty object as var LDAP = {}. Rest will be solved magically :)
I finally got to work it. Referneces:
http://notjoshmiller.com/using-ldaps-in-meteor/, https://github.com/emgee3/meteor-accounts-ldap
server-side:
var Future = Meteor.npmRequire('fibers/future');
var ldap = Meteor.npmRequire('ldapjs');
var LDAP = {};
LDAP.ldap = ldap;
//provides the variables, needed for the connection
LDAP.serverIP = 'xxx';
LDAP.serverPort = 'xxx';
LDAP.searchOu = 'ou=xxx,dc=xxx,dc=xxx';
//is needed for the searchQuery, which delivers the Filter so that only the uid with
//the given username get searched
LDAP.searchQuery = function(username) {
return{
filter: '(uid=' + username + ')',
scope: 'sub'
}
};
LDAP.checkAccount = function (options) {
//connects the client, nginx is here not necessary
LDAP.client = ldap.createClient({
url: 'ldap://' + LDAP.serverIP + ':' + LDAP.serverPort
});
options = options || {};
var dn = [];
future = new Future;
if (options.hasOwnProperty('username') && options.hasOwnProperty('password')) {
//create the connection
LDAP.client.search(LDAP.searchOu, LDAP.searchQuery(options.username), function (err, search) {
if(err){
console.log(err)
}
//uses the class searchEntry, which is node-specific
search.on('searchEntry', function (entry) {
dn.push(entry.objectName);
LDAP.displayName = entry.object.displayName
});
search.on('error', function (err) {
throw new Meteor.Error(500, "LDAP server error");
});
//uses the end class to 'fulfill' the connection by binding
search.on('end', function () {
if (dn.length === 0) {
future['return'](false);
return false;
}
LDAP.client.bind(dn[0], options.password, function (err) {
future['return'](!err);
});
});
});
return future.wait();
} else {
throw new Meteor.Error(400, "Missing Parameter");
}
};
Meteor.startup(function(){
Accounts.registerLoginHandler("ldapjs", function (loginRequest) {
if (LDAP.checkAccount(loginRequest)) {
var userId;
var user = Meteor.users.findOne({
username : loginRequest.username
//'profile.name': LDAP.displayName
});
if (user) {
userId = user._id;
} else {
// If no Meteor Account is found for a valid LDAP logon,
// you can either prevent logon by passing 'undefined' or
// you can automatically create the new account.
// return undefined;
userId = Meteor.users.insert({ username : loginRequest.username });
}
return {
userId: userId
}
}
return undefined;
});
});
client side:
Meteor.ldapLogin = function (username, password, callback) {
var loginRequest = {
username: username,
password: password
};
Accounts.callLoginMethod({
methodArguments: [loginRequest],
userCallback: function (err) {
if (err) {
console.log(err);
Session.set('alert', 'No valid inputs!');
} else {
Router.go('/Home');
}
}
});
};
//handles LogIn-Button, by using LDAPJS
Template.signIn.events({
"submit #box-login": function (e, t) {
e.preventDefault();
var signInForm = $(e.currentTarget),
username = trimInput(signInForm.find('#emailSignIn').val().toLowerCase()),
password = signInForm.find('#passwordSignIn').val();
if(isNotEmpty(username)&& isNotEmpty(password)) {
Meteor.ldapLogin(username, password, function (err) {
if (err) {
console.log(err)
Session.set('alert', 'Sorry, something went wrong.');
}
});
} else {
Session.set('alert','Please insert your username and password!')
}
return false;
}
});
PS: No Meteor.methods and Meteor.call is needed! It might change with every new Meteor version and package, but I guess u're aware of that ;)