none
OData consumer in .Net 4/WinForms for dynamic provider selection - howto begin?

    Question

  • Hi there,

    I'm trying to implement a generic OData consumer as an import interface for a WinForms application.

    Overwhelmed by all the available libraries and samples, I just can't find the right library for my task.

    With WCF Data Services 5 the samples implicate that the service has to be known at compile time so I can't offer a dialog for endpoint selection as in the Silverlight ODataExplorer sample. On the other hand the APIs used in this sample seem not to work in WinForms.

    I looked at ODataLib (5.01) but theMicrosoft.Data.OData.Samples don't even compile. Anyway I have the impression these calls are too rudimentary to be of help in my case.

    I need APIs that, for a dynamically selectable endpoint, return the collection of available tables (the OData workspace) with their metadata (i.e. columns plus data types). Then, after the user has selected a table plus some or all of their columns, get a DataTable filled with the actual contents.

    This should be possible, shouldn't it?

    Thomas

    Thursday, June 28, 2012 7:02 AM

Answers

  • WPF was no option, so I looked further for a solution.

    And now I got a prototype that uses the OData.MetaData single file project from the ODataExplorer sample. As this project has only few Silverlight specific references, it was relatively easy to port to WinForms. It was mostly a matter of creating an empty class lib project and adapting a handful of lines of code.

    This class lib parses the metadata or service document and creates a metadata structure in memory. With this it is easy to build the DataTable schema and then use XmlDocument.Load() and parse that for the real data.

    Here's the core of my schema creation:

          internal void CreateSchemaAsync()
          {
          dtSchema = null;
          currentContext = new DataServiceContext(new Uri(Properties["currentWorkspaceUri"]));
          if (currentContext.GetMetadataUri() != null)
             {
             MetadataParser parser = new MetadataParser();
             parser.ParseComplete += new MetadataParser.OnParseComplete(parser_ParseComplete);
             parser.BeginParse(currentContext.GetMetadataUri().AbsoluteUri);
             }
          }
    
          public delegate void OnSchemaCreated();
          public event OnSchemaCreated SchemaCreated, sc;
    
          void parser_ParseComplete(EDMModel model, Exception Error)
             {
             if (Error == null)
                {
                string currentService = Properties["currentService"];
                EntityContainer cont = model.DataServices[0].Schemas[0].Containers[0];
                var es = cont.EntitySets.First(s => s.SetName.CompareTo(currentService) == 0);
                string typename = es.TypeName;
                DataTable dt = new DataTable(es.SetName);
                EntityType et = model.GetEntityType(typename);
                DataColumn dc;
    
                foreach (var p in et.Properties)
                   if (p.PropertyType != null) // komplexer Typ? ggf. innertext nehmen
                      {
                      dc = dt.Columns.Add(p.PropertyName, p.PropertyType);
                      if (p.FeedCustomizationMapping != null)
                         {
                         dc.ExtendedProperties["FC_KeepInContent"] = false;
                         dc.ExtendedProperties["FC_TargetPath"] = p.FeedCustomizationMapping.Mapping.ToString();
                         }
                      }
    
                if (et.KeyProperties.Count > 0)
                   dt.PrimaryKey = et.KeyProperties.Select(x => dt.Columns[x]).ToArray();
    
                dtSchema = dt;
                if (SchemaCreated != null)
                   SchemaCreated();
                }
             }

    Remember, it's a prototype and no production-quality code!

    Thomas


    • Edited by thomas_schmidt Friday, June 29, 2012 1:29 PM typo
    • Marked as answer by Yi-Lun Luo Wednesday, July 04, 2012 9:20 AM
    Friday, June 29, 2012 1:28 PM

