rest - ServiceStack deserialization of JSON content in multipart/form-data request -
i'm creating restful service using servicestack should consume post multipart/form-data content. content in json format, when send post, object not deserialized correctly (all properties null/default values). if try sending object regular post (without multipart/form-data), deserializes fine.
i poked around in servicestack code try figure out going on, , current understanding:
- httplistenerrequestwrapper::loadmultipart() loading multipart request , saving (non-file) parts "formdata", maps name of part contents. however, appears content-type (which correctly written httpmultipart::element individual sections being parsed) lost because isn't stored in anywhere.
- some time later in control-flow, endpointhandlerbase::deserializehttprequest() calls keyvaluedatacontractdeserializer.instance.parse() formdata , type deserialize to.
- if first time kind of object being deserialized, stringmaptypedeserializer created type , cached typestringmapserializermap. each property of type, call jsvreader.getparsefn() parsestringdelegate parse deserialize property.
- the created/cached stringmaptypedeserializer used deserialize object, using "parsefn's" set earlier... treat content jsv format.
i confirmed jsvreader.parsefncache has bunch of types in it, while jsonreader.parsefncache empty. also, if change request remove quotes (i.e. turn json jsv format), deserializes correctly. 1 weird thing 1 of properties of object dictionary, , deserializes correctly, when it's in json format; i'm assuming fortunate coincidence (?!?).
am correct in understanding of what's going on here? known limitation in servicestack? bug? there anyway work around other putting object in file , manually calling jsonserializer.deserializefromstream()?
thanks!
jps
also, incase it's useful, here's relevant request , data-objects:
post /api/task http/1.1 accept: application/json content-type: multipart/form-data; boundary=boundary_1_1161035867_1375890821794 mime-version: 1.0 host: localhost:12345 content-length: 385 --boundary_1_1161035867_1375890821794 content-type: application/json content-disposition: form-data; name="mymap" {"myfile.dat":"importantfile"} --boundary_1_1161035867_1375890821794 content-disposition: form-data; name="mything" content-type: application/json {"id":123,"name":"myteststring"} --boundary_1_1161035867_1375890821794 content-type: application/octet-stream content-disposition: form-data; filename="myfile.dat" mydatagoeshere... --boundary_1_1161035867_1375890821794--
.
public class testobj { public long id { get; set; } public string name { get; set; } } [route("/task", "post")] public class taskrequest : authenticatedrequest, ireturn<taskresponse> { public testobj mything { get; set; } public dictionary<string, string> mymap { get; set; } }
have tried setting properties of request object using 'apimember' attribute? in particular 'parametertype' properties.
/// <summary> /// create , upload new video. /// </summary> [api("create , upload new video.")] [route("/videos", "post", summary = @"create , upload new video.", notes = "video file / attachment must uploaded using post , 'multipart/form-data' encoding.")] public class createvideo : operationbase<ivideo> { /// <summary> /// gets or sets video title. /// </summary> [apimember(name = "title", allowmultiple = false, datatype = "string", description = "video title. required, between 8 , 128 characters.", isrequired = true, parametertype = "form")] public string title { get; set; } /// <summary> /// gets or sets video description. /// </summary> [apimember(name = "description", allowmultiple = false, datatype = "string", description = "video description.", parametertype = "form")] public string description { get; set; } /// <summary> /// gets or sets publish date. /// </summary> /// <remarks> /// if blank, video published immediately. /// </remarks> [apimember(name = "publishdate", allowmultiple = false, datatype = "date", description = "publish date. if blank, video published immediately.", parametertype = "form")] public datetime? publishdate { get; set; } }
Comments
Post a Comment