Could not deserialize 'application/xml' bug or something else?

Hi,
First time posting here.

Recently our app has been connected via API/SOAP with WSDL (Servicestack.Service) to a customer that makes lots of requests (for us at least 50k/hour) to our API.

Since then, we’ve started getting an error trying to deserialize the XML they send. This is ServiceStack 5.4.0, under NET4.7.1

I tried the same request using a simple load testing app and above 10 simultaneous requests, I see the same error.

What I’m not sure is, if it’s a NET issue, a ServiceStack issue, a configuration issue.

This is the trace for the error:

{"ClassName":"System.Runtime.Serialization.SerializationException","Message":"Could not deserialize 'application/xml' request using te_webservices.hotels_search_v2'\nError: System.Runtime.Serialization.SerializationException: There was an error deserializing the object of type te_webservices.hotels_search_v2. Start element 'hotels_search_v2' does not match end element 'hotels_search_vX-'. Line 1, position 200. ---> System.Xml.XmlException: Start element 'hotels_search_v2' does not match end element 'hotels_search_vX-'. Line 1, position 200.\r\n   at System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, String res, String arg1, String arg2, String arg3)\r\n   at System.Xml.XmlUTF8TextReader.ReadEndElement()\r\n   at System.Xml.XmlUTF8TextReader.Read()\r\n   at System.Runtime.Serialization.CollectionDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)\r\n   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 id, RuntimeTypeHandle declaredTypeHandle, String name, String ns)\r\n   at Readhotels_search_v2FromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )\r\n   at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)\r\n   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)\r\n   at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName, DataContractResolver dataContractResolver)\r\n   at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)\r\n   --- End of inner exception stack trace ---\r\n   at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)\r\n   at System.Runtime.Serialization.XmlObjectSerializer.ReadObject(XmlDictionaryReader reader)\r\n   at ServiceStack.Host.ContentTypes.<>c__DisplayClass35_0.<GetStreamDeserializerAsync>b__0(Type type, Stream stream)\r\n   at ServiceStack.Host.Handlers.ServiceStackHandlerBase.CreateContentTypeRequestAsync(IRequest httpReq, Type requestType, String contentType)","Data":null,"InnerException":{"ClassName":"System.Runtime.Serialization.SerializationException","Message":"There was an error deserializing the object of type te_webservices.hotels_search_v2. Start element 'hotels_search_v2' does not match end element 'hotels_search_vX-'. Line 1, position 200.","Data":null,"InnerException":{"ClassName":"System.Xml.XmlException","Message":"Start element 'hotels_search_v2' does not match end element 'hotels_search_vX-'. Line 1, position 200.","Data":null,"InnerException":null,"HelpURL":null,"StackTraceString":"   at System.Xml.XmlExceptionHelper.ThrowXmlException(XmlDictionaryReader reader, String res, String arg1, String arg2, String arg3)\r\n   at System.Xml.XmlUTF8TextReader.ReadEndElement()\r\n   at System.Xml.XmlUTF8TextReader.Read()\r\n   at System.Runtime.Serialization.CollectionDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)\r\n   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Int32 id, RuntimeTypeHandle declaredTypeHandle, String name, String ns)\r\n   at Readhotels_search_v2FromXml(XmlReaderDelegator , XmlObjectSerializerReadContext , XmlDictionaryString[] , XmlDictionaryString[] )\r\n   at System.Runtime.Serialization.ClassDataContract.ReadXmlValue(XmlReaderDelegator xmlReader, XmlObjectSerializerReadContext context)\r\n   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator reader, String name, String ns, Type declaredType, DataContract& dataContract)\r\n   at System.Runtime.Serialization.XmlObjectSerializerReadContext.InternalDeserialize(XmlReaderDelegator xmlReader, Type declaredType, DataContract dataContract, String name, String ns)\r\n   at System.Runtime.Serialization.DataContractSerializer.InternalReadObject(XmlReaderDelegator xmlReader, Boolean verifyObjectName, DataContractResolver dataContractResolver)\r\n   at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":"8\nThrowXmlException\nSystem.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\nSystem.Xml.XmlExceptionHelper\nVoid ThrowXmlException(System.Xml.XmlDictionaryReader, System.String, System.String, System.String, System.String)","HResult":-2146232000,"Source":"System.Runtime.Serialization","WatsonBuckets":null,"res":"Xml_UserException","args":["Start element 'hotels_search_v2' does not match end element 'hotels_search_vX-'. Line 1, position 200."],"lineNumber":0,"linePosition":0,"sourceUri":null,"version":"2.0"},"HelpURL":null,"StackTraceString":"   at System.Runtime.Serialization.XmlObjectSerializer.ReadObjectHandleExceptions(XmlReaderDelegator reader, Boolean verifyObjectName, DataContractResolver dataContractResolver)\r\n   at System.Runtime.Serialization.XmlObjectSerializer.ReadObject(XmlDictionaryReader reader)\r\n   at ServiceStack.Host.ContentTypes.<>c__DisplayClass35_0.<GetStreamDeserializerAsync>b__0(Type type, Stream stream)\r\n   at ServiceStack.Host.Handlers.ServiceStackHandlerBase.CreateContentTypeRequestAsync(IRequest httpReq, Type requestType, String contentType)","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":"8\nReadObjectHandleExceptions\nSystem.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\nSystem.Runtime.Serialization.XmlObjectSerializer\nSystem.Object ReadObjectHandleExceptions(System.Runtime.Serialization.XmlReaderDelegator, Boolean, System.Runtime.Serialization.DataContractResolver)","HResult":-2146233076,"Source":"System.Runtime.Serialization","WatsonBuckets":null},"HelpURL":null,"StackTraceString":"   at ServiceStack.Host.Handlers.ServiceStackHandlerBase.CreateContentTypeRequestAsync(IRequest httpReq, Type requestType, String contentType)\r\n   at ServiceStack.Host.RestHandler.<CreateRequestAsync>d__16.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at ServiceStack.Host.RestHandler.<CreateRequestAsync>d__15.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at ServiceStack.Host.RestHandler.<ProcessRequestAsync>d__14.MoveNext()","RemoteStackTraceString":null,"RemoteStackIndex":0,"ExceptionMethod":"8\nCreateContentTypeRequestAsync\nServiceStack, Version=5.0.0.0, Culture=neutral, PublicKeyToken=02c12cbda47e6587\nServiceStack.Host.Handlers.ServiceStackHandlerBase\nSystem.Threading.Tasks.Task`1[System.Object] CreateContentTypeRequestAsync(ServiceStack.Web.IRequest, System.Type, System.String)","HResult":-2146233076,"Source":"ServiceStack","WatsonBuckets":null}

