4

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?

dawebber
  • 3,503
  • 1
  • 16
  • 16

1 Answers1

3

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; } 
}
mythz
  • 141,670
  • 29
  • 246
  • 390
  • thank you for a very detailed response and great advice. One small comment--in my case I was using POST instead of GET as indicated in the question, and was inheriting from ServiceBase, overriding the Run method, so just to adjust your code sample on getting the value outside of the DTO, I'd have to do `var enumStr = base.RequestContext.Get().FormData["FormElementName"]` This is just to help others trying to do the same thing. Good to know about this feature of SS. – dawebber Nov 20 '11 at 04:19