MessagePack Custom Error DTO without ServiceStack.Client

Hi!

I’ve been trying to Deserialize the error object on the client (Unity game engine), where I can’t use ServiceStack.Client (because Unity is using .net 2).

I’m using
throw new HttpError(HttpStatusCode.Forbidden) { Response = new HttpErrorResponse() { Message = "Test error" } };)

So I looked into Custom Exceptions and returning my own DTO to represent the error, but it looks like I can only do that if my DTO has a member called ResponseStatus of type ServiceStack.ResponseStatus. If I don’t include that, my object seems to get ignored. (Same thing happens if I use JSON for the content type, my object seems to be ignored and just the default ResponseStatus is returned)

Since I can’t use that exact object, I tried cloning it in my client library but I can’t seem to match it close enough to be able to properly decode the object.

Is there a way that I can return my own DTO without relying on any types from ServiceStack so that I can decode them in my client library that doesn’t use ServiceStack?

The only dependency your Service Models need is ServiceStack.Interfaces which is a portable library that supports multiple .NET platforms:

.NET 4.5, Silverlight 5, Windows 8, Windows Phone 8.1, Windows Phone Silverlight 8, Xamarin.Android, Xamarin.iOS, Xamarin.iOS (classic)

If you’re trying to reuse these DTOs in a non-supported .NET platform you’re going to be extremely limited since you’re not going to be able to use many of the other data annotations like IReturn<T> which simplifies the usability of your Services.

Most serializers don’t rely on exact types so you could just take a copy of the ResponseStatus DTO:

namespace ServiceStack
{
    [DataContract]
    public class ResponseStatus 
    {
        [DataMember(Order = 1)]
        public string ErrorCode { get; set; }
        [DataMember(Order = 2)]
        public string Message { get; set; }
        [DataMember(Order = 3)]
        public string StackTrace { get; set; }
        [DataMember(Order = 4)]
        public List<ResponseError> Errors { get; set; }
        [DataMember(Order = 5)]
        public Dictionary<string, string> Meta { get; set; }
    }

    [DataContract]
    public class ResponseError 
    {
        [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 1)]
        public string ErrorCode { get; set; }
        [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 2)]
        public string FieldName { get; set; }
        [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 3)]
        public string Message { get; set; }
        [DataMember(IsRequired = false, EmitDefaultValue = false, Order = 4)]
        public Dictionary<string, string> Meta { get; set; }
    }

    [DataContract] //Structured Error Responses can be deserialized in this DTO
    public class ErrorResponse 
    {
        [DataMember(Order = 1)]
        public ResponseStatus ResponseStatus { get; set; }
    }
}

And instead of trying to reuse your ServiceModel.dll, use the C# Add ServiceStack Reference feature to download a source copy of your server DTOs and compile it on your platform which will make use your local copies for any missing Types, e.g. ResponseStatus, ResponseError. If you’re not using a major IDE we have integration for you can use our ssutil.exe command line utility to download your Server DTOs, e.g:

ssutil http://example.org -file MyDtos -lang CSharp

Or just go to /types/csharp on your Server in a browser and save the generated C# DTOs.

This would be the recommended option since you’re not limiting your Service to not have the ServiceStack.Interfaces dependency.

Thanks for the tips!

Unfortunately when I attempt to add ServiceStack.Interfaces I’m presented with:
Error Could not install package 'ServiceStack.Interfaces 4.5.4'. You are trying to install this package into a project that targets '.NETFramework,Version=v3.5', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author. 0

The info about /types/csharp is great, I didn’t know about that. Instead I have my own Library where I’ve got all my model, request and response data that I share between Unity and the Server. I just have to be wary of the dependencies.

I’ll try copying again. I removed the DataMember stuff because my shared library doesn’t have those dependencies, but I have a few ideas now to see if I can get around that and recreate the class member order exactly, as I’m assuming that might be the problem.

My only other alternative that I can think of is to just have a property of the Response that signals an error and have my client look for that and not be able to rely on exception handling on the server.

Thanks for the details information!

1 Like

I seem to be having some difficulty with the custom response object when just following the help docs.

For example I’m using the following error object:

[DataContract] //Structured Error Responses can be deserialized in this DTO
public class ErrorResponse
{
	[DataMember(Order = 1)]
	public ServiceStack.ResponseStatus ResponseStatus { get; set; }
	[DataMember(Order = 2)]
	public string MyTestResponse { get; set; }
}

And then I’m using:


throw new HttpError(HttpStatusCode.Forbidden, "Oh no") { Response = new ErrorResponse() { MyTestResponse = "SADFASDF" } };

But when I view the response I don’t see MyTestResponse at all. Instead I see:

{
  "ResponseStatus": {
    "ErrorCode": "Forbidden",
    "Message": "Oh noy",
    "StackTrace": "[ServerConfigRequest: 10/12/2016 6:55:20 AM]:\n[REQUEST: {ClientVersion:0}]\nServiceStack.HttpError: Oh no\r\n   at GameServer.ServiceInterface.GameServices.Any(ServerConfigRequest request) in GameServices.cs:line 177\r\n   at lambda_method(Closure , Object , Object )\r\n   at ServiceStack.Host.ServiceRunner`1.Execute(IRequest request, Object instance, TRequest requestDto)",
    "Errors": []
  }
}

I’m using ServiceStack 4.5.4. What am I doing wrong?

Structured Error Responses are populated in a predictable ResponseStatus property or returned in a generic ErrorResponse DTO. This is needed in order for ServiceClients to be able to parse errors in each language and convert them into a Local Exception.

If you want to skip ServiceStack’s auto error handling, you’ll need to write it directly to the response yourself, e.g:

GlobalResponseFilters.Add((req, res, response) =>
{
    var ex = response as IHttpError;
    if (ex != null)
    {
        res.StatusCode = ex.Status;
        ex.StatusDescription = ex.StatusDescription;
        res.WriteToResponse(ex.Response, req.ResponseContentType);
    }
});

Note overriding the built-in Error Handling will prevent it working in ServiceStack’s different Service Clients.

Ah awesome, okay that gives me a lot to work with, I’ll have a play and see what I come up with.

I was able to overcome that limitation by having a base class request object in the shared library without implementing IReturn and then having another class in my ServiceModel that derives from that class and implements IReturn.

For example:

[DataContract]
public class ConfigRequest
{
	[DataMember(Order = 1)]
	public uint ClientVersion { get; set; }
}

[Route("/config")]
public class ServerConfigRequest : ConfigRequest, IReturn<ConfigResponse>
{
}

public ConfigResponse Any(ServerConfigRequest request)
{
	...
}