Servicestack Exception Handling: Passing a Status That Came From Web - servicestack

Let's say I have multiple services. One service is calling another service to get something. That service also gets some information from a third party vendor. Let's say the third party vendor returned a Too Many Requests message with 429 status code. The method that calls the third party vendor is used by lots of other methods and can be called directly via GET Request or within another Http Request.
When I detect the 429 status code, I was throwing a custom exception (let's say TooManyRequestsException) and using the Mapper to send the code to the requester.
Config.MapExceptionToStatusCode.Add(typeof(TooManyRequestsException),429);
It works if the method is called directly. But obviously I forgot the fact that this method was called by many other methods inside the service and all other methods are wrapping this exception with generic System.Exception objects with custom messages inside their catch blocks.
What other options do I have other than changing all the methods that wrap the exception with System.Exception? I tried to go over http://docs.servicestack.net/error-handling but couldn't really find a way that would help me, or couldn't make sense of it.

I recommend looking at Overriding OnExceptionTypeFilter in your AppHost which will let you apply custom logic to inspect the Exception and customize the ResponseStatus returned:
public override void OnExceptionTypeFilter(
Exception ex, ResponseStatus responseStatus)
{
var argEx = ex as ArgumentException;
var isValidationSummaryEx = argEx is ValidationException;
if (argEx != null && !isValidationSummaryEx && argEx.ParamName != null)
{
var paramMsgIndex = argEx.Message.LastIndexOf("Parameter name:");
var errorMsg = paramMsgIndex > 0
? argEx.Message.Substring(0, paramMsgIndex)
: argEx.Message;
responseStatus.Errors.Add(new ResponseError
{
ErrorCode = ex.GetType().Name,
FieldName = argEx.ParamName,
Message = errorMsg,
});
}
}

Related

How to Nak a ServiceStack RabbitMQ message within the RegisterHandler?

I'd like to be able to requeue a message from within my Service Endpoint that has been wired up through the RegisterHandler method of RabbitMQ Server. e.g.
mqServer.RegisterHandler<OutboundILeadPhone>(m =>
{
var db = container.Resolve<IFrontEndRepository>();
db.SaveMessage(m as Message);
return ServiceController.ExecuteMessage(m);
}, noOfThreads: 1);
or here.
public object Post(OutboundILeadPhone request)
{
throw new OutBoundAgentNotFoundException(); // added after mythz posted his first response
}
I don't see any examples how this is accomplished, so I'm starting to believe that it may not be possible with the ServiceStack abstraction. On the other hand, this looks promising.
Thank you, Stephen
Update
Throwing an exception in the Service does nak it, but then the message is sent to the OutboundILeadPhone.dlq which is normal ServiceStack behavior. Guess what I'm looking for is a way for the message to stay in the OutboundILeadPhone.inq queue.
Throwing an exception in your Service will automatically Nak the message. This default exception handling behavior can also be overridden with RabbitMqServer's RegisterHandler API that takes an Exception callback, i.e:
void RegisterHandler<T>(
Func<IMessage<T>, object> processMessageFn,
Action<IMessage<T>, Exception> processExceptionEx);
void RegisterHandler<T>(
Func<IMessage<T>, object> processMessageFn,
Action<IMessage<T>, Exception> processExceptionEx,
int noOfThreads)

Golang beego framework to set the status code

I am using Golang to write web applications, and I use beego framework. It seems the the framework have the internal status code returned for golang web server.
I am wondering is there any method in golang or beego, or other tools that can let me control the status code returned to browser, say 200, or 500 or others number.
In your controller you can access the http.ResponseWriter via the Ctx
type SomeController struct {
beego.Controller
}
func (c *SomeController) Get() {
c.Ctx.ResponseWriter.WriteHeader(500)
}
Edit: After further inspection you should probably do this:
func (c *SomeController) Get() {
c.CustomAbort(500, "Internal server error")
}
I'm leaving the reference about the context because you can find the http.Request and http.ResponseWriter on controller's Ctx property.
Have a look on http.ResponseWriter.WriteHeader. If you have access to the ResponseWriter-object, you can easily return your own HTTP status code.
c.Abort("500")
it response HTTP code is 200.
Must be:
c.Ctx.ResponseWriter.WriteHeader(500)
Very late to the party. I m able to set status on beego v2.0.2.
func (u *UserController) Post() {
var user models.User
json.Unmarshal(u.Ctx.Input.RequestBody, &user)
uid, _ := models.AddUser(&user)
u.Data["json"] = map[string]interface{}{"uid": uid}
u.Ctx.Output.Status = http.StatusCreated #<<<------------
u.ServeJSON()
}

ServiceStack/Funq not disposing RavenDB document session after request is complete

In trying to integrate RavenDB usage with Service Stack, I ran across the following solution proposed for session management:
A: using RavenDB with ServiceStack
The proposal to use the line below to dispose of the DocumentSession object once the request is complete was an attractive one.
container.Register(c => c.Resolve<IDocumentStore>().OpenSession()).ReusedWithin(ReuseScope.Request);
From what I understand of the Funq logic, I'm registering a new DocumentSession object with the IoC container that will be resolved for IDocumentSession and will only exist for the duration of the request. That seemed like a very clean approach.
However, I have since run into the following max session requests exception from RavenDB:
The maximum number of requests (30) allowed for this session has been
reached. Raven limits the number of remote calls that a session is
allowed to make as an early warning system. Sessions are expected to
be short lived, and Raven provides facilities like Load(string[] keys)
to load multiple documents at once and batch saves.
Now, unless I'm missing something, I shouldn't be hitting a request cap on a single session if each session only exists for the duration of a single request. To get around this problem, I tried the following, quite ill-advised solution to no avail:
var session = container.Resolve<IDocumentStore>().OpenSession();
session.Advanced.MaxNumberOfRequestsPerSession = 50000;
container.Register(p => session).ReusedWithin(ReuseScope.Request);
Here is a sample of how I'm using the resolved DocumentSession instance:
private readonly IDocumentSession _session;
public UsersService(IDocumentSession session)
{
_session = session;
}
public ServiceResponse<UserProfile> Get(GetUser request)
{
var response = new ServiceResponse<UserProfile> {Successful = true};
try
{
var user = _session.Load<UserProfile>(request.UserId);
if (user == null || user.Deleted || !user.IsActive || !user.IsActive)
{
throw HttpError.NotFound("User {0} was not found.".Fmt(request.UserId));
}
response.Data = user;
}
catch (Exception ex)
{
_logger.Error(ex.Message, ex);
response.StackTrace = ex.StackTrace;
response.Errors.Add(ex.Message);
response.Successful = false;
}
return response;
}
As far as I can see, I'm implementing SS + RavenDB "by the book" as far as the integration point goes, but I'm still getting this max session request exception and I don't understand how. I also cannot reliably replicate the exception or the conditions under which it is being thrown, which is very unsettling.

How do I call my own service from a request/response filter in ServiceStack?

My problem is...
...I have a DTO like this
[Route("/route/to/dto/{Id}", "GET")]
public class Foo : IReturn<Bar>
{
public string Id { get; set; }
}
and need to call the service that implements the method with this signature
public Bar Get(Foo)
from a request and/or response filter. I don't know what class implements it (don't want to need to know). What I need is something like the LocalServiceClient class in the example below:
var client = new LocalServiceClient();
Bar bar = client.Get(new Foo());
Does this LocalServiceClient thing exists? JsonServiceClient has a pretty similar interface, but using it would be inneficient (I need to call my own service, I shouldn't need an extra round-trip, even to localhost, just to do this).
I'm aware of ResolveService method from Service class, but it requires me to have a service instance and to know what class will handle the request.
I think this LocalServiceClient is possible because I have all the data that a remote client (e.g. JsonServiceClient) needs to call the service - request DTO, route, verb - but couldn't find how to do it. Actually, it should be easier to implement than JsonServiceClient.
JsonServiceClient would do it, but there must be a better way, using the same request context.
What I want to do (skip this if you're not curious about why I'm doing this)
Actually, my DTOs are like this:
[EmbedRequestedLinks]
[Route("/route/to/dto/{Id}", "GET")]
public class MyResponseDto
{
public string Id { get; set; }
public EmbeddableLink<AResponseDto> RelatedResource { get; set; }
public EmbeddableLink<AnotherResponteDto> AnotherRelatedResource { get; set; }
}
EmbedRequestedLinksAttribute is a request/response filter. This filter checks if there is a query argument named "embed" in the request. If so, the filter need to "embed" the comma-separated related resources referenced by the argument into the response to this request. EmbeddableLink<T> instances can be obtained by using extension methods like these:
1) public static EmbeddableLink<T> ToEmbeddableLink<T>(this IReturn<T> requestDto)
2) public static EmbeddableLink<T> ToEmbeddableLink<T>(this T resource)
Assume a client places this request:
GET /route/to/dto/123456?embed=relatedResource HTTP/1.1
The service that will handle this request will return an instance of MyResponseDto with EmbeddableLinks created using signature (1). Then my response filter will see the embed query argument and will call the Get method of the appropriate service, replacing the RelatedResource with another instance of EmbeddableLink, this time created using extension method (2):
var client = new LocalServiceClient();
response.RelatedResource = client.Get(response.RelatedResource.RequestDto)
.ToEmbeddableLink();
The serialization routine of EmbeddableLink takes care of the rest.
In case an embeddable link is not included in the embed list the serialization routine will call the extension method ToUrl (provided by ServiceStack), that takes a verb and converts a request DTO into a URL. In this example the client will get this response:
{
"id": "9asc09dcd80a98",
"relatedResource": { "id": "ioijo0909801", ... },
"anotherRelatedResource":
{
"$link": { "href": "/route/to/another/dto/1sdf89879s" }
}
}
I know the creators of ServiceStack think that polymorphic request/responses are bad things but this case seems OK to me because I'm not creating services, instead I'm extending the framework to help me create services the way I (and possibly other users of ServiceStack) need. I'm also creating other hypermedia extensions to ServiceStack. (I hope my boss allow me to publish these extensions on github)
If you really want to do this then look the source code for ServiceStack. Look at the ServiceManager and ServiceController. These classes are responsible for registering and resolving services. You might even be able to use reflection to create services on the fly with the static EndpointHost.Metadata like so:
var operation = EndpointHost.Metadata.Operations
.FirstOrDefault(x => x.RequestType == typeof(Person));
if (operation != null)
{
var svc = Activator.CreateInstance(operation.ServiceType);
var method = operation.ServiceType.GetMethod("Get");
var response = method.Invoke(svc, new[] { new Person() });
}
This kinda works but you will get NULL exceptions if there is other code calling
var httpRequest = RequestContext.Get<IHttpRequest>();
But I would not suggest this.
Instead if you create your own Business Service classes that do all the CRUD operations (POST/PUT/GET ect). Then make the ServiceStack Services thin wrappers over them. Now you can call your own services whenever you want without worrying about the HTTP Request and ServiceStack. Only use the ServiceStack Service when you are dealing with HTTP requests
You can call the static AppHostBase.Resolve() method as demonstrated here, calling a SeviceStack Service from an MVC controller:
var helloService = AppHostBase.Resolve<HelloService>();
helloService.RequestContext = System.Web.HttpContext.Current.ToRequestContext();
var response = (HelloResponse)helloService.Any(new HelloRequest { Name = User.Identity.Name });
However, I would take #kampsj's approach of making your ServiceStack services a thin wrapper around your application service classes and only deal with HTTP/Session specific stuff in the ServiceStack service.

