4

I am making a web service that will use a different EDM model based on the request. To achieve this my aim is to load the model from XML, however my tests show that my serialize method seems to be loosing data (and seems like really smelly code).

I have the following API controller method to test the deserialize, write to xml and read back again

public IHttpActionResult Post()
{
    IEnumerable<EdmError> errors;
    var model = FromXml(await Request.Content.ReadAsStringAsync(), out errors);

    var parts = ToXml(model);

    model = FromParts(parts);

    var odataProperties = Request.ODataProperties();
    odataProperties.Model = model;
    return Ok(GetMetadata());
}

public IEdmModel FromXml(string xml, out IEnumerable<EdmError> errors)
{
    var readers = new List<XmlReader>();
    var disposables = new List<IDisposable>();
    try
    {
        //Have no idea if this is correct but only way I was able to make it work
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(xml);
        doc.GetElementsByTagName("Schema").Cast<XmlNode>().ToList().ForEach(node =>
        {
            var stringReader = new StringReader(node.OuterXml);
            var xmlReader = XmlReader.Create(stringReader);
            readers.Add(xmlReader);
            disposables.Add(xmlReader);
            disposables.Add(stringReader);
        });

        IEdmModel model;
        CsdlReader.TryParse(readers.AsEnumerable(), out model, out errors);

        return model;
    }
    finally
    {
        disposables.ForEach(r => r.Dispose());
    }
}

//Really don't thing this is right but couldn't write the model
//But passing the model into TryWriteCsdl gives edm error Single file provided but model cannot be serialized into single file
public static List<string> ToXml(IEdmModel model)
{

    IEnumerable<EdmError> errors = new List<EdmError>();
    var xmlParts = new List<string>();
    foreach (var schema in model.SchemaElements)
    {
        var xmlBuilder = new StringBuilder();
        var tempModel = new EdmModel();
        tempModel.AddElement(schema);
        using (var xmlWriter = XmlWriter.Create(xmlBuilder, new XmlWriterSettings() { Encoding = Encoding.UTF32 }))
        {
            tempModel.TryWriteCsdl(xmlWriter, out errors);
        }
        xmlParts.Add(xmlWriter.ToString());
    }

    return xmlParts;
}

public IEdmModel FromParts(List<string> parts)
{
    var readers = new List<XmlReader>();
    var disposables = new List<IDisposable>();
    EdmEntityContainer entityContainer = null;
    try
    {
        IEdmModel model;
        IEnumerable<EdmError> errors;
        await
            parts.ForEachAsync(f =>
            {
                var stringReader = new StringReader(f);
                var xmlReader = XmlReader.Create(stringReader);
                readers.Add(xmlReader);
                disposables.Add(xmlReader);
                disposables.Add(stringReader);
            });
        CsdlReader.TryParse(readers, out model, out errors);

        return model ;
    }
    finally
    {
        disposables.ForEach(r => r.Dispose());
    }
}

When I send the following as the request body

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
  <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/os/vocabularies/Org.OData.Core.V1.xml">
    <edmx:Include Alias="Core" Namespace="Org.OData.Core.V1"/>
  </edmx:Reference>
  <edmx:DataServices>
    <Schema Namespace="NorthwindModel" xmlns="http://docs.oasis-open.org/odata/ns/edm">
      <EntityType Name="Item">
        <Key>
          <PropertyRef Name="ItemID"/>
        </Key>
        <Property Name="ItemID" Type="Edm.Int32" Nullable="false">
          <Annotation Term="Core.Computed" Bool="true" />
        </Property>
        <Property Name="ItemName" Type="Edm.String"/>
      </EntityType>
    </Schema>
    <Schema Namespace="ODataWebExperimental.Northwind.Model" xmlns="http://docs.oasis-open.org/odata/ns/edm">
      <EntityContainer xmlns:p4="http://schemas.microsoft.com/ado/2009/02/edm/annotation" Name="NorthwindEntities" p4:LazyLoadingEnabled="true">
        <EntitySet Name="Items" EntityType="NorthwindModel.Item" />
      </EntityContainer>
    </Schema>
  </edmx:DataServices>
</edmx:Edmx>

I get this response

<?xml version="1.0" encoding="utf-8"?>
<edmx:Edmx Version="4.0" 
xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
    <edmx:DataServices>
        <Schema Namespace="NorthwindModel" 
        xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <EntityType Name="Item">
                <Key>
                    <PropertyRef Name="ItemID" />
                </Key>
                <Property Name="ItemID" Type="Edm.Int32" Nullable="false" />
                <Property Name="ItemName" Type="Edm.String" />
            </EntityType>
        </Schema>
        <Schema Namespace="ODataWebExperimental.Northwind.Model" 
        xmlns="http://docs.oasis-open.org/odata/ns/edm">
            <EntityContainer Name="NorthwindEntities">
                <EntitySet Name="Items" EntityType="NorthwindModel.Item" />
            </EntityContainer>
        </Schema>
    </edmx:DataServices>
</edmx:Edmx>

This is nearly right except the <Annotation Term="Core.Computed" Bool="true" /> line has disappeared. I need to make sure that no data is lost in the serialize/deserialize

The way I am serializing the model seems really wrong to me but not sure how I should be done

Gert Arnold
  • 105,341
  • 31
  • 202
  • 291
Mike Norgate
  • 2,393
  • 3
  • 24
  • 45

0 Answers0