Spring AMQP - what if I return null in a Rabbit listener method with #SendTo annotation? - spring-amqp

Spring AMQP doc says:
Assuming our processOrder method should now return an OrderStatus, it
is possible to write it as follow to automatically send a reply:
#RabbitListener(destination = "myQueue")
#SendTo("status")
public OrderStatus processOrder(Order order) {
// order processing
return status;
}
What if I return a null at the end of the processOrder method? Will it send a null object to MQ or simply do nothing?

If you return null, no reply will be sent. Under TRACE level logging, you will see a log message No result object given - no result to handle.

Related

Use SpringAOP to intercept send and receive messages

For some reasons, I have to intercept send and receive messages. (Wrap up the message and parse the message when it is received).
I know MessagePostProcessor is a form of interceptor, but it will influence current code. So, I am considering using Spring AOP.
For sending messages, I can simply intercept RabbitTemplate’s send and convertAndSend methods, Like the following code:
#Around("execution(* org.springframework.amqp.rabbit.core.RabbitTemplate.send(..))")
But for receiving messages, Which method is best to intercept? In most cases, RabbitListener is used to receive messages.
Any help is appreciated.
Add an Advice to the listener container's adviceChain. See https://docs.spring.io/spring-amqp/docs/2.2.10.RELEASE/reference/html/#containerAttributes
EDIT
#Bean
public MethodInterceptor advice() {
return invocation -> {
Message message = (Message) invocation.getArguments()[0];
try {
// before
invocation.proceed();
// after
}
catch (Exception e) {
// ...
throw e;
}
finally {
// ...
}
return null;
};
}

Reading a POST request in Undertow without consuming it

In Undertow I have two handlers, that are chained:
The first handler reads the request and then calls calls the second handler via next.handleRequest(exchange);
The second handler is a proxy handler which send the request to and external server where it is processed.
My problem is the first handler which reads the request. The request headers are no big deal but getting the body data of POST requests is a problem.
Existing solutions as shown in the question How to properly read POST request body in a Handler? consume the request body su that the handler chaining does not work anymore.
How can I read the request body data without consuming it or altering the request in a way that the handler chain does not work afterwards?
I found the problem, in the end it was a missing call to ByteBuffer.flip().
If someone ever needs such an POST data reader one can use the following simplified implementation of an AbstractStreamSourceConduit that is able to read the incoming POST data without consuming it:
exchange.addRequestWrapper(new ConduitWrapper<StreamSourceConduit>() {
#Override
public StreamSourceConduit wrap(ConduitFactory<StreamSourceConduit> factory, HttpServerExchange exchange) {
StreamSourceConduit source = factory.create();
return new AbstractStreamSourceConduit<StreamSourceConduit>(source) {
ByteArrayOutputStream bout = new ByteArrayOutputStream(8192);
#Override
public int read(ByteBuffer dst) throws IOException {
int x = super.read(dst);
if (x >= 0) {
ByteBuffer dup = dst.duplicate();
dup.flip();
byte[] data = new byte[x];
dup.get(data);
bout.write(data);
} else {
// end of stream reached
byte[] data = bout.toByteArray();
// ... to something with data
}
return x;
}
};
}
});

In OpenRasta, how should you handle codec errors or exceptions?