Azure Service Bus - SubscriptionClient.AcceptMessageSession() vs. SubscriptionClient.BeginAcceptMessageSession()

In the Azure Service Bus namespace, there is a SubscriptionClient type, with a method to initiate a MessageSession in this manner:-
MessageSession session = subscriptionClient.AcceptMessageSession(...);
This is the synchronous version, and it returns a MessageSession. The library also provides an asynchronous version, BeginAcceptMessageSession(). This one is tripping me up, because it invokes a callback, passing in an IAsyncResult and whatever state object you wish to pass. In my case, I am passing the SubscriptionClient instance, so that I can invoke EndAcceptMessageSession() on the SubscriptionClient. BeginAcceptMessageSession() has a return type of void.
How can I access the MessageSession that is accepted via BeginAcceptMessageSession()? All I get back in the callback's result parameter is my SubscriptionClient instance, which I need in order to terminate the BeginAcceptMessageSession() via EndAcceptMessageSession().
The MessageSession reference is nowhere to be found. The documentation is no help in this regard. Searching on Google only reveals a scant 3 pages of search results, most of which is simply the online description of the method itself from MSDN. I looked in AsyncManager.Parameters and it is also empty.
Does anyone know how BeginAcceptMessageSession() is supposed to be invoked so that I can get a reference to the MessageSession thus created?
You should invoke the method like this:
Call the begin method with a method that accepts the IAsyncResult and the SubscriptionClient.
In the other method (AcceptDone in this case), call EndAcceptMessageSession with the IAsyncResult to get the MessageSession
What you see here is an standard implementation of the Asynchronous Programming Model.
private static void Do()
{
SubscriptionClient client = ...
client.BeginAcceptMessageSession(AcceptDone, client);
}
public static void AcceptDone(IAsyncResult result)
{
var subscriptionClient = result.AsyncState as SubscriptionClient;
if (subscriptionClient == null)
{
Console.WriteLine("Async Subscriber got no data.");
return;
}
var session = subscriptionClient.EndAcceptMessageSession(result);
...
subscriptionClient.Close();
}

Resources