Request DTO map all empty string properties to null value

What is the recommended way to map all request DTO string properties that are empty to a null value?

The RequestConverter approach is unsuitable, because ServiceStack’s PopulateInstance() ignores null values.

https://forums.servicestack.net/t/intercept-autocrud-create-update-to-trim-all-requestdtos-strings/9268/4

You should still be able to do this with the available Reflection Utils. Something like converting the Request DTO to an Object Dictionary with dto.ToObjectDictionary(), iterating all the properties to find empty strings than using the Property Accessors to update string.Empty property values to null.

Is there any example showing this approach?

For example, my requestDto is an object, not a specific type, so it is not clear how I can use the Property Accessors to set an identified property containing an empty string.

The docs contains an example of accessing and using property accessors of a runtime type:

var runtimeType = dto.GetType();

var typeProps = TypeProperties.Get(runtimeType); //Equivalent to:
//  typeProps = TypeProperties<MyType>.Instance;
 
var propAccessor = typeProps.GetAccessor("Id");
propAccessor.PublicSetter(dto, 1);
var idValue = propAccessor.PublicGetter(dto);

Thank you, I solved it as follows:

    private void ConfigureRequestConverters()
    {
        // convert empty strings to null
        RequestConverters.Add((req, requestDto) =>
        {
            var updateMap = new Dictionary<string, object?>();
            requestDto.ToObjectDictionary().ForEach((key, value) =>
            {
                if (value is string strValue && String.IsNullOrWhiteSpace(strValue))
                {
                    updateMap[key] = null;
                }
            });

            if (updateMap.Count > 0)
            {
                foreach(KeyValuePair<string, object?> entry in updateMap)
                {
                    var runtimeType = requestDto.GetType();
                    var typeProps = TypeProperties.Get(runtimeType);
                    var propAccessor = typeProps.GetAccessor(entry.Key);
                    propAccessor.PublicSetter(requestDto, entry.Value);
                }
            }

            return Task.FromResult(requestDto);
        });
    }
1 Like