What is the purpose of the out queue in RedisMQ? - redis

In the Re-usability use-case project with RedisMQ there is a SMessageService which has the following handler.
SMessageService :Service{
public object Any(EmailMessage request)
{
var sw = Stopwatch.StartNew();
Db.InsertAll(Email.Process(request));
return new SMessageResponse { TimeTakenMs = sw.ElapsedMilliseconds };
}...
}
When the services returns, it puts the message in the mq:SMessageResponse.inq list.
My questions is if I return null instead of new SMessageResponse{...}, a message is put in the mq:EmailMessage.outq list, what is the reason for this?
Also, if I don't want to return a response at all, how would I do this or is this bad practice in the area of messaging?. In other words, I always need to have a log of what has happened.

Related

WebClient - how to ignore a specific HTTP error

I'd like to create a Spring WebClient that ignores a specific HTTP error. From the documentation of WebClient.retrieve():
By default, 4xx and 5xx responses result in a WebClientResponseException. To customize error handling, use ResponseSpec.onStatus(Predicate, Function) handlers.
I want all calls through a WebClient instance to ignore the specific HTTP error. That is why onStatus() is of no use to me (it has to be set per response).
The best I could come up with is this:
WebClient webClient = WebClient.builder().filter((request, next) -> {
Mono<ClientResponse> response = next.exchange(request);
response = response.onErrorResume(WebClientResponseException.class, ex -> {
return ex.getRawStatusCode() == 418 ? Mono.empty() : Mono.error(ex);
});
return response;
}).build();
URI uri = UriComponentsBuilder.fromUriString("https://httpstat.us/418").build().toUri();
webClient.get().uri(uri).retrieve().toBodilessEntity().block();
but it does throw the exception instead of ignoring it (the lambda passed to onErrorResume() is never called).
Edited: fixed the mistake pointed out by the first answer.
After extensive debugging of spring-webflux 5.3.4 and with the help of some ideas by Martin Tarjányi, I've come to this as the only possible "solution":
WebClient webClient = WebClient.builder().filter((request, next) -> {
return next.exchange(request).flatMap(res -> {
if (res.rawStatusCode() == HttpStatus.I_AM_A_TEAPOT.value()) {
res = res.mutate().rawStatusCode(299).build();
}
return Mono.just(res);
});
}).build();
URI uri = UriComponentsBuilder.fromUriString("https://httpstat.us/418").build().toUri();
String body = webClient.get().uri(uri).retrieve().toEntity(String.class).block().getBody();
The background: I am migrating some code from RestTemplate to WebClient. The old code looks like this:
RestTemplate restTemplate = ...;
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
if (response.getRawStatusCode() == HttpStatus.I_AM_A_TEAPOT.value()) {
return;
}
super.handleError(response);
}
});
URI uri = UriComponentsBuilder.fromUriString("https://httpstat.us/418").build().toUri();
String body = restTemplate.getForEntity(uri, String.class).getBody();
I believe it is a straightforward and common case.
WebClient is not yet a 100% replacement for RestTemplate.
UPDATE: Turns out this answer doesn't address the core problem of filtering out a specific status code, just addresses a general coding pattern.
The reason onErrorResume lambda is not called is that response.onErrorResume creates a brand new Mono and your code does not use the result (i.e. it's not assigned to the response variable), so in the end a Mono without the onErrorResume operator is returned.
Using Project Reactor it's usually a good practice to avoid declaring local Mono and Flux variables and use a single chain instead. This helps to avoid similar subtle bugs.
WebClient webClient = WebClient.builder()
.filter((request, next) -> next.exchange(request)
.onErrorResume(WebClientResponseException.class, ex -> ex.getRawStatusCode() == 418 ? Mono.empty() : Mono.error(ex)))
.build();

Getting a client readable message from an Npgsql.PostgresException

I'm writing a web api using PostgreSQL and am checking database constraints as part of the validation process, but I also have a global exception filter as a fallback in case something gets by when saving. My problem is that the exception doesn't seem to have any message that I can present to the client without some processing. The added image is of the PostgresException data from a breakpoint. For example, in this case I would want something along the lines of "Asset Number x already exists" or just "Asset Number must be unique". Is this something that can be configured somewhere? The place that makes the most sense is at the constraint creation code, but I couldn't find an option to do so.
modelBuilder.Entity<AssetItem>().HasIndex(item => new { item.AssetNumber }).IsUnique();
public class DbExceptionFilter : IExceptionFilter
{
private const string UNIQUE_EXCEPTION = "23505";
public async void OnException(ExceptionContext context)
{
var exceptionType = context.Exception.InnerException.GetType().FullName;
if (exceptionType == "Npgsql.PostgresException")
{
var pgException = (PostgresException) context.Exception.InnerException;
switch(pgException.SqlState)
{
case UNIQUE_EXCEPTION:
var error = new {error = "Unique Error Here"};
await WriteJsonErrorResponse(context.HttpContext.Response, HttpStatusCode.BadRequest, error);
return;
}
}
else
{
var error = new { error = "Unexpected Server Error"};
await WriteJsonErrorResponse(context.HttpContext.Response, HttpStatusCode.InternalServerError, error);
return;
}
}
private async Task WriteJsonErrorResponse(HttpResponse response, HttpStatusCode statusCode, dynamic error)
{
response.ContentType = "application/json";
response.StatusCode = (int) statusCode;
await response.Body.WriteAsync(Encoding.ASCII.GetBytes(JsonConvert.SerializeObject(error)));
}
}
The closest thing to a user-readable message that PostgreSQL provides is the message text exposed on PostgresException.
However, as a general rule it is not a good idea to expose database errors directly to users (including web API users): these are intended to the application directly interacting with the database (i.e. your application). These messages generally don't mean much to the users of your API, and more importantly they leak potentially sensitive information about your database schema and are therefore not secure. It's especially problematic to dump/serialize the entire exception to the user as you seem to be doing (with JsonConvert.SerializeObject).
The best practice here would be to identify legitimate database exceptions that the user may trigger, intercept these and return and appropriately-worded message of your own (e.g. "A user with that name already exists").
As a side note, to identify PostgresException, rather than getting the name of the exception and comparing to that, you can simply use C# pattern matching:
if (context.Exception.InnerException is PostgresException postgresException)
{
// ...
}

Proper way to retrieve the Request.Content from global error handler

I have register a global exception handler, and it fires and contains all of the information I need with the exception of the Request.Content which is always empty... I need the values that were passed in when I am debugging...
Public class MyExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
try
{
... other code
var methodName = context.Request.Method.ToString();
var errorUri = context.Request.RequestUri.ToString();
var errorMessage = context.Exception.Message;
var errorStackTrace = context.Exception.StackTrace.ToString();
var payload = context.Request.Content.ReadAsStringAsync().Result;
..... other code
}
}
}
What is the proper way to retrieve the Request.Content from global error handler ? In the code above the Content property has already been read by the model binders and as such is always empty.
How can I consistently get the posted body from an exception ?
Should I retrieve and save the posted body in a custom MessageHandler ?
Thanks
Greg
In experimenting with reading the buffer of the request.Content in a custom message handler.. It appears that if I read it with this code:
var payload = context.Request.Content.ReadAsStringAsync().Result;
and do NOTHING with it... The buffer will not be emptied when the model binders read it, because its always there in my exception logger now... I don't know if this is by design or what but its exasperating !