What confuses me the most, is the error we get: Start element ‘hotels_search_v2’ does not match end element ‘hotels_search_vX-’,

The XML that’s sent is the following:

<?xml version="1.0" encoding="utf-8"?><hotels_search_v2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.datacontract.org/2004/07/te_webservices"><timeoutMilliseconds>0</timeoutMilliseconds><optionsQuota>0</optionsQuota><checkin_date>2019-04-06</checkin_date><checkout_date>2019-04-07</checkout_date><destination_id>MzM%3D_MjM0MTQ%3D</destination_id><destination_type>4</destination_type><nationality_code>US</nationality_code><rooms><hotels_search_room_v2><adults>2</adults><children>0</children></hotels_search_room_v2></rooms></hotels_search_v2>

So, there is no ‘hotels_search_vX-’.

This is how the service is configured:

Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");
            Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");

            ServiceStack.Text.JsConfig.EmitCamelCaseNames = false;
            ServiceStack.Text.JsConfig.DateHandler = ServiceStack.Text.DateHandler.ISO8601; 

            Plugins.Add(new CorsFeature(
                allowOriginWhitelist: new List<string>() { "http://localhost:2093", "http://localhost:3000" },
                allowCredentials: true,
                allowedHeaders: "Content-Type, Allow, Authorization, ss-id, Origin, Accept, Access-Control-Request-Method"
            ));

            container.Register<IRedisClientsManager>(c =>new RedisManagerPool(travtion.generic.setting.api.redis_cache_connection_string));

            container.Register(c => c.Resolve<IRedisClientsManager>().GetCacheClient());

            // solo requestlog y postman en desarrollo
            if (travtion.generic.setting.system.is_debug)
            {
                Plugins.Add(new PostmanFeature());
                Plugins.Add(new RequestLogsFeature
                {
                    EnableSessionTracking = true,
                    RequiredRoles = null,
                });
            }

            //this.GetPlugin<PostmanFeature>();

            SetConfig(new HostConfig
            {
                WsdlServiceNamespace = "http://api.travtion.com/v1",
                DefaultContentType = MimeTypes.Json,
                HandlerFactoryPath = "/api"
            });

            Plugins.Add(new SoapFormat());

            SuppressFormsAuthenticationRedirectModule.PathToSupress = Config.HandlerFactoryPath;


            //Handle Exceptions occurring in Services:
            ServiceExceptionHandlers.Add((httpReq, request, exception) =>
            {
                //log your exceptions here
                travtion.generic.function.logging_engine.log_errors(exception);
                //call default exception handler or prepare your own custom response
                return DtoUtils.CreateErrorResponse(request, exception);
            });

            //Handle Unhandled Exceptions occurring outside of Services
            //E.g. Exceptions during Request binding or in filters:
            UncaughtExceptionHandlers.Add((req, res, operationName, ex) =>
            {
                travtion.generic.function.logging_engine.log_errors(ex);

                res.WriteAsync("Error: {0}: {1}".Fmt(ex.GetType().Name, ex.Message));
                res.EndRequest(skipHeaders: true);
            });


            AuthFeature authFeature = new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] { new api_authprovider(), new api_authprovider_basic() }, null);
            authFeature.IncludeAssignRoleServices = false;
            authFeature.HtmlRedirect = null;
            Plugins.Add(authFeature);


            container.Register<ICacheClient>(c =>
                       (ICacheClient)c.Resolve<IRedisClientsManager>()
                       .GetCacheClient())
                       .ReusedWithin(Funq.ReuseScope.None);