My scenario is this:
A client application executes a HTTP POST against an endpoint exposed by OpenRasta.
The body of the request contains an error that causes a problem in the codec - which is a custom implementation of OpenRasta.Codecs.IMediaTypeReader. This converts a JSON payload to the POCO expected by the handler.
The codec throws an exception that describes the error in a useful way. For example: Newtonsoft.Json.JsonReaderException: After parsing a value an unexpected character was encountered: ". Line 4, position 5.
The client application receives a HTTP 405 - MethodNotAllowed. The client doesn't see any of the exception details.
If the codec is modified to catch a JsonReaderException and return Missing.Value, similar to the Implementing a codec wiki, then the client receives a HTTP 500 - Internal Server Error. The body of the response also describes the following exception:
System.InvalidOperationException: The operation is not ready for invocation.
at OpenRasta.OperationModel.MethodBased.MethodBasedOperation.Invoke()
at OpenRasta.OperationModel.Interceptors.OperationWithInterceptors.<Invoke>b__0()
at OpenRasta.OperationModel.Interceptors.OperationWithInterceptors.Invoke()
at OpenRasta.OperationModel.OperationExecutor.Execute(IEnumerable`1 operations)
at OpenRasta.Pipeline.Contributors.OperationInvokerContributor.ExecuteOperations(ICommunicationContext context)
at OpenRasta.Pipeline.PipelineRunner.ExecuteContributor(ICommunicationContext context, ContributorCall call)
How should I modify my application so that:
The client receives a HTTP 400 Bad Request.
The client receives a string containing the details of the exception encountered in the codec.
Here is a minor variation of the answer above - this time with codec selection based on the operation result data.
Within IConfigurationSource:
using (OpenRastaConfiguration.Manual)
{
ResourceSpace.Uses.PipelineContributor<ErrorCheckingContributor>();
ResourceSpace.Has.ResourcesOfType<ApplicationError>()
.WithoutUri
.TranscodedBy<ApplicationErrorCodec>();
// Or use a generic JSON serializer like this:
// .AsJsonDataContract();
// Other configuration here
}
Now ErrorCheckingContributor looks like this:
public class ErrorCheckingContributor : IPipelineContributor
{
public void Initialize(IPipeline pipelineRunner)
{
pipelineRunner
.Notify(CheckRequestDecoding)
.After<KnownStages.IOperationResultInvocation>()
.And.Before<KnownStages.ICodecResponseSelection>();
}
private static PipelineContinuation CheckRequestDecoding(ICommunicationContext context)
{
if (context.ServerErrors.Count == 0)
{
return PipelineContinuation.Continue;
}
Error err = context.ServerErrors[0];
// Get a suitable message (err.Message contains stack traces, so try to avoid that)
string msg = err.Title;
if (msg == null && err.Exception != null)
msg = err.Exception.Message;
if (msg == null)
msg = err.Message;
// Create instance of an error information resource which is specific for the application
// - This one is rather simple and only contains a copy of the message
ApplicationError error = new ApplicationError(msg);
// Set operation result to be "400 Bad Request" and remove errors
context.OperationResult = new OperationResult.BadRequest { ResponseResource = error };
context.ServerErrors.Clear();
// Render immediately without starting any handlers
return PipelineContinuation.RenderNow;
}
}
The class ApplicationError is:
public class ApplicationError
{
public string Message { get; set; }
public ApplicationError(string message)
{
Message = message;
}
}
At last we need a codec ApplicationErrorCodec for ApplicationError. This is not different from any other IMediaTypeWriter codec but depends a lot on your expected response media type. See https://github.com/openrasta/openrasta/wiki/Implementing-a-Codec for one example.
Having found this thread on Google Groups which contains all the answers, my current implementation looks something like this.
Within my implementation of IConfigurationSource:
using (OpenRastaConfiguration.Manual)
{
ResourceSpace.Uses.PipelineContributor<ErrorCheckingContributor>();
// Other configuration here
}
Then ErrorCheckingContributor looks something like this:
public class ErrorCheckingContributor : IPipelineContributor
{
public void Initialize(IPipeline pipelineRunner)
{
pipelineRunner
.Notify(CheckRequestDecoding)
.After<KnownStages.IOperationResultInvocation>()
.And.Before<KnownStages.ICodecResponseSelection>();
}
private static PipelineContinuation CheckRequestDecoding(ICommunicationContext context)
{
if (context.ServerErrors.Count == 0)
{
return PipelineContinuation.Continue;
}
var first = context.ServerErrors[0];
if (first.Exception is Newtonsoft.Json.JsonReaderException)
{
context.Response.Entity.ContentType = MediaType.TextPlain;
context.Response.Entity.ContentLength = first.Exception.Message.Length;
using (var sw = new StreamWriter(context.Response.Entity.Stream))
{
sw.Write(first.Exception.Message);
}
}
return PipelineContinuation.Continue;
}
}
There's some things to be aware of with the above:
If a handler were to throw a JsonReaderException, it would also be processed here.
It doesn't check what media types the client accepts. This is different from exceptions thrown by Handlers that do go through codec selection.
Tried setting context.OperationResult to context.ServerErrors - but it doesn't go through the codec.

ASP.NET MVC - Proper way to handle ajax actions with no return object

I have a controller action that does some work in the database and then exits when it's finished. This action is being called via jQuery's ajax function with the dataType set to 'json'.
If I set the return type of the action to void, everything will function just fine except Firefox will show an error in the console that says: "no element found".
It makes sense that Firefox would throw this error if it was expecting XML to come back. However, even when I change the dataType property of the ajax call to "text", I still receive the error. In order to get rid of the error with the return type void, I would have to set the Response's ContentType to "text/html". Or I could set the return type to JsonResult and return a new [empty] JsonResult object.
I'm sure there are several ways I can make this error go away, but I wanted to know the proper way to handle actions with no return values being called via ajax.
If it matters, I'm also using the async controller action pattern.
public void DoSomethingAsync(SomeJsonObjectForModelBinding model)
{
// do some database things
}
public void DoSomethingCompleted()
{
// nothing to do...
// what should my return type be?
// do I need to set the content type here?
}
I know this doesn't exactly answer your question, but I would argue that you should always have a return value coming back from an AJAX or web service call. Even if only to tell you that the operation was successful, or otherwise return the error (message) back to you.
I often define a class like this:
public class JsonResultData
{
private bool _success = true;
public bool Success
{
get { return _success; }
set { _success = value; }
}
public object Value { get; set; }
public List<string> Errors { get; set; }
public JsonResultData()
{
this.Errors = new List<string>();
}
}
And then use it to return data or any other call meta data in the JsonResultData wrapper like so:
return new JsonResult {
Data = new JsonResultData { Value = returnValue, Success = true }
};
I can't comment because of my reputation but I still wanted to contribute to clear the confusion in Kon's answer.
In an application I caught all exceptions within an ActionMethod, set an HttpStatusCode and added an error message to the response. I extracted the message in the Ajax error function and showed it to the user.
Everything worked out fine until the application got put on the staging server, who had some kind of settings that did not allow a return message within an erroneous response. Instead some standard Html was transmitted resulting in a JS error processing the response.
In the end I had to rewrite all my exception handling returning my application errors as successful Ajax call (which it actually is) and then differ within the Ajax success function, just the way it should be.
You should not mix system-level and application-level feedback. You may not be able to control the system-level feedback the way your application needs.

ASP.net MVC Futures AsyncController: Handling server validation

I want to be able to check the form inputs prior to launching a long running asynchronous task.
Two approaches that come to mind:
Check values on the Begin method and
throw an exception?
Post to a normal (synchronous method) which validates as per normal. redirects to the asynchonrous method if no errors found.
Throwing an exception i thought would be a simple solution. I can't return the view from the begin method, so the exception is handled on the end method. Only it isn't getting across to the end method (I thought this was the normal pattern)
Validating in a normal synchronous method is fine... but how do i transfer or redirect the request to the asynchronous method???
You don't need to use exceptions or a synchronous method, you can just pass back a different IAsyncResult (assuming that's the pattern you're using - if you're using the event or delegate patterns, you'd still be able to achieve something similar without exceptions).
Here's a simple example of this where we use a dummy delegate to return if there's an error (in this case an invalid ID):
public class MyAsyncController : AsyncController
{
public IAsyncResult BeginFoo(int id, AsyncCallback callback, object state)
{
Action errorDelegate = () => ViewData["errors"] = "Invalid ID";
// Here's our validation check, return the error delegate if necessary
if (id <= 0) return errorDelegate.BeginInvoke(callback, state);
var webRequest = WebRequest.Create("http://www.apple.com");
return webRequest.BeginGetResponse(callback, webRequest);
}
public ActionResult EndFoo(IAsyncResult asyncResult)
{
if (asyncResult.AsyncState is WebRequest)
{
var webRequest = (WebRequest) asyncResult.AsyncState;
var httpResponse = (HttpWebResponse) webRequest.EndGetResponse(asyncResult);
ViewData["status"] = httpResponse.StatusCode;
}
return View();
}
}

Resources