Is it possible to return a response from a Web API constructor?

I have a Web API ApiController base class and I would like to perform some validations in the constructor. This might include checking the current load on the server. If it's high, I'd like to return an appropriate HttpResponseMessage indicating the requestor should try again later.
Is something like this possible?
I Haven't tested it but that's not what the constructor is for. I don't think all plumbing is set at that time.
You could use global filters for this purpose. Here you have a sample that sets a global filter for authorization, you should use a similar logic but creating your own filter for your specific purposes.
A global filter would intercept all your requests and is executed before the controller actions so is a good place to perform your task.
Even though what you are doing sounds like it may be better to revise the approach. Note that you can throw HttpResponseException since the WebApi is Rest Service HttpResponseException is the recommended way to throw Exceptions back to the client.
var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent("No idea what happened "),
ReasonPhrase = "Something was not Not Found"
}
throw new HttpResponseException(resp);
As long as you're using .NET 4.5, then you'd be better off creating a custom MessageHandler. You'll need to extend DelegatingHandler in order to do that.
public class MyHandler : DelegatingHandler {
protected override async Task<HttpResponseMessage> SendAsync(
HttpMessageRequest request, CancellationToken cancellationToken) {
// Access the request object, and do your checking in here for things
// that might cause you to want to return a status before getting to your
// Action method.
// For example...
return request.CreateResponse(HttpStatusCode.Forbidden);
}
}
Then inside your WebApiConfig, just add the following code to use the new Handler:
config.MessageHandlers.Add(new MyHandler());
You can't throw HttpResponseException in constructor, that will always cause 500.
Easiest way is to override ExecuteAsync():
public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) {
if (!myAuthLogicCheck()) {
// Return 401 not authorized
var msg = new HttpResponseMessage(HttpStatusCode.Unauthorized) { ReasonPhrase = "User not logged in" };
throw new HttpResponseException(msg);
}
return base.ExecuteAsync(controllerContext, cancellationToken);
}

