Logging Servicestack Bad Requests - servicestack

Is there a way to log the validation results which get populated in the ResponseStatus when you have the ValidationFeature plugin enabled?
From what i can understand, any requests coming in get validated and if the validation passes then it goes to the service. Using request filters i can log the requests coming in however using the response filters i can only log valid requests.
I trying to log all responses especially HttpStatus 400 (Bad request) which is returned as a result of a validation error.
I have also tried to play a bit with the RequestLog plugin but from what i understood what gets logged are only valid request (i.e requests that went to the service).
I hope you understand what i am trying to say.

Look to see how 7digital have customized ServiceStack's Validation Feature to support logging.
Related Features
The new API supports the concept of a ServiceRunner you can override to add your own event and exception hooks you can read about in the wiki.
There is also the built-in Request Logger that lets you expect details of the more recently processed requests.
Create an issue on the GitHub project if you want to see logging in the validation feature.

A quick way to log errors from the ValidationFeature plugin is simply thus:
public override void Configure(Container container)
{
...etc...
Plugins.Add(new RequestLogsFeature() { etc });
Plugins.Add(new ValidationFeature()
{
ErrorResponseFilter = MyValidationError
});
...etc...
}
public object MyValidationError(ValidationResult validationResult, object errorDto)
{
Container.Resolve<IRequestLogger>().Log(null, null, errorDto, TimeSpan.Zero);
return errorDto;
}
However, in my case, I realized that logging validation errors in the service itself is not the proper place; I instead log these errors in the applications that consume the service.

Related

Azure App Service - Some WebAPI methods throw OWIN Exception

I have an Azure Mobile App that has some methods that generate 500 errors but does not record any exceptions in Application Insights and no exceptions are thrown inside my code. I have been able to determine that normal TableController methods work fine, but custom methods do not. Also, I can remote debug the code and watch it finish executing without any exceptions being thrown. It should also be noted that I did not have this problem when this project was a Mobile Service. Here is an example method that fails:
private readonly MobileServiceContext context; //Autofac injection
private readonly IUserHelper userHelper; //Autofac injection
[HttpGet, Route("api/Site/{id}/Users")]
public async Task<HttpResponseMessage> Users(string id)
{
var userId = await userHelper.GetUserIdAsync(User, Request);
var query = context.UserSiteMaps.Include(x => x.User).Where(map => map.SiteId == id);
var auth = query.FirstOrDefault(x => x.UserId == userId && x.IsAdmin);
if (auth != null)
{
return Request.CreateResponse(HttpStatusCode.OK, query.Select(map => map.User));
}
return Request.CreateUnauthorizedResponse();
}
The deepest error log that I have been able to obtain is the detailed error page from IIS:
Module __DynamicModule_Microsoft.Owin.Host.SystemWeb.OwinHttpModule, Microsoft.Owin.Host.SystemWeb, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35_9de2321b-e781-4017-8ff3-4acd1e48b129
Notification PreExecuteRequestHandler
Handler ExtensionlessUrlHandler-Integrated-4.0
Error Code
0x00000000
I haven't been able to generate a more detailed error message and I have no idea what Owin is upset about here since other method return requests just fine. Am I doing something I shouldn't?
Any help would be greatly appreciated!
Update : Here is the full error message that I have been able to get.
I have also been able to narrow the cause down a bit. If I replace the query.Select(map => map.User) object in the response with a simple string, it returns that string without complaint. However, if I stringify the response myself and pass that in, I get 500s again. Could it be some serializer setting problem?
The best way to track down the issue is to turn on exception stack traces for you app and to turn on logging on your Mobile App backend.
See Server Side Logging in the Mobile Apps wiki and Enable diagnostics logging for web apps in Azure App Service. You can also remote debug your service to see the exact error, see Remote debugging .NET server SDK.

ServiceStack Message via RabbitMq routing to verb other than POST