Any help will be greatly appreciated.

Regards!

ServiceStack uses .NET Xml DataContract Serializer under the hood so a good way to inspect the issue is to try manually deserializing the XML in .NET’s DataContractSerializer.

Can you provide the full HTTP Raw Request/Response Headers (using something like Fiddler) and provide all C# DTOs used in this request that’s failing.

Hi Mythz,

I do have the headers they are as follows:

Content-Type: application/xml
Accept-Encoding: gzip, deflate
Authorization: Basic ......
Accept: application/xml
Expect: 100-continue

DTO:

    [DataContract]
    [Authenticate]
    [Route("/hotels_v2/search", "POST")]
    [RequiredRole("front")]
    public class hotels_search_v2 : IReturn<hotels_search_v2Response>
    {
        [DataMember]
        [ApiMember(DataType = "string", IsRequired = true)]
        public string destination_id { get; set; }

        [DataMember]
        [ApiMember(DataType = "long", IsRequired = true)]
        public long destination_type { get; set; }

        [DataMember]
        [ApiMember(DataType = "dateTime", IsRequired = true)]
        public DateTime checkin_date { get; set; }

        [DataMember]
        [ApiMember(DataType = "dateTime", IsRequired = true)]
        public DateTime checkout_date { get; set; }

        [DataMember]
        [ApiMember(DataType = "List<hotels_search_room_v2>", IsRequired = true)]
        public List<hotels_search_room_v2> rooms { get; set; }

        [DataMember]
        [ApiMember(DataType = "string", IsRequired = true)]
        public string nationality_code { get; set; }
    }

    [DataContract]
    public class hotels_search_room_v2
    {
        [DataMember]
        [ApiMember(DataType = "int", IsRequired = true)]
        public int adults { get; set; }

        [DataMember]
        [ApiMember(DataType = "int", IsRequired = true)]
        public int children { get; set; }

        [DataMember]
        [ApiMember(IsRequired = false)]
        public int[] children_ages { get; set; }
    }

    [DataContract]
    public class hotels_search_v2Response : IHasResponseStatus
    {
        [DataMember]
        public string search_string { get; set; }

        [DataMember]
        public long search_total_results { get; set; }

        [DataMember]
        public List<ws_hotel_v2> hotels { get; set; }

        [DataMember]
        public ResponseStatus ResponseStatus { get; set; }
    }

    [DataContract]
    public class ws_hotel_v2
    {
        [DataMember]
        public string name { get; set; }

        [DataMember]
        public string hotel_id { get; set; }

        [DataMember]
        public bool important { get; set; }

        [DataMember]
        public List<ws_room_v2> rooms { get; set; }
    }

    [DataContract]
    public class ws_room_v2
    {
        [DataMember]
        public string name { get; set; }

        [DataMember]
        public string rate_name { get; set; }

        [DataMember]
        public string image { get; set; }

        [DataMember]
        public string promo_code { get; set; }

        [DataMember]
        public ws_price_v2 price { get; set; }

        [DataMember]
        public string status { get; set; }

        [DataMember]
        public long[] amenities { get; set; }

        [DataMember]
        public long[] accesibilites { get; set; }

        [DataMember]
        public List<ws_description_v2> descriptions { get; set; }

        [DataMember]
        public List<ws_policy_v2> policies { get; set; }

        [DataMember]
        public bool has_resort_fee { get; set; }
        [DataMember]
        public string resort_description { get; set; }


        [DataMember]
        public bool has_free_night { get; set; }

        [DataMember]
        public int free_night_quantity { get; set; }

        [DataMember]
        public string free_night_text { get; set; }

        [DataMember]
        public bool has_promotion { get; set; }

        [DataMember]
        public string promotion_text { get; set; }

        [DataMember]
        public int i_search { get; set; }

        [DataMember]
        public string room_id { get; set; }

        //[DataMember]
        //public string hotel_id { get; set; }

        [DataMember]
        public string data_contract { get; set; }
        [DataMember]
        public string meal_plan_code { get; set; }

    }

As I said, it only happens under load, I can share the endpoint privately if you want to test it directly.

Can you provide the full HTTP Request/Response Headers (inc. body) of a HTTP request that fails, I’d want to ensure the request isn’t malformed which is what the Error message is suggesting.

The body is the one on my previous post:

<?xml version="1.0" encoding="utf-8"?><hotels_search_v2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://schemas.datacontract.org/2004/07/te_webservices"><checkin_date>2019-04-06</checkin_date><checkout_date>2019-04-07</checkout_date><destination_id>MzM%3D_MjM0MTQ%3D</destination_id><destination_type>4</destination_type><nationality_code>US</nationality_code><rooms><hotels_search_room_v2><adults>2</adults><children>0</children></hotels_search_room_v2></rooms></hotels_search_v2>

Can you please paste the whole Request/Response Headers in its entirety (i.e. entire Headers + Body) so we can correlate the exact HTTP Request that generated the exact HTTP Response.

You can get this from Raw view in Fiddler or follow tcp stream in WireShark.