سؤال

I am making a web api project and I noticed that one of my method dies when I try to use xml. I usually just use json when testing as this is my preferred method and it works fine.

public HttpResponseMessage GetStoreNames(StoreDm vm)
        {
            if (ModelState.IsValid)
            {

                var result = storeService.AutoCompleteStore(vm.Latitude, vm.Longitude, vm.Name);
                return Request.CreateResponse <ResponseResult<AutoCompleteSearchDto>>(result.Status.Code, result);

            }


            var responseResult = new ResponseResultWrapper();
            responseResult.Status.Code = HttpStatusCode.BadRequest;
            responseResult.Status.Message = GenericErrors.InvalidRequest;
            responseResult.ModelStateToResponseResult(ModelState);

            return Request.CreateResponse<ResponseResult>(responseResult.Status.Code, responseResult);


        }

 [DataContract(Name = "MyRoot")]
    public class ResponseResultWrapper : ResponseResult
    {
        public void ModelStateToResponseResult(ModelStateDictionary modelState)
        {
            foreach (var kvp in modelState)
            {
                foreach (var error in kvp.Value.Errors)
                {
                    string key = kvp.Key;
                    string msg = error.ErrorMessage;
                    if (String.IsNullOrEmpty(msg))
                    {
                        msg = error.Exception.Message;
                    }

                    base.AddError(key, msg);
                }
            }
        }
    }


 [DataContract(Name = "MyRoot")]
    public class ResponseResult
    {

        public ResponseResult()
        {
            Errors = new Dictionary<string, string>();
            Status = new ResponseBase();
        }

        public void AddError(string key, string errorMessage)
        {
            if (!Errors.ContainsKey(key))
            {
                Errors.Add(key, errorMessage);
            }
        }

        public bool IsValid()
        {
            if (Errors.Count > 0)
            {
                return false;
            }

            return true;
        }

        [DataMember]
        public Dictionary<string, string> Errors { get; private set; }

        [DataMember]
        public ResponseBase Status { get; set; }
    }


    [DataContract(Name = "MyRoot")]
    public class ResponseResult<T> : ResponseResult
    {
        [DataMember]
        public T Response { get; set; }
    }

I get this error

HTTP/1.1 500 Internal Server Error
Cache-Control: private
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/8.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcV2luZG93czdcRGVza3RvcFxQcmljZUNoZWNrXHRydW5rXFByaWNlQ2hlY2tcUHJpY2VDaGVjay5BcGlcYXBpXHN0b3JlXEdldFN0b3JlTmFtZXM=?=
X-Powered-By: ASP.NET
Date: Thu, 23 May 2013 16:44:14 GMT
Content-Length: 2195

<Error><Message>An error has occurred.</Message><ExceptionMessage>The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.</ExceptionMessage><ExceptionType>System.InvalidOperationException</ExceptionType><StackTrace /><InnerException><Message>An error has occurred.</Message><ExceptionMessage>Type 'ResponseResultWrapper' with data contract name 'http://schemas.datacontract.org/2004/07/Api.Models' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.</ExceptionMessage><ExceptionType>System.Runtime.Serialization.SerializationException</ExceptionType><StackTrace>   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeAndVerifyType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, Boolean verifyKnownType, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiTypeAtTopLevel(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle originalDeclaredTypeHandle, Type graphType)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
   at System.Runtime.Serialization.DataContractSerializer.WriteObject(XmlWriter writer, Object graph)
   at System.Net.Http.Formatting.XmlMediaTypeFormatter.&lt;&gt;c__DisplayClass7.&lt;WriteToStreamAsync&gt;b__6()
   at System.Threading.Tasks.TaskHelpers.RunSynchronously(Action action, CancellationToken token)</StackTrace></InnerException></Error>

Edit

[DataContract]
    public class StoreDm
    {
        [DataMember(IsRequired = true)]
        [MinLength(3)]
        public string Name { get; set; }

        [DataMember(IsRequired = true)]
        public double Latitude { get; set; }

        [DataMember(IsRequired = true)]
        public double Longitude { get; set; }
    }

I get this error after trying "Youssef Moussaoui" first part of his answer.

There was an error deserializing the object of type StoreDm. The data at the root level is invalid. Line 1, position 1.

I can't really do his second part as "ResponseResultWrapper" and "ResponeResult" are in 2 different libraries.

هل كانت مفيدة؟

المحلول

Try changing:

return Request.CreateResponse<ResponseResult>(responseResult.Status.Code, responseResult);

to

return Request.CreateResponse<ResponseResultWrapper>(responseResult.Status.Code, responseResult);

The problem is that DataContractSerializer needs known types to support inheritance. You can learn more about that here:

http://blogs.msdn.com/b/youssefm/archive/2009/04/21/understanding-known-types.aspx

Changing the generic parameter on CreateResponse is the simplest solution, but if you want to serialize derived instances of ResponseResult, you'd want to add known type attributes to ResponseResult like this:

[DataContract(Name = "MyRoot")]
[KnownType(typeof(ResponseResultWrapper))]
public class ResponseResult
{
}

.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top