implementing service bus with servicestack and rabbitmq here.
Documentation states "each message will instead be executed by the best matching ServiceStack Service that handles the message with either a Post or Any fallback verb".
How then would I make the published message from the client route to PUT?
Thanks in advance for any suggestions or samples.
each message will instead be executed by the best matching ServiceStack Service that handles the message with either a Post or Any fallback verb"
This documentation says that messages are treated as POST requests, as such can only be handled with Post(Request) or Any(Request) handlers. This is the same as ServiceStack's SOAP Support where all SOAP request are POST's, which you can ensure is accessible by SOAP/MQ requests by maintaining separate Request DTO's (a common and recommended practice) and implementing them using Any() so they're still accessible by both PUT and POST requests, e.g:
[Route("/customers", "POST"]
public class CreateCustomer { ... }
[Route("/customers/{Id}", "PUT"]
public class UpdateCustomer { ... }
public class CustomerService : Service
{
public object Any(CreateCustomer request) { ... }
public object Any(UpdateCustomer request) { ... }
}
This service enables access to the service via POST /customers and PUT /customers/1 HTTP routes while still allowing them to be accessed via SOAP/MQ.

Accessing Request, Response, Service and Db Context, etc. in ServiceStack

In my previous project, I use a framework (Agatha RRSL) similar to ServiceStack, in that everything is made of Request, Response and Handler. It also has Interceptors that can attach to handler and you can inject other interfaces to the handler as well. I can use this to open a transaction BeforeHandling, access to both request and response in AfterHandling, create audit, save to database and close transaction if needed.
I try to experiment similar with SerivceStack. But seems with Filters, I can't grab request and response together?
With custom ServiceRunner. When I try to debug OnAfterExecute(...), I can see the name of my request dto in IRequestContext {ServiceStack.ServiceHost.HttpRequestContext}. But just the name, I couldn't figure out how to retrieve the actual request object to work with the response object.
Another thing I haven't figure out is if it's possible to inject the auto wired service interface into it, like a db context or audit service. Maybe this one is too far ahead in the pipeline?
The final thing is, it seems I can only register one custom service runner? With Interceptor, I can drop a bunch of them, and they will wrap around each other.
Any thoughts? Thanks
The RequestContext also contains the HttpRequest and HttpResponse which you can get access with:
var httpReq = RequestContext.Get<IHttpRequest>();
var httpRes = RequestContext.Get<IHttpResponse>();
See the docs on Accessing HTTP Specific features for more info.

Sending a GET request to the path given in the route

I am trying to call a REST service from a URL like this:
example.org/account/someusername
I have defined request and response DTOs.
[Route("/account/{UserName}", "GET")]
public class AccountRequest : IReturn<AccountResponse>
{
public string UserName { get; set; }
}
public class AccountResponse
{
public int Id { get; set; }
public string UserName { get; set; }
public string Bio { get; set; }
}
Calling the service:
JsonServiceClient client = new JsonServiceClient("http://example.org");
AccountRequest request = new AccountRequest { UserName = "me" };
AccountResponse response = client.Get(request);
However when I call the Get on the client, it doesn't respect the route. When I check the client instance in debugger, AsyncOneWayBaseUri value is example.org/json/asynconeway/. This part is irrelevant because it doesn't mean request is sent to this URL. I actually have no idea where it sends the request. I don't get any errors and all of my properties in response object is null.
What am I missing here?
Consume 3rd Party REST / HTTP Apis
ServiceStack's Service Clients are opinionated to call ServiceStack web services as they have support for ServiceStack's pre-defined routes, built-in Auth, auto-route generation, built-in Error Handling, etc.
To call 3rd Party REST / HTTP Apis you can use the HTTP Utils that come with ServiceStack.Text, which provide succinct, readable pleasant API's for common data access patterns around .NET's HttpWebRequest, e.g:
List<GithubRepo> repos = "https://api.github.com/users/{0}/repos".Fmt(user)
.GetJsonFromUrl()
.FromJson<List<GithubRepo>>();
Consuming ServiceStack services with C# .NET Service Clients
I'm not seeing the reported behavior, are you using the latest version of ServiceStack on the client?
One way to test the generated url that gets used (without making a service call) is to call the TRequest.ToUrl(method) extension method (that the Service Clients uss) directly, e.g.
AccountRequest request = new AccountRequest { UserName = "me" };
request.ToUrl("GET").Print(); // /account/me
The same auto-generated route was used when I tried calling it via the JsonServiceClient, e.g:
var client = new JsonServiceClient("http://example.org");
var response = client.Get(request); //calls http://example.org/account/me
Route URL used in ServiceStack's Service Clients
ServiceStack will attempt to use the most appropriate route that matches the values populated in the DTO and HTTP Method you're calling with, if there is no matching route it will fallback to the pre-defined routes.
By default the original predefined routes will be used:
/api/[xml|json|html|jsv|csv]/[syncreply|asynconeway]/[servicename]
But ServiceStack now also supports the shorter aliases of /reply and /oneway, e.g:
/api/[xml|json|html|jsv|csv]/[reply|oneway]/[servicename]
Which you can opt-in to use in the clients by setting the flag:
client.UseNewPredefinedRoutes = true;
it doesn't respect the route
Are you getting a 404 or a Handler not found exception?
Make sure whatever assembly your 'AccountService' class is in is added to the 'assembliesWithServices' parameter when configuring your AppHost. It sounds like the your Route is not being picked up by ServiceStack.
public MyAppHost() : base("my app", typeof(AccountService).Assembly) { }
What does your Service class look like?
Something like below should work (don't forget the Service interface)
public class AccountService : Service
{
public object Any(AccountRequest request)
{
return new AccountResponse() { UserName = request.UserName};
}
}
Servicestack supports a number of different data formats, such as JSON, XML, JSV, CSV, etc. and supports a number of different endpoints for accessing this data out of the box. Please find below details of the supported endpoints that has been taken from the formats section of the SS documentation.
The clients provided by ServiceStack use the default endpoint, not the restful endpoint to access the data. The data is still accessible restfully, you can test this by navigating to the restful URL in your browser.
Restful Endpoints
You can define which format should be used by adding ?format={format} to the end of the URL.
?format=json
?format=xml
?format=jsv
?format=csv
?format=htm
Example: http://www.servicestack.net/ServiceStack.Hello/servicestack/hello/World!?format=json
Alternatively ServiceStack also recognizes which format should be used with the Accept http header:
Accept: application/json
Accept: application/xml
As you can see, this approach only works with json and xml.
Default endpoint
/servicestack/[xml|json|html|jsv|csv]/[syncreply|asynconeway]/[servicename]
Examples:
/servicestack/xml/[syncreply|asynconeway]/[servicename] will be XML
/servicestack/json/[syncreply|asynconeway]/[servicename] will be JSON
SOAP endpoint
The SOAP endpoint only supports XML of course.
UPDATE
The ServiceStack clients cannot be used to connect to a non-ServiceStack web service because they rely on behavior which is specific to ServiceStack. Its probably best to use something like RestSharp or one of the many other available clients that allow you to interact with a restful web service.
Thanks everyone for their answers. C# client was sending the request to the right address from the start, I debugged it with Fiddler. Only I wasn't deserializing it properly.
Account object was in the data property of the response, not the response itself. The client is good at working with REST services even if they are not built with ServiceStack. It is pretty cool.

ServiceStack.Razor CustomHttpHandler not displaying for HttpStatusCode.BadRequest

I'm trying to get a minimal app working using ServiceStack.Razor, and I'm having trouble getting a CustomHttpHandler to work. I've followed the instructions here and here, but it's not working right.
I'm using the following code to register a custom http handler for HttpStatusCode.BadRequest:
public override void Configure(Container container)
{
this.Plugins.Add(new RazorFormat());
this.SetConfig(new EndpointHostConfig
{
CustomHttpHandlers =
{
{ HttpStatusCode.NotFound, new RazorHandler("/notfound") },
{ HttpStatusCode.BadRequest, new RazorHandler("/error") }
},
DebugMode = true
});
}
The thing is, the /notfound handler works perfectly for 404s, but no matter what I do, I can't get the /error razor file to display whenever an ArgumentNullException is thrown.
My service method looks like this:
public object Any(Hello request)
{
if (string.IsNullOrEmpty(request.Name))
{
throw new ArgumentNullException("Name");
}
return new HelloResponse { Result = "Hello " + request.Name };
}
ServiceStack returns a 400 status, which is fine, but it still displays the view I have for HelloResponse:
What am I missing? Am I misunderstanding how CustomHttpHandlers are supposed to work?
For reference, I put the project up on github.
Yeah the CustomHttpHandlers are just meant for handling un-handled system generated errors. Currently they're limited to:
NotFound (404) for un-handled requests
Forbidden (403) when a request is made to an forbidden file or resource
These are the errors happen outside of ServiceStack and so isn't able to be handled by existing ServiceStack's event hooks or user-defined custom logic, so we allow users to modify the behavior in this case via CustomHttpHandlers.
The Error Handling wiki describes how to handle errors in ServiceStack.
Though it might make sense (since it's opt-in) to allow a fallback after the exception is handled to allow it to be further handled by rendering it to a user-specified page, that you're expecting to do here.
We'll look at trying to explore something like this in the future. Feel free to add future feature requests like these to ServiceStack's issue list so we don't forget.

Resources