Parsing CRM OData v4 Metadata

One of the nice things about OData is it has a lot of rich metadata available. If you want to have it parsed into a nice object model, you can use IEdmModel. This is great if you want to build any tools that consume the metadata and don't want to parse the XML manually.

Here is what the code looks like -

  var request = WebRequest.CreateHttp("https://<orgname>.crm.dynamics.com/api/data/v8.0/$metadata");
  request.Headers.Add("Authorization", "Bearer <accesstoken>");
  
  var metadataMessage =  new ODataResponseMessage(request.GetResponse());
  
  var settings = new ODataMessageReaderSettings()
      { MessageQuotas = new ODataMessageQuotas() { MaxReceivedMessageSize = 10000000 } };

  using (var messageReader = new ODataMessageReader(metadataMessage, settings)) 
  {                
      IEdmModel edmModel = messageReader.ReadMetadataDocument();
      foreach(var entity in edmModel.EntityContainer.EntitySets())
      {
          Console.WriteLine("Entity:" + entity.Name);
      }
      
      //continue processing
  }

One of the confusing things is IEdmModel exists in multiple places. To get this to work with the CRM OData V4 metadata I had to use the Microsoft.OData.Core nuget package. You will also notice ODataResponseMessage isn't part of that, I modeled that after the sample here - http://odatasamples.codeplex.com/SourceControl/latest#Features/Containment/ODataResponseMessage.cs But I then changed it to work with WebResponse instead of only the stream.

Here is the code for that class...

public class ODataResponseMessage : IODataResponseMessage
{
    
    private readonly Dictionary<string, string> headers;
    private WebResponse _response;

    public ODataResponseMessage(WebResponse response)
    {
        this.headers = new Dictionary<string, string>();
        _response = response;
    }

    public IEnumerable<KeyValuePair<string, string>> Headers
    {
        get
        {
            return this._response.Headers.AllKeys.Select(
              headerName => new KeyValuePair<string, 
				string>(headerName, _response.Headers.Get(headerName)));

        }
    }
    public string GetHeader(string headerName)
    {
        if (headerName == null)
            throw new ArgumentNullException("headerName");

        return this._response.Headers.Get(headerName);
    }

    public int StatusCode { get; set; }

    public Uri Url { get; set; }

    public string Method { get; set; }


     public void SetHeader(string headerName, string headerValue)
    {
        headers[headerName] = headerValue;
    }

    public Stream GetStream()
    {
        return this._response.GetResponseStream();
    }
}