I am using signal R 1.0 with c#
the issue is most of the time with IE(v 10) and sometimes with chrome(v 28).
My client methods are not being executed.
I have chat functionality and on page load in
$(document).ready(function(){
//here i call server method to create group between two users
});
chat.client.groupcreated = function(){} //this is not invoked
on server side i write Client.groupcreated()
It is working perfact in FF. More interesting thing is if i put a break point in my cs code at server side it works perfact in IE also
Oppss...... I was doing a silly mistake
In the server method to create group i was doing something like below
Groups.Add(connectionid1,groupname);
Groups.Add(connectionid2,groupname);
Clients.Group(strGroupName).hellworld(); //no users added yet to the group while this line executes
The problem with above code is adding members to the signalr group is actually asynchronous, so sending messages to that group immediately won't work as the adding members to group may have not yet finished.
Solution
Groups.Add(connectionid1, groupname).ContinueWith(t =>
Groups.Add(connectionid2, groupname).ContinueWith(t2 =>
Clients.Group(groupname).helloworld());
wait for the task to complete before calling client method
By the way, thanks for posting your comments
Related
We have a cluster with 3 servers with Load Balancer in front (CloudFlare). Things worked well when we had 2 servers (A & B) in the cluster but after we added a 3-rd server (C) we noticed few odd things.
One of them is quite important and I do not understand how it happens at all.
Our web application makes AJAX requests to itself in order to get some JSON data back and if requests hit new server (C) response looks like that:
{
code: 404,
text: "Not Found",
message: "Database context not allowed."
}
Our application does not throw such error and so I searched in google a bit and noticed that it's mentioned on: OpenNTF XPagesExtensionLibrary
However, we do not use XPages at all so I wonder how could it be that our AJAX requests somehow involve that logic.
Any suggestion & tip would be appreciated.
UPDATE
The backend code of my agent is not important (it could be also an empty agent, I checked), because the request does not come to my agent.
The AJAX call is triggered by jQuery
let url = "domain.tld/api/key";
let params = {"a": 1};
$.post(url, params, function (data) {
// some code
},
"json"
).always(function() {
// some code
});
The URL, which I suspect is an issue starts with /api/key and I believe it's an issue (because all other ajax calls where endpoint do not start from /api/ work well).
Thanks.
Figured that our with help from comments (which you can see under my original post).
Apparently there is DAS servlet that handles all requests starting from /api/* and it runs if XPages engine is loaded.
In my case the 2 servers out of 3 have XPages shut down so the issue happened only on 1 server.
The solution would be:
Shut down XPages (or find a way to shut down DAS).
Alternatively change a URL from /api/path to something else (this is what we will do).
I'm always reluctant to claim that a bug that I'm seeing is actually a .Net Core bug, but after spending 8+ hours investigating the following bug, it looks like a .Net Core SignalR bug to me. I need techniques for tracking this down further and for fixing it.
The first rule of honing in on a bug is to try to create a minimal amount of code that can consistently repro the bug. While I can't reproduce it in a small stand along project, I have worked hard try to zero in on what's happening.
I have a controller with the following action method
[HttpPost]
[Route("/hack/ajax/start")]
public JsonResult AjaxStart([FromBody] JObject data) {
//A call to some method that does some work
return Json(new {
started = true
});
}
Calling this code via a jquery ajax call or Postman works flawlessly every time if I do not have any SignalR Core 1.0 hubs registered in the startup.cs method. However, when I register the following in the startup.cs file I have intermittent issues.
namespace App.Site.Home {
public class HackHub : Hub {
public async Task SendMessage(string status, string progress) {
await Clients.All.SendAsync("serverMsg", status, progress);
}
}
}
Startup.cs ConfigureServices contains
services.AddSignalR();
Startup.cs Configure contains
app.UseSignalR(routes => {
routes.MapHub<App.Site.Home.HackHub>("/hub/hack");
});
If I were to comment out the one line above routes.MapHub<App.Site.Home.HackHub>("/hub/hack"); everything works fine every time. However with this line present, (I.e. some SignalR hub registered) then that's when the fun starts for me, even if I have no code executing on the client or server that makes use of the hub!
The issue is that sometimes when a HTTP POST request is made for the action method above, something in .Net Core (SignalR??) is converting the POST method to Post, and then because Post is not a valid HTTP Method it converts it to a blank method. And since My action method requires an HTTP POST a 404 status code is returned. Many of the HTTP POSTS for that endpoint work fine, but often the issue I just described occurres.
To ensure that my client code was not part of the problem, I was able to reproduce my issue using Postman to make the requests. Further to ensure that POST was actually being sent and not Post, I used Fiddler to watch what was going over the wire. All this is documented below.
Here is the first request (which always works) done via Postman:
Here is the second (identical!) request done via Postman, this one resulted in a 404:
Here is what the first request (the one that worked properly) looked like in fiddler:
Here is what the second request looked like in fiddler:
As you can see, the requests are identical. But the response certainly is not.
So to get a better idea what the server was seeing, I added the following code to the beginning of the startup.cs Configure method. Due to it's placement, for the request this code gets to run before any other application code or middleware.
public void Configure(IApplicationBuilder app, IHostingEnvironment env) {
//for debugging
app.Use(async (context, next) => {
if(context.Request.Method == "") {
string method = context.Request.Method;
string path = context.Request.Path;
IHttpRequestFeature requestFeature = context.Features.Get<IHttpRequestFeature>();
string kestralHttpMethod = requestFeature.Method;
string stop = path;
}
await next();
});
//more code here...
}
For the first request, the request.Method was POST as one would expect:
But for the second request request.Method was blank!!
To investigate this further, I accessed the requestFeature and checked the Http Method Method there. This is where things get really interesting. If I just hover over the property in the debuggger, it's blank too.
But, If I expand the requestFeature object and look at the Method property there, is it Post!!!
That alone seems like craziness. How can two views of the SAME property in the debugger have different values???! It would seem that some code converted the POST to Post, and at some level the system knows that Post is not a valid http method so in some views of that variable it's converted to a blank string. But that is so weird!
Also, we clearly saw via Postman and Fiddler that POST was sent, so how did it get changed to Post? What code did that? I'd like to claim that it can't be my code since I'm checking the value of the RequestFeature before any of my other code related to the request gets a chance to run. Also, if I comment out the one line of code that registers that SignalR hub, then POST is never converted to Post and I never get a 404. But with that SignalR hub registered I periodically get this behavior.
Are there any SignalR or other .net Core switches I can turn on to get better trace or logging info to see when the POST is getting changed to Post? Is there a way to fix this?
This question was looked into via this GitHub issue https://github.com/aspnet/KestrelHttpServer/issues/2591 which was originally opened up when someone else also observed random 404 errors
I want to especially thank #ben-adams for his help in understanding what was going on.
Let me start by saying that this did not turn out to be a bug in the framework. It was a bug in my code. How can that be given what I was observing?
Well, it's like this...
In some parts of the HttpRequest the method is a string, but it in other parts it's an enum. The enum value for POST is Post. So that's why the case conversion was happening.
The reason that one part of the request was saying Post while the other part showed a Method value of a blank string was because the request object was gummed up because I had accessed it at a time when it was in between requests.
How did I do THAT? you may wonder. Well let me tell you, because the plot thickens...
I turns out that I have some logging code that that gathers context information when it's called and one of the pieces of context info it gathers is the current request.Method. When this logging code is called from a main thread, there is no issue.
However, my system does have some code that runs on background threads that are either started via a Timer or via a ThreadPool.QueueUserWorkItem. If this code hits an exception it will call the same logger code.
When my logger code, running on a background thread, checks for the current httpContext via IHttpContextAccessor I fully expected it to receive null. And certainly this same code in the same situation when accessing the current HttpContext via HttpContext.Current in a non .Net Core website does receive null. But as it turns out, under .Net core, it wasn't receiving null, it was receiving an object. But that object was for a request that had already finished and who's request object had already been reset!!!
Starting in .Net Core 2.0 the HttpContext, and it's child objects like request, gets reset after the connection for a request closes. So the HttpContext object (and it's request object) the logger code was getting when running on a background thread was an object that had been reset. It's request.Path for example was null.
It turns out that a request in this state does not expects it's request.Method property to be accessed. And doing so gums up the works for the next request that comes in. Ultimately this is the source of why the next request that came in ended up returning a 404 error.
So how do we fix this? Why does IHttpContextAccessor return an object rather than null in this out of context situation especially given that the object may very possibly be between requests? The answer is that when I was used Timer or ThreadPool.QueueUserWorkItem to create a background task, the Execution Context was being flowed to the new thread. This is just what happens by default when you use these API methods. But, internally the IHttpContextAccessor uses an AsyncLocal to keep track of the current HttpContext and since my new thread received Execution Context from the main thread it had access to the same AsyncLocal. And so IHttpContextAccessor provided an object rather than the null I was expecting when called from a background thread.
The fix? (Thank you #Ben-Adams!) Instead of calling ThreadPool.QueueUserWorkItem I needed to call ThreadPool.UnsafeQueueUserWorkItem instead. This method DOES NOT flow the current Execution Context to the new thread, and therefore the new thread won't have access to those AsyncLocals from the main thread. Once I did this, IHttpContextAccessor then returned null when called from the background thread instead of returning a object that was in between requests and untouchable. Yea!
When creating a `Timer' I also needed to change my code to do it in a way that would not flow Execution Context. Here is the code I use (which was inspired by some #Ben-Adams suggested):
public static Timer GetNewTimer(TimerCallback callback, object state, int dueTime, int interval) {
bool didSuppress = false;
try {
if (!ExecutionContext.IsFlowSuppressed()) {
//We need to suppress the flow of the execution context so that it does not flow to our
//new asynchronous thread. This is important so that AsyncLocals (like the one used by
//IHttpaccessor) do not flow to the new thread we are pushing our work to. By not flowing the
//execution context, IHttpAccessor wil return null rather than bogusly returning a context for
//a request that is in between requests.
//Related info: https://github.com/aspnet/KestrelHttpServer/issues/2591#issuecomment-399978206
//Info on Execution Context: https://blogs.msdn.microsoft.com/pfxteam/2012/06/15/executioncontext-vs-synchronizationcontext/
ExecutionContext.SuppressFlow();
didSuppress = true;
}
return new Timer(callback, state, dueTime, interval);
} finally {
// Restore the current ExecutionContext
if (didSuppress) {
ExecutionContext.RestoreFlow();
}
}
}
This only leaves one remaining question unanswered. My original question noted that registering a SignalR hub was causing the system to exhibit this random 404 behavior but the system did not exhibit this behavior when no SignalR hub was registered (or so I thought). Why was this? I truly don't know. Perhaps it was putting more resource pressure on some part of the system and thus causing the issue to show up more easily. Not sure. All I know is that the root issue was that I was flowing Execution Context to my background threads without realizing it and that was causing the IHttpContextAccessor's AsyncLocal to be in scope. Not flowing the Execution Context to the background threads fixes that issue.
I have REST-endpoint done with node-red which do some async tasks, for example odbc-query to the database.
When I'm resulting query to the http-response. It's just hangs on browser.
Looks like I need forward req and res object to the http-response. But how I do it?
Here is the flow:
[{"id":"a35e6901.509a1","type":"http in","z":"ec714e97.d73b58","name":"","url":"/get","method":"get","upload":false,"swaggerDoc":"","x":287.8571472167969,"y":1660.357177734375,"wires":[["7c116e0a.f8d67"]]},{"id":"98e22918.79bc4","type":"sqldbs","z":"ec714e97.d73b58","mydb":"8df7f8b0.bd44c","querytype":"select","name":"","x":723.5714111328125,"y":1644.6428833007812,"wires":[["de837ef9.5c1cf8"]]},{"id":"7c116e0a.f8d67","type":"function","z":"ec714e97.d73b58","name":"","func":"msq.topic = \"Select * from User\"\nreturn msg;","outputs":1,"noerr":0,"x":469.28570556640625,"y":1613.9286499023438,"wires":[["98e22918.79bc4"]]},{"id":"de837ef9.5c1cf8","type":"http response","z":"ec714e97.d73b58","name":"","statusCode":"","headers":{},"x":922.1428833007812,"y":1677.8570861816406,"wires":[]},{"id":"8df7f8b0.bd44c","type":"sqldbsdatabase","z":"","host":"127.0.0.1","port":"1433","db":"test","dialect":"mysql"}]
You need to make sure that it's the same message object that flows from the http-in node all the way to the http-out node.
This message object will have fields of msg.req and msg.res and the msg.res field will be used by the http-out node to send the response back to the browser.
Any node that takes an input and then forwards it on should preserve these field and not just create a new object for the output. All the built in nodes do this correctly and as should all the published 3rd party nodes. If you find one that does not follow this pattern you should raise a bug with the maintainer.
Your flow looks ok, but I've never used the DB nodes you have so can't comment on those.
Hello i'm newbie and im hardly to understand this notification in service-worker, and because my knowledge isn't good yet then probably i will unable to explain my problem clearly.
so here's the code :
// triggered everytime, when a push notification is received.
self.addEventListener('push', function(event) {
console.info('Event: Push');
var title = 'New commit on Github Repo: RIL';
var body = {
'body': 'Click to see the latest commit',
'tag': 'pwa',
'icon': './images/48x48.png'
};
event.waitUntil(
self.registration.showNotification(title, body)
);
});
this is the code that trigger to POP the notification, what I do not understand is where the argument to accept/ receive the data ?
I've been searched a lot: https://auth0.com/blog/introduction-to-progressive-web-apps-push-notifications-part-3/ ,
https://developers.google.com/web/updates/2015/03/push-notifications-on-the-open-web
there's some new data JSON or from git-server or push api, but I still hardly to understand where's to accept the data.
sorry if you still do not understand what's my problem.
Here to make it simple what I want :
Let's say i make a button, and everytime i click the button it will value as 'True' and I want that 'True' value to pass into argument and trigger the push of notication in service-worker.
2nd questions: am I able to trigger notification with header or text in html ? since we can manipulate the text with DOM ?
am I able to trigger notification without GCM, or API cause I just want a simple notification in serivce-worker like above without passing much data.
If you give more advice or maybe notification without service-worker but real time , I am surely happy to read it but I hope Im able to understand.
There are basically two concepts involved that work well together but can be used independently. The first is the visible UI shown to a user that tells them information or prompts them for an action. The second is sending an event from a server to the browser without requiring the user to currently be active on the site. For full details I recommend reading Google's Web Push docs.
Before either of those scenarios you have to request permission from the user. Once permission is granted you can just create a notification. No server or service worker required.
If you want to send events from a server you will need a service worker and you will need to get a subscription for the user. Once you have a subscription you would send it to a server for when you want to send an event to that specific browser instance.
Once you receive a push event from a server you display the UI the same as in the first scenario except you have to do it from the service worker.
I'm trying to simulate an asynchronous response on a webservice mock. The goal is to response a synchronous acknowledge message and then a delayed message back to the replyTo address. The approach I have selected uses mock service that will handle the acknowledge and then run a test case that will handle the processed message back to the replyTo. I'm using OnRequest Script to generate the acknowledged message and AfterRequest Script to run the test case that will emulate the delay and the response back to the replyTo.
So the question is which script object I can use to have access to the requestContent. I have seen examples using:
def holder = new com.eviware.soapui.support.XmlHolder( mockRequest.requestContent )
but the mockRequest instance is not available on AfterRequest, Which object I can use instead to have a holder with the request content?
I did find that
def holder = new com.eviware.soapui.support.XmlHolder( mockResult.getMockRequest().requestContent )
do the trick, but now I find that running a test script in AfterRequest delays the synchronous response back, Why could this be happening? Isn't AfterRequest's script executed after the mock service response back? Do i have to explicitly execute something at Dispatch or at OnRequest in order to summit back the response before AfterRequest code being executed?
I know this is really old question, but I just faced the same issue myself. I have no idea why it works as it works, but you can avoid the problem by accessing the request content in OnRequest, then store needed information to context and use the context in AfterRequest to get the information you need.