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.
Related
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.
I have created my own REST service based on the examples from "Domino Sample REST Service Feature" from 901v00_11.20141217-1000 version of XPages Extension Library.
As far as I understand the design of the library each REST request will be run in its own thread on the server. This approach does not allow to handle parallel POST requests to the same document.
I have not found any examples in XPages Extension Library which would handle post requests as transactions on the server, i.e. which would block the server resource for the whole request processing time and would put put next requests in the queue?
Can anybody point to the source code of the service which would allow to handle parallel requests?
The skeleton for my post request processing function is this
#POST
#Path(PATH_SEPARATOR + MyURL)
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response myPost(
String requestEntity,
#Context final UriInfo uriInfo)
{
LogMgr.traceEntry(this, "myPost");
RestContext.verifyUserContext();
String myJson = ... // Process post
Response response = buildResponse(myJson);
LogMgr.traceExit(this, "myPost", "OK");
return response;
}
And I would like to implement something like this
// Start transaction
String myJson = ... // Process post
// Stop transaction
Is there a way to do it in Java?
I suppose you could use document locking in traditional Notes/Domino context - and synchronized in Java :-)
Have you tried any of these? I cannot see why they should not work.
/John
I agree with John. You can use document locking to prevent simultaneous updates to the same document. You might also want to consider some changes to the definition of your REST API.
First, you imply you are using POST to update an existing document. Usually, POST is used to create a new resource. Consider using PUT instead of POST.
Second, even with document locking, you still might want to check for version conflicts. For example, let's say a client reads version 2 of a document and then attempts to update it. Meanwhile, another client has already updated the document to version 3. Many REST APIs use HTTP ETags to handle such version conflicts.
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
I'm trying to automatically trigger a soapui request with a groovy script when my mockservice receives a request. The request to trigger is based on a different WSDL than the service.
if possible, how would I go about to achieve the above?
Sorry if this is a totally stupid question...
If you have a TestSuite for the MockService and the SoapUI request as a TestStep, you can run the test step by it's name in the OnRequest Script for the MockService
testRunner.runTestStepByName("AnotherSoapRequest")