Handling Serialization Exceptions in ServiceStack - servicestack

I am using ServiceStack to create a service which accepts request from and HTML form (POSTed). One of the DTO properties is an Enum, and when the input doesn't match the Enum members, I get the following exception:
Error occured while Processing Request: KeyValueDataContractDeserializer: Error converting to type: Requested value 'MyValue' was not found.
System.Runtime.Serialization.SerializationException: KeyValueDataContractDeserializer: Error converting to type: Requested value 'MyValue' was not found. ---> System.ArgumentException: Requested value 'MyValue' was not found.
at System.Enum.TryParseEnum(Type enumType, String value, Boolean ignoreCase, EnumResult& parseResult)
at System.Enum.Parse(Type enumType, String value, Boolean ignoreCase)
at ServiceStack.ServiceModel.Serialization.StringMapTypeDeserializer.PopulateFromMap(Object instance, IDictionary`2 keyValuePairs)
How can I intercept this exception and handle it myself in my service code?

There are a couple of ways to handle this situation:
You can make the DTO Enum property a string (since everything can successfully deserialize into a string :) and then convert that yourself manually i.e.
using ServiceStack.Common; //ToEnum<> is an extension method
public class RequestDto
{
public string EnumString { get; set; }
}
public override object OnGet(RequestDto request)
{
MyEnum defaultValue = MyEnum.None;
try {
defaultValue = request.EnumString.ToEnum<MyEnum>();
} catch {}
}
The other alternative is to completely remove it from the request DTO and get value manually from the IHttpRequest Context like:
public class RequestDto {}
public override object OnGet(RequestDto request)
{
MyEnum enumValue = MyEnum.DefaultValue;
try {
var enumStr = base.RequestContext.Get<IHttpRequest>().QueryString["EnumString"];
enumValue = enumStr.ToEnum<MyEnum>();
} catch {}
}
I generally discourage the use of enums on DTOs for many reasons, the primary one being on XML/SOAP endpoints the XSD treats them as a restricted set of values which is a pain in when trying iteratively to evolve your web services as you will need to re-gen the clients to add a new value.
By convention the way I deal with it is to have all enums as strings but provide some metadata on the DTO which points to the target type (which helps in VS.NET/R# navigation and metadata tools).
public class RequestDto
{
[References(typeof(MyEnum))]
public string EnumString { get; set; }
}

Related

How to make Servicestack serialize an implicit string overload the way I want it to?

I have a small class which I am using to make sure the strings sent and received by a service remain URL safe without additional encoding (see below).
Ideally I would like to just apply this type to my DTOs and have Servicestack be smart enough to use the implicit operators.
public class MyDto {
Base64UrlString myString;
}
var dto = new MyDto() { myString = "hello i am url safe"; }
On the client this is received as myString: {}
Is there a more elegant way to do this? I had hoped applying a type this way would "just work"
// used only for Base64UrlEncoder
using Microsoft.IdentityModel.Tokens;
namespace MyDto.ServiceModel.Types
{
public class Base64UrlString
{
private readonly string _base64UrlString;
public Base64UrlString(string str)
{
_base64UrlString = Base64UrlEncoder.Encode(str);
}
public static implicit operator string(Base64UrlString base64UrlString) => base64UrlString.ToString();
public static implicit operator Base64UrlString(string str) => new(str);
public override string ToString() => Base64UrlEncoder.Decode(_base64UrlString);
}
}
You'll need to change your class to a struct to make use of the custom struct behavior you're trying to use in your example.
Also ServiceStack.Text serializers only serializes public properties by default so your DTO should use public properties:
public class MyDto {
public Base64UrlString MyString { get; set; }
}
Alternatively you can configure it to serialize public fields with:
JsConfig.Init(new Config {
IncludePublicFields = true
});

Change Autoquery return type in DTO generation

I want to return a custom class from my custom AutoQuery endpoint that inherits QueryResponse<T> but adds a few extra properties.
public class WritingAssignmentBlogLookUpResponse : QueryResponse<BlogDto>, IResponse
{
public bool Success { get; set; }
public string Message { get; set; }
public string DebugMessage { get; set; }
}
But if I specify request like so:
[Route("/assignment/blogs/", "POST")]
public class WritingAssignmentBlogsLookUpRequest : QueryDb<Blog, BlogDto>, IReturn<WritingAssignmentBlogLookUpResponse>
{
}
Then the return type specified in generatd DTO for client.post(req) is QueryResponse<BlogDto> and it doesn't generate WritingAssignmentBlogLookUpResponse at all.
Do I just have to specify return type as any from my typescript service or is there a way to make the types match so I can strongly type it?
You can’t change AutoQuery responses which are already fixed in their service contract definition to return a QueryResponse<T>.
You can add extra info to the Meta Dictionary of the Response DTO (exists for this reason) otherwise if you need to change the Service Contract you’d need to convert it into a normal (I.e. non-AutoQuery) API which could use the Service Gateway to call an existing AutoQuery API that decorates the response.

Service Stack IRequiresHttpRequest Pattern

How does this work? I've read the docs but am hoping for some more info.
From reading the docs I understand that when my DTO implements IRequiresHttpRequest, then the DTO's properties will not get automatically populated, but in my DTO I now have access to the HttpRequest object so I can change my DTO to have 'get' properties that pull things from the request object.
What is meant to inject the HttpRequest into my DTO? The docs suggest that service stack does this behind the scenes, however I can only get it to work if I register a custom request binder and manually inject the HttpRequest object.
RequestBinders.Add(typeof(MyDto), httpReq => {
var dto = new MyDto();
dto.HttpRequest = httpReq;
return dto;
});
Question 1: How exactly is the injection for IRequiresHttpRequest meant to work?
Question 2: Is there a way to gain access to the HttpRequest object so that my DTO can support custom 'get' properties, by still have service stack run it automatic mapping? For example:
public class MyDto
: IRequiresHttpRequest
{
public Int32 AutoMappedProperty1 { get; set; }
public Int32 AutoMappedProperty2 { get; set; }
public Int32 AutoMappedProperty3 { get; set; }
public Int32 AutoMappedProperty4 { get; set; }
public Int32 CustomMappedProperty { get { return customMappedProperty; } }
IHttpRequest httpRequest;
public IHttpRequest HttpRequest
{
get
{
return httpRequest;
}
set
{
httpRequest = value;
// lets say this searches the query string for a variety of
// different keys, and then maps one of them of
// CustomMappedProperty based upon a specific set of rules
customMappedProperty = [...]
}
}
}
In the case above I am defining how CustomMappedProperty gets populated, but I still want service stack to go ahead and map all of the 'set'-able properties. Is there a way to achieve this? Can I manually invoke the service stack dto mapper?
Which docs did you read about IRequiresHttpRequest? IRequiresHttpRequest works the same as IRequiresRequestContext which is only for decorating on Services and Validators to tell ServiceStack that it requires access and to inject the current IHttpRequest or IRequestContext.
The Custom Serialization / Deserialization wiki only mentions that IRequiresRequestStream and IRequiresSoapMessage can be used on Request DTOs to signal to ServiceStack to skip processing the Request body and allow you to manually deserialize the request yourself.

ServiceStack and dynamic properties in request DTOs

I would like to post a JSON object to my service stack service and use a dynamic property in the request DTO. All approaches I have tried so far leave the object being a NULL value.
The javascript code I use:
$.getJSON(
"/api/json/reply/Hello",
{
Name: "Murphy",
Laws: {
SomeProp: "A list of my laws",
SomeArr: [
{ Title: "First law" },
{ Title: "Second law" },
{ Title: "Third law" }
]
}
},
function(data) {
alert(data.result);
}
);
The DTO to receive the request:
public class Hello
{
public string Name { get; set; }
public dynamic Laws { get; set; }
}
I also tried to use an object and JsonObject instead of dynamic in the DTO.
To be complete, here's the service too:
public class HelloService : Service
{
public object Any(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
Murphy comes through in the Name property without any problems, but the Laws property remains NULL.
In the end, I want to somehow iterate (using reflection?) over the Laws property and get all the contained properties and values.
I cannot use a typed DTO here, because I don't know the JSON of the Laws property at development time (and it can change quite frequently).
Thanks for any help!
The .NET 3.5 library builds of ServiceStack on NuGet doesn't have native support for the .NET 4.0+ dynamic type. You can pass JSON into a string property and dynamically parse it on the server:
public object Any(Hello request)
{
var laws = JsonObject.Parse(request.Laws);
laws["SomeProp"] //
laws.ArrayObjects("SomeArr") //
}
Otherwise You can use Dictionary<string,string> or if you specify in your AppHost:
JsConfig.ConvertObjectTypesIntoStringDictionary = true;
You can use object which will treat objects like a string dictionary.
Otherwise dynamic shouldn't be on the DTO as it's meaningless as to what the service expects. You could just add it to the QueryString. You can use the JSV Format to specify complex object graphs in the QueryString, e.g:
/hello?laws={SomeProp:A list of my laws,SomeArr:[{Title:First Law}]}
Note: the spaces above gets encoded with %20 on the wire.
Which you can access in your services with:
public object Any(Hello request)
{
var laws = base.QueryString["laws"].FromJsv<SomeTypeMatchingJsvSent>();
}

servicestack text, json deserialization Index was outside the bounds of the array exception

i was diagnosing an issue where i had json or jsv objects being received in web form or query variables and was getting an Index was outside the bounds of the array exception being thrown by servicestack. This is a rest client in another product sending this to my servicestack rest services.
I narrowed it down to de-serializing a form variable with an empty string as the value instead of json.
this is a simple test case that does the same thing. I would have expected null being returned?
v3.9.26 servicestack.text
`
class simpleDTO {
public string FirstName { get; set; }
public string LastName { get; set; }
}
[TestMethod]
public void TestMethod1()
{
var json = "";
var o = JsonSerializer.DeserializeFromString(json, typeof(simpleDTO));
Assert.IsNull(o);
}`
That issue was fixed in this commit: 6ea6f235dc and should be included in the next ServiceStack.Text release.

Resources