All replies

  • On 6/28/2012 3:02 AM, thomas_schmidt wrote:
    > Hi there,
    >
    > I'm trying to implement a generic OData consumer as an import interface
    > for a WinForms application.
    >
    > Overwhelmed by all the available libraries and samples, I just can't
    > find the right library for my task.
    >
    > With WCF Data Services 5 the samples implicate that the service has to
    > be known at compile time so I can't offer a dialog for endpoint
    > selection as in the Silverlight ODataExplorer sample. On the other hand
    > the APIs used in this sample seem not to work in WinForms.
    >
    > I looked at ODataLib (5.01) but theMicrosoft.Data.OData.Samples don't
    > even compile. Anyway I have the impression these calls are too
    > rudimentary to be of help in my case.
    >
    > I need APIs that, for a dynamically selectable endpoint, return the
    > collection of available tables (the OData workspace) with their metadata
    > (i.e. columns plus data types). Then, after the user has selected a
    > table plus some or all of their columns, get a DataTable filled with the
    > actual contents.
    >
    > This should be possible, shouldn't it?
     
    No I don't think so. OData service works with objects that can be
    serialized either custom objects/DTO(s) (Data Transfer Objects) you
    create or objects/entities from Linq-2-SQL or ADO.NET Entity Framework.
     
     
     
    You may want to look at a standard WCF service in attempting what you
    are trying to do here.
     
     
    You might be able to build a dynamic typed datatable based on criteria
    and send it back.
     
    Thursday, June 28, 2012 8:45 AM
  • Thanks darnold924,

    that's not what I wanted to hear...

    I began by reading the service/workspace reply into a xml document and parse the available tables. After the user has selected one of them

    * I have to rely on the $metadata being present

    * and read the $metadata into another xml doc and then parse the relevant entries in order to construct my DataTable.

    This is a very finicky task due to the hierarchical namespace definitions and variants in the metadata reply.

    I wonder how the Silverlight APIs implement this. When I saw the sample I had hoped I could do something like this in WinForms.

    Thomas

    Thursday, June 28, 2012 9:07 AM
  • On 6/28/2012 5:07 AM, thomas_schmidt wrote:
    > Thanks darnold924,
    >
    > that's not what I wanted to hear...
    >
    > I began by reading the service/workspace reply into a xml document and
    > parse the available tables. After the user has selected one of them
    >
    > * I have to rely on the $metadata being present
    >
    > * and read the $metadata into another xml doc and then parse the
    > relevant entries in order to construct my DataTable.
    >
    > This is a very finicky task due to the hierarchical namespace
    > definitions and variants in the metadata reply.
    >
    > I wonder how the Silverlight APIs implement this. When I saw the sample
    > I had hoped I could do something like this in WinForms.
     
    Maybe you need to look a Windows Presentation Foundation, which can be
    ran as an application on the desktop instead of a Windows form based
    application on the desktop. WPF is like Siliverlight, and it is for the
    desktop and Web based applications UI(s).
     
    Thursday, June 28, 2012 9:31 AM
  • WPF was no option, so I looked further for a solution.

    And now I got a prototype that uses the OData.MetaData single file project from the ODataExplorer sample. As this project has only few Silverlight specific references, it was relatively easy to port to WinForms. It was mostly a matter of creating an empty class lib project and adapting a handful of lines of code.

    This class lib parses the metadata or service document and creates a metadata structure in memory. With this it is easy to build the DataTable schema and then use XmlDocument.Load() and parse that for the real data.

    Here's the core of my schema creation:

          internal void CreateSchemaAsync()
          {
          dtSchema = null;
          currentContext = new DataServiceContext(new Uri(Properties["currentWorkspaceUri"]));
          if (currentContext.GetMetadataUri() != null)
             {
             MetadataParser parser = new MetadataParser();
             parser.ParseComplete += new MetadataParser.OnParseComplete(parser_ParseComplete);
             parser.BeginParse(currentContext.GetMetadataUri().AbsoluteUri);
             }
          }
    
          public delegate void OnSchemaCreated();
          public event OnSchemaCreated SchemaCreated, sc;
    
          void parser_ParseComplete(EDMModel model, Exception Error)
             {
             if (Error == null)
                {
                string currentService = Properties["currentService"];
                EntityContainer cont = model.DataServices[0].Schemas[0].Containers[0];
                var es = cont.EntitySets.First(s => s.SetName.CompareTo(currentService) == 0);
                string typename = es.TypeName;
                DataTable dt = new DataTable(es.SetName);
                EntityType et = model.GetEntityType(typename);
                DataColumn dc;
    
                foreach (var p in et.Properties)
                   if (p.PropertyType != null) // komplexer Typ? ggf. innertext nehmen
                      {
                      dc = dt.Columns.Add(p.PropertyName, p.PropertyType);
                      if (p.FeedCustomizationMapping != null)
                         {
                         dc.ExtendedProperties["FC_KeepInContent"] = false;
                         dc.ExtendedProperties["FC_TargetPath"] = p.FeedCustomizationMapping.Mapping.ToString();
                         }
                      }
    
                if (et.KeyProperties.Count > 0)
                   dt.PrimaryKey = et.KeyProperties.Select(x => dt.Columns[x]).ToArray();
    
                dtSchema = dt;
                if (SchemaCreated != null)
                   SchemaCreated();
                }
             }

    Remember, it's a prototype and no production-quality code!

    Thomas


    • Edited by thomas_schmidt Friday, June 29, 2012 1:29 PM typo
    • Marked as answer by Yi-Lun Luo Wednesday, July 04, 2012 9:20 AM
    Friday, June 29, 2012 1:28 PM