Creating an SPListItem in a WCF service deployed to SharePoint

i have the following method in a WCF service, that has been deployed to SharePoint using Shail Malik's guide:
[OperationContract]
public string AddItem(string itemTitle, Guid? idOfListToUse)
{
using (var portal = new SPSite(SPContext.Current.Site.Url, SPContext.Current.Site.SystemAccount.UserToken))
{
using (var web = portal.OpenWeb())
{
Guid listId;
web.AllowUnsafeUpdates = true;
if (idOfListToUse != null && idOfListToUse.Value != new Guid())
{
listId = idOfListToUse.Value;
}
else
{
try
{
listId = new Guid(web.Properties[PropertyBagKeys.TagsList]);
}
catch (Exception ex)
{
throw new MyException("No List Id for the tag list (default list) has been found!", ex);
}
}
var list = web.Lists[listId];
string title = "";
SPSecurity.RunWithElevatedPrivileges(delegate{
var newItem = list.Items.Add();
newItem["Title"] = itemTitle;
newItem.Update();
title = newItem.Title;
});
web.AllowUnsafeUpdates = false;
return title;
}
}
}
When the method gets called from Javascript (using Rick Strahl's excellent ServiceProxy.js) it fails and it does so on newItem.Update() because of ValidateFormDigest().
Here's the kicker though, when I step through the code it works! No exceptions at all!
Ok, found the answer (there's 2 even :-D)
First, the dirty one:
Set FormDigestValidatedProperty in the context:
HttpContext.Current.Items["FormDigestValidated"] = true;
Second, the slightly less dirty version (basically leaving the way open for XSS attacks, but this is an intranet anyway)
The answer
I don't think you can access 'list' as it was created outside the elevated code block.
http://blogs.pointbridge.com/Blogs/herzog_daniel/Pages/Post.aspx?_ID=8
I'm guessing when you are stepping though the entire process is in admin mode so all are elevated.
Colin, it's a really bad idea to try to access HttpContext (likewise SPContext) inside a WCF service. See here: MSDN: WCF Services and ASP.NET
From the article:
HttpContext: Current is always null
when accessed from within a WCF
service.
It's likely this is the cause of your problem.
EDIT: I notice that you're trying to use SPContext to get the url of the site collection. I didn't find a good solution to this either so I just send the url of the target site collection as a parameter to the service call. Not the most optimal solution but I couldn't think of a better way. Also, if you need to check authentication/identities, etc use ServiceSecurityContext.Current.