В нашем приложении у нас есть REST-Api с несколькими контроллерами, такими как UsersController
или UserGroupsController
и многими другими. Все вызовы (get, put, pu sh, delete) на каждой REST-конечной точке всегда возвращают HttpResponseMessage
, который всегда является объектом следующего типа:
public class ComRestResult<T> where T : class
{
public T Data { get; set; }
public ValidationItem[] ValidationItems { get; set; }
}
И ValidationItem
- класс выглядит так:
[DataContract]
[Serializable]
public class ValidationItem
{
[DataMember]
public string[] ErrorParameters { get; set; }
[DataMember]
public ValidationSeverity Severity { get; set; }
private ValidationId validationId;
[IgnoreDataMember]
[XmlIgnore]
public ValidationId ValidationId
{
get { return validationId; }
set
{
validationId = value;
if(validationId != ValidationId.UnresolvedError)
{
legacyValidationId = validationId.ToString();
}
}
}
private string legacyValidationId;
[DataMember(Name = "ValidationId")]
[XmlElement("ValidationId")]
public string LegacyValidationId
{
get { return legacyValidationId; }
set
{
legacyValidationId = value;
validationId = ValidationId.UnresolvedError;
ValidationId parsedValidationId;
if(!string.IsNullOrEmpty(legacyValidationId) && Enum.TryParse(legacyValidationId, out parsedValidationId))
{
validationId = parsedValidationId;
}
}
ValidationId
и Severity
являются перечислениями.
Например, Get-Method для UsersController выглядит следующим образом:
[HttpGet]
[Route("")]
public HttpResponseMessage Get()
{
RequestHandler handler = new RequestHandler(Request);
HttpResponseMessage responseMessage = handler.ProcessRequest<User[]>(PersonsAccess.GetAllPersons);
return responseMessage;
}
RequestHandler создает необходимый HttpResponseMessage
и принимает Func<object, T>
в своем ProcessRequest-методе.
HttpResponseMessage
создается внутри ProcessRequest-метода со следующей строкой:
HttpResponseMessage httpResponseMessage = request.CreateResponse(httpStatusCode, restResult);
Все просто отлично работает.
Если я посмотрю на ответ в json, он выглядит так:
{"ValidationItems":[{"ValidationId":"UserIsNew","ErrorParameters":["foo","bar"],"Severity":0,}],"Data":[{"UserId":"ABC123","UserName":"John Smith","IsNew":true},{"UserId":"XYZ789","UserName":"Raimond Test","IsNew":true}]}
Это выглядит хорошо. Теперь, если я посмотрю на ответ как xml, он выглядит так:
<ComRestResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Data xmlns:d2p1="http://schemas.datacontract.org/2004/07/Comp.Rest.Data.Persons">
<d2p1:User>
<d2p1:UserId>ABC123</d2p1:UserId>
<d2p1:UserName>John Smith</d2p1:UserName>
<d2p1:IsNew>true</d2p1:IsNew>
</d2p1:User>
<d2p1:User>
<d2p1:UserId>XYZ789</d2p1:UserId>
<d2p1:UserName>Raimond Test</d2p1:UserName>
<d2p1:IsNew>true</d2p1:IsNew>
</d2p1:User>
</Data>
<ValidationItems xmlns:d2p1="http://schemas.datacontract.org/2004/07/Comp.BaseInterface.Validation">
<d2p1:ValidationItem>
<d2p1:ValidationId>UserIsNew</d2p1:ValidationId>
<d2p1:ErrorParameters xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d4p1:string>foo</d4p1:string>
<d4p1:string>bar</d4p1:string>
</d2p1:ErrorParameters>
<d2p1:Severity>Information</d2p1:Severity>
</d2p1:ValidationItem>
</ValidationItems>
</ComRestResult>
И это выглядит не очень хорошо. Хотя вся информация присутствует, у нас есть проблема с пространствами xml -names. d2p1
и все остальные.
Если я применяю атрибуты [DataContract]
и [DataMember]
к классу User
, например:
[DataContract(Name = "User", Namespace = "")]
public class User
{
[DataMember(Name = "UserId")]
public string UserId { get; set; }
[DataMember(Name = "UserName")]
public string UserName { get; set; }
[DataMember(Name = "IsNew")]
public bool IsNew { get; set; }
}
ответ- xml для пользователя выглядит так:
<Data>
<User>
<IsNew>true</IsNew>
<UserId>ABC123</UserId>
<UserName>John Smith</UserName>
</User>
<User>
<IsNew>true</IsNew>
<UserId>XYZ789</UserId>
<UserName>Raimond Test</UserName>
</User>
</Data>
Это то, что нам нужно. Но действительно ли нам нужно применять атрибуты к каждому классу, или есть возможность деактивировать (или около того) пространство имен при сериализации в целом?
Другая проблема - string[]
в ValidationItem
- учебный класс. На данный момент это сериализовано как:
<d2p1:ErrorParameters xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d4p1:string>foo</d4p1:string>
<d4p1:string>bar</d4p1:string>
</d2p1:ErrorParameters>
Я знаю, что могу заменить string[]
следующим классом:
[CollectionDataContract(ItemName = "value", Namespace = "")]
public class StringArray : List<string>
{
}
Но, к сожалению, этот класс очень старый, очень часто используется (~ 4000 ссылок), а также используется для SOAP -сериализации. Поэтому мы не можем легко изменить это.
Там нам также нужно что-то вроде обобщенной c сериализации на xml без пространств имен.