I've been playing around with SignalR for a few days and I have to say that it's an absolutely phenomenal library. I've managed to get a few things working with it and was astounded at the simplicity, but I recently ran into a small problem.
I'm unable to call a Hub method from JavaScript in the browser. The request returns a 500 error code, and when I look at the error page source, I see this:
[ArgumentNullException: Value cannot be null.
Parameter name: s]
System.IO.StringReader..ctor(String s) +10207225
Newtonsoft.Json.Linq.JObject.Parse(String json) +74
SignalR.Hubs.HubRequestParser.Parse(String data) +78
SignalR.Hubs.HubDispatcher.OnReceivedAsync(IRequest request, String connectionId, String data) +266
SignalR.<>c__DisplayClass6.<ProcessRequestAsync>b__4(String data) +84
SignalR.Transports.ForeverTransport.ProcessSendRequest() +159
SignalR.Transports.ForeverTransport.ProcessRequestCore(ITransportConnection connection) +149
SignalR.Transports.ForeverTransport.ProcessRequest(ITransportConnection connection) +42
SignalR.PersistentConnection.ProcessRequestAsync(HostContext context) +1087
SignalR.Hubs.HubDispatcher.ProcessRequestAsync(HostContext context) +251
SignalR.Hosting.AspNet.AspNetHandler.ProcessRequestAsync(HttpContextBase context) +656
SignalR.Hosting.AspNet.HttpTaskAsyncHandler.System.Web.IHttpAsyncHandler.BeginProcessReques t(HttpContext context, AsyncCallback cb, Object extraData) +143
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9479007
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +178
My server-side code is:
public class SourceHub : Hub
{
public void RegisterSource(string source)
{
Groups.Add(Context.ConnectionId, source);
}
}
and on the client-side I have:
var SourceHub = $.connection.sourceHub;
$.connection.hub.start().done(function () {
SourceHub.registerSource("test");
});
I've been digging for a while, but I just can't find the source of the problem... could someone please help me out?
Preface: I'm on edobry's team for this project, and I'm the backend guy, so this foray into frontend was new and fascinating to me.
So, after some careful dissection of the code as I stepped through the project, it turns out that the POST data in the request variable was coming up empty. The data was getting sent properly up to the $.ajax call, but never arriving at the server. Some more hunting and I had uncovered something suspicious that edobry and I were then able to discern what was happening.
We're using Ajax for other parts of the page, and the ajax method is called several times, so we had factored out some settings we set on every method call into $.ajaxSetup. One of these was dataType getting set to "text", and contentType to "application/json". It seems that signalR is not overriding global ajax settings properly. I'm not sure if this is a bug or intended behavior, but it should be documented better if that's the case (and if it is, feel free to call us dumb. :))
Your method is called RegisterSource and you call registerSources instead of registerSource in javascript.
Related
I have a AngularJS webapplication with a Jersey Backend Application.
Now everything is working fine using ngResource to access REST resource out of AngularJS. The only problem is with the DELETE option.
I have the following code to delete a course using my ngResource:
Course.deleteCourse = function(course) {
course.$remove({
courseId:course.id
});
return course;
};
In the backend (Jersey) I have the following code:
#DELETE
#Path("{id}")
public final void remove(#PathParam("id") final String id) {
System.out.println("DELETE ID = " + id);
}
If I try to delete an item the following url is called from Angular:
DELETE http://localhost:8080/manager-api/courses/5
This is fine (after me). If I call this url from CURL, i get the ssystem.out from the Backend posted to the console.
In the client-app (AngularJS) i get the following exception on the browser console:
DELETE http://localhost:8080/manager-api/courses/5 415 (Unsupported Media Type)
Anyone an idea what the problem might be? POST + GET are working fine.
I have the following consume/produce annotations:
#Consumes({ MediaType.APPLICATION_JSON })
#Produces({ MediaType.APPLICATION_JSON })
Thanks in advance for your help.
Greets
Marc
EDIT:
I have tried to replace the way of accessing the REST services out of AngularJS with $http.
Now my service looks as below:
MyApp.factory("Course", ["$http", function ($http) {
var courseBaseUrl = "/api/courses/";
return {
show: function show(courseId) {
return $http.get(courseBaseUrl + courseId);
},
list: function list() {
return $http.get(courseBaseUrl, {});
},
remove: function remove(courseId) {
return $http.delete(courseBaseUrl + courseId, {});
},
save: function save(course) {
return $http.post(courseBaseUrl, course, {});
}
};
}]);
The result is still the same. The application calls e.g
DELETE http://localhost:8080/manager-api/courses/1
and receives a
DELETE http://localhost:8080/manager-api/courses/1 415 (Unsupported Media Type)
If I call the same DELETE call on Curl, everything works fine.
Thanks for your help
Marc
I came across this as well, the problem is angular always sets the Content-Type header to xml on DELETE requests and jersey will chuck an error as you have specified that your api consumes/produces JSON with the annotations.
So to fix it (from the client side), set the content-type header, eg:
.config(function($httpProvider) {
/**
* make delete type json
*/
$httpProvider.defaults.headers["delete"] = {
'Content-Type': 'application/json;charset=utf-8'
};
})
However, for reasons I dont understand/dont know of, angular will strip away the content-type header from the request if it has no data. This would make sense if it wasn't for the fact that browsers (chrome at least) will always send a content-type... Anyway you will have to go to the trouble of finding this in the angular source:
// strip content-type if data is undefined
if (isUndefined(config.data)) {
delete reqHeaders['Content-Type'];
}
and get rid of it. I dont know of a way to do this without editing the source. Maybe someone with better JS know-how, erm, knows how.
Alternatively, from the server side, you can do as Rob has suggested and change the Jersey configuration to allow consuming MediaType.APPLICATION_XML
#Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public final void remove(#PathParam("id") final String id) {
System.out.println("DELETE ID = " + id);
}
I had same issue, Try returning new instance of Course object in your delete method.
#DELETE
#Path("{id}")
public final Course remove(#PathParam("id") final String id) {
System.out.println("DELETE ID = " + id);
return new Course();
}
Using angularjs $resource (instead of $http), without "payload" in the request, the content-type is setted as text/plain.
So IMHO it's better a server side support.
"Postel's Law states that you should be liberal in what you accept and conservative in what you send. -- source"
#DELETE
#Path("{id}")
#Consumes({ MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN })
public void remove(#PathParam("id") Long id) { ...
The Program I'm writing and the functionality I'm trying to achieve
Okay. So what I'm writing at the moment is a very simple forum, in Javascript using AJAX. Part of my task is to add a new post, using an API that my lecturer wrote for us in PHP. Just to note, the API and the SQL database are completely local.
The function I am using to add this post is:
function addPosts()
{
// Add the new thread to the SQLlite database.
var treq = new Request({
url:'guestbook/control.php?action=insertPost',
'method':'post',
onSuccess: function() {
alert('win');
},
onFailure: function() {
alert('fail');
}
}).send(Object.toQueryString({
// Had to convert it to a query string because it wouldn't work as a normal object.
// These are the required values to send, to store a "post" in the database.
'name':'This is a name',
'comment':'This is a comment!'
}));
}
I am aware this will add the same data every single time. I'm just trying to get the damn thing working!
The problem
What is happening is, when this function is called, I am getting an SQL syntax error. I was confused, because that would imply that my lecturer's code is wrong. After speaking with my lecturer, he explained that this happens when the post data isn't sent correctly to the PHP code. So I went about using Google Chrome's developer tools to see what was going on, and this is what I discovered:
Now to me, this means that the data is successfully being loaded into the request, and is being passed to the PHP files fine. Obviously I'm wrong. I've been racking my brains trying to make this work.
I know that the API works fine, because everyone else in my class isn't having any problem with it, and the code I am using is practically a rip off of the code in the notes, so I'm about 90% sure that's correct to.
One thing to note is that the code in the onSuccess key runs, so I know it's not a problem on the AJAX side.
Another thing is that this code worked in University on those computers, and it's since I've got it home that it's decided not to work.
Stack Trace
Fatal error: Uncaught exception 'PDOException' with message
'SQLSTATE[HY000]: General error: 1 near ")": syntax error' in G:\Ajax
Coursework\guestbook\php\database.php:134Stack trace:#0 G:\Ajax
Coursework\guestbook\php\database.php(134): PDO->prepare('INSERT INTO
pos...')#1 G:\Ajax Coursework\guestbook\php\class.GuestBook.php(44):
DatabaseHandler->insert(Array)#2 G:\Ajax
Coursework\guestbook\control.php(8): GuestBook->insert(Array)#3
G:\Ajax Coursework\guestbook\control.php(56): insertPost()#4 {main}
thrown in G:\Ajax Coursework\guestbook\php\database.php on line 134
Object.toQueryString is used in convert an object to a query string. So if the server is requiring both $_POST['name'] and $_POST['comment'] to be set, it wont be.
Frankly because you are posting it, I dont think $_GET['name'] or $_GET['comment'] would be set either.
Request.send expects an opject. You are sending it a string. So it should be
Request.send({prop: 'value'}), not Request.send(value).
Do yourself a favor and make a PHP with the following php code, and see what it returns. It may clear this up for you right away. I have a feeling nothing is being sent except for $_GET['action']
<?php
echo '<pre>';
print_r($_GET);
print_r($_POST);
echo '</pre>';
?>
Just in-case anyone stumbles upon this thread looking for an answer:
function addPosts()
{
// Add the new thread to the SQLlite database.
var treq = new Request({
url:'guestbook/control.php?action=insertPost',
onSuccess: function() {
alert('win');
},
onFailure: function() {
alert('fail');
}
}).post('name=This is a name&comment=This is a comment!');
}
Here I'm using the .post method to POST data.
I have written a java script function in the skin file of the visual web Gui application which returns some value too. Now i am invoking the java script method from code behind.
public void XYZ( string message)
{
this.InvokeMethodWithId("testCall", message);
}
And javascript function is:--
function testCall(strGuid, txt) {
alert("hai Java script fired..");
return txt+ 'returned from JavaScript';
}
I want the value returned from JavaScript in the application. how can i achieve it. Is there in other method to invoke the methods of JavaScript?
I want something like this:--
public void Conect( string message)
{
string returnedvalue = this.InvokeMethodWithId("testCall", message);
}
Javascript is executed on the client so the return won't make it to the server.
A solution could be to use AJAX to send that value to the server. Stack Overflow is full of answers about AJAX.
Here's a good example.
#Amish Kumar,
As noted by other replies already, the client-side and server-side are not directly connected in web programming. The client is always the initiator of every request, and the server-side's "purpose" is to render a response, which will then be returned to the client for processing, in Visual WebGui this is usually some UI update processing. This basically means that your client script will not execute until the server-side has finished rendering the response, and the only way the client can get some message back to the server is to issue another request.
Think about how you need to use the MessageBox in Visual WebGui for instance. In order to receive the "response" from the MessageBox, you need to supply a callback handler in your server-side code, and then your server-side code will have completed creating the response, which is returned to the client. The client updates its UI and on some action to the MessageBox dialog, it sends a new request to the server, which interpretes the action and invokes your callback handler. In the callback handler you use Form.DialogResult to get the user action.
A very basic way to make this work in custom Visual WebGui code could be like the following code on a Form:
private void button1_Click(object sender, EventArgs e)
{
SendClientMessage("This is a test");
}
public void SendClientMessage(string strMessage)
{
System.Text.StringBuilder sb = new StringBuilder();
sb.AppendLine("var objEvent = mobjApp.Events_CreateEvent('{0}', 'MessageEvent');");
sb.AppendLine("mobjApp.Events_SetEventAttribute(objEvent, 'Msg', '{1}');");
sb.AppendLine("mobjApp.Events_RaiseEvents();");
this.InvokeScript(string.Format(sb.ToString(), this.ID, strMessage));
}
protected override void FireEvent(Gizmox.WebGUI.Common.Interfaces.IEvent objEvent)
{
if (objEvent.Type == "MessageEvent")
MessageBox.Show(objEvent["Msg"]);
else
base.FireEvent(objEvent);
}
This code will not work unless you set your Visual WebGui applicaton for no Obscuring. In order for this code to work on an obscured application, you would need to add the JavaScript as an obscured JavaScript resource and it would work fine.
Palli
enter code here
I have a project that uses PageMethods to call functions on the server.
The server functions (written in C#) return the values as array of strings, without doing any kind of serialization and in the client side (from Js) the accessing of the return values is by using static variable called arguments.
I found that sometimes for some users (cases are not repro) sometimes an exception occured
"WebServiceFailedException the server method 'Foo' returned invalid data.
the 'd' property is missing from JSON."
Some searching on google I found that people are serializing the return values using DataContractJsonSerializer class and in js accessing the return value using one of the callback function
Example:
function OnRequestComplete(result,
userContext, methodName) {
var Person = eval('(' + result + ')');
alert(Person.Forename);
alert(Person.Surname); }
So is the first technique is correct? or what?
P.S:
the function on the server is defined on the default.aspx.cs file as follows:
[System.Web.Services.WebMethodAttribute(), System.Web.Script.Services.ScriptMethodAttribute()]
public static string[] Foo(string s);
from the client side the calling is as follows
PageMethods.Foo("value",OnSuccess);
Also all the users have the same browser version (IE8)
I don't know if it's the entire problem, but your first issue is manually serializing the return value. PageMethods and ScriptServices automatically JSON serialize their return values. Nesting two levels of JSON could definitely be throwing a wrench in the framework's client-side deserialization process (which is also happening automatically, before your eval() code).
To return an instance of your Person class, this is all you need:
public static Person GetPerson() {
Person p = new Person();
// Populate the Person object here.
return p;
}
Then, on the client-side you can work with the object's properties as expected:
function OnRequestComplete(result, userContext, methodName) {
console.log('Person name: ' + result.Forename + ' ' + result.Surname);
}
Alternatively, if you're using jQuery for other tasks and already have it on the page, you don't even need the ScriptManager and MS AJAX to call page methods. You can directly call page methods with jQuery and skip all that overhead.
Without knowing how the request is made and how the server end is coded, my answer may not be accurate.
Where is the WebMethod decorated method in your server side code? If it is an a separate class with the ScriptService attribute, and if JSON is specified while making the request, then the JSON values should have been automatically serialized and dont need to be serialized manually again. With this set up ASP.NET 3.5 wraps the response in a "d" object
Some users getting the exception might be due to the browser that they are using. If you are using jQuery, I'd specify the content type as so in the ajax request body
contentType: "application/json; charset=utf-8",
Hakeem
This is a bit funky. ASP.NET always adds the "d" to all results. So it either should work or not. Here is some background on the "d" issue:
http://encosia.com/2009/06/29/never-worry-about-asp-net-ajaxs-d-again/
My question is if there is a way to simply post process wicket HTML response?
What I want to do is to apply some DOM transformations to the generated HTML using Rhino (http://www.mozilla.org/rhino/) and jQuery.
Anyone ever thought about it? Any suggestions where to start?
Best,
Maciej Wrzalik
OK, I've got this:
public class MyRequestCycle extends WebRequestCycle {
public MyRequestCycle(WebApplication application, WebRequest request, WebResponse response) {
super(application, request, response);
}
#Override
protected void onEndRequest() {
String responseString = response.toString();
//String newResponseString = process(responseString);
//replace old response content with the newResponseString
super.onEndRequest();
}
}
In method onEndRequest the string responseString contains HTML code that I'm going to alter some way using Rhino, Envjs and jQuery but the question is how can I replace the old response content with the new one?
Envjs emulates the browser environment under Rhino, and specifically allows you to do DOM manipulation server-side using jQuery. I have used it before in my projects, and have had good success. Relevant resources:
http://www.envjs.com/
http://ejohn.org/blog/bringing-the-browser-to-the-server/
If you want the post-processing done on the server, your best bet is likely to implement a Servlet Filter which modifies the response before it goes to the client.
As you're working on the rendered HTML, this has nothing particular to do with Wicket, and could be applied to html generated by any Java framework.
As suggested, a normal Java EE filter would work fine, if there's nothing Wicket-specific that you need for the processing.
But if you want to do it inside Wicket, for some reason or other, I suppose you could create your own RequestCycle implementation (MyRequestCycle extends WebRequestCycle) and do the processing there (perhaps by overriding onEndRequest and/or getWebResponse).
To use a custom RequestCycle, override newRequestCycle in your Application class:
#Override
public RequestCycle newRequestCycle(Request request, Response response) {
return new MyRequestCycle(this, (WebRequest) request, response);
}
I'm using custom a RequestCycle for a couple of things (e.g. this) myself—it's simple and straightforward—but I'm not 100% sure if it fits your needs here. (My Wicket experience is still somewhat limited.)