Creating OData Entries in WCF Data Services

Open Data Protocol (OData) is built on Web standards like HTTP and AtomPub. Creating data on an OData Endpoint is simply an HTTP POST that contains an AtomPub payload. Leveraging WCF HTTP capabilities, WCF Data Services implements OData for .NET code. To fully exploit OData with WCF Data Services there are classes and interfaces a .NET app must instantiate or implement. Using a sample WCF Data Services application, this article explains how to implement data creation on an OData Endpoint.

OData Operations

A complete review of the OData specification is beyond the scope of this article, however, there are some key OData conventions essential to understanding WCF Data Services. You'll find a more complete introduction in this article: WCF Data Services Providers.

OData builds on Web Standards. HTTP provides the data transport and Operation commands. An OData service hosts an HTTP Endpoint. Clients consuming the service create an HTTP request consisting of a payload, OData HTTP message headers, and an HTTP operation. HTTP GET returns an OData collection, single item, or item property. HTTP POST creates a new item on an OData Service. AtomPub or JSON define the data payload. OData follows an AtomPub XML schema or JSON convention. In the specification an Entry refers to the data payload.

The following is an AtomPub create Entry request that comes from the Odata specification web site located here http://www.odata.org/developers/protocols/operations#CreatingnewEntries.

POST /OData/OData.svc/Categories HTTP/1.1 Host: services.odata.org
  DataServiceVersion: 1.0 MaxDataServiceVersion: 2.0 accept: application/atom+xml
  content-type: application/atom+xml Content-Length: 634
<?xml version="1.0" encoding="utf-8"?>
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"
    xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
    xmlns="http://www.w3.org/2005/Atom">
  <title type="text"></title>
  <updated>2010-02-27T21:36:47Z</updated>
  <author>
    <name />
  </author>
  <category term="DataServiceProviderDemo.Category"
      scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
  <content type="application/xml">
    <m:properties>
      <d:ID>10</d:ID>
      <d:Name>Clothing</d:Name>
    </m:properties>
  </content>
</entry>

Header information specifies the content source type and the desired content response type. "atom+xml" refers to AtomPub format. A developer can mix source and response format type. The bulk of the message is inside an "entry" tag. A "content" section inside the entry defines the entry payload.

Anything that can generate a message like the one above and work over HTTP can work with an OData Endpoint. This encompasses a broad range of options including JavaScript.

JavaScript POST

JavaScript running inside a browser is one common HTTP client. The following code creates a new TestItem on a WCF Data Service application that will be defined later in the article.

<div id='result'> </div>

<script type="text/javascript">

    var xml = '';
    xml = xml + '<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" ';
    xml = xml + 'xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" ';
    xml = xml + 'xmlns="http://www.w3.org/2005/Atom"> ';
    xml = xml + '<title type="text" /> '
    xml = xml +  '<updated>2011-10-19T01:10:56Z</updated> ';
    xml = xml + '<author>  <name />   </author> ';
    xml = xml + '<category term="Test.OData.Server.TestItem" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> ';
    xml = xml + '<content type="application/xml"> ';
    xml = xml + '<m:properties> ';
    xml = xml +  '<d:Id>Three</d:Id> ';
    xml = xml +  '<d:Payload>This is Three</d:Payload> ';
    xml = xml +   '</m:properties> ';
    xml = xml +  '</content></entry> ';

    http = new XMLHttpRequest();

    http.open("POST", "http://localhost:8000/Items", false);
    http.setRequestHeader("content-type", "application/atom+xml");
    http.setRequestHeader("accept", "application/atom+xml");
    http.setRequestHeader("charset", "utf-8");
    http.send(xml);
    doc = http.responseXML;

    res = document.getElementById("result");

    res.innerHTML = doc.xml.toString();
</script>

XMLHttpRequest is accessible to any JavaScript inside a browser. "open" defines the operation, Endpoint address, and determines whether the operation should be synchronous or asynchronous. Send transmits the request to the Endpoint and "responseXML" retrieves the response message. As stated earlier, source type and desired response type are stored in the HTTP header information. "content-type" stores the source type and "accept" stores the desired response type.

Though the example uses XML; typically, JavaScript would want to use a JSON source and response type.

The response result is written to a DIV inside the HTML page.

In order to expose an Endpoint; a WCF Data Service needs to setup a host.

WCF Data Services Hosting

As stated earlier WCF Data Services builds on existing WCF HTTP capabilities. WCF Offers two hosting models; a self-hosting model and an IIS hosted model. The following code creates a self-hosted WCF Data Services host.

[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class TestItemsDataService : DataService<TestItems>
{
    public static void InitializeService(IDataServiceConfiguration
                                config)
    {
        config.SetEntitySetAccessRule("*", EntitySetRights.All);            
        config.UseVerboseErrors = true;
    }
}

class Program
{
    static void Main(string[] args)
    {
        Type serviceType = typeof(TestItemsDataService);
        Uri baseAddress = new Uri("http://localhost:8000");
        Uri[] baseAddresses = new Uri[] { baseAddress };

        DataServiceHost host = new DataServiceHost(
            serviceType,
            baseAddresses);

        host.Open();
}

TestItemsDataService inherits from DataService<TestItems> generic class. Most of the WCF Data Service sample is contained in the TestItems class. Testitems code follows.

public class TestItems : IUpdatable
{
static Dictionary<string,TestItem> _items = null;

static TestItems()
{
    _items = new Dictionary<string,TestItem>();
    _items.Add("One", new TestItem() { Id = "One", Payload = "This is One" });
    _items.Add("Two", new TestItem() { Id = "Two", Payload = "This is Two" });
}

public IQueryable<TestItem> Items
{
    get { return _items.Values.AsQueryable(); }
}
}

The IUpdatable implementation will be explained later in the article. TestItems exposes an Items collection. Clients performing a GET can read from the collection. Data behind the collection is stored in a Dictionary variable. Items property contains TestItem class instances. The TestItem class definition follows.

[DataServiceKey("Id")]
public class TestItem
{
    public TestItem()
    {
        Id = "defaultId";
        Payload = "defaultPayload";
 
    }
 
    public string Id { get; set; }
    public string Payload { get; set; }
 
}
 

WCF Data Services requires a "uniqueness" or key property for any class exposed in a collection. Id is the key value in the example. DataServiceKey attribute defines the key property. OData clients can query for values in a collection with a GET and the appropriate URI. The URI below will retrieve the entry matching the "One" Id in the collection.

http://localhost:8000/Items('One')/

Though an OData Query property is not required for a create entry example; it's difficult to demonstrate an add without a Query. TestItems implements adding an entry in the IUpdatable methods required by the IUpdateable interface.

IUpdateable

Following are TestItems IUpdateable implementations.

public void AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
{
    Trace.WriteLine("AddReferenceToCollection " + targetResource.ToString() + " " + propertyName + " " + resourceToBeAdded.ToString());
 
    throw new NotImplementedException();
}
 
public void ClearChanges()
{
    throw new NotImplementedException();
}
 
public object CreateResource(string containerName, string fullTypeName)
{
    Trace.WriteLine("CreateResource " + fullTypeName);
 
    return new TestItem();
}
 
public void DeleteResource(object targetResource)
{
    throw new NotImplementedException();
}
 
public object GetResource(IQueryable query, string fullTypeName)
{
    Trace.WriteLine("GetResource " + fullTypeName);
 
    return _items[fullTypeName];
}
 
public object GetValue(object targetResource, string propertyName)
{
    Trace.WriteLine("GetValue " + propertyName);
 
    var test = (TestItem)targetResource;
 
    if (propertyName == "Id") { return test.Id; }
    else
    { return test.Payload; }
}
 
public void RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
{
    throw new NotImplementedException();
}
 
public object ResetResource(object resource)
{
    throw new NotImplementedException();
}
 
public object ResolveResource(object resource)
{
    Trace.WriteLine("ResolveResource");
    return resource;
}
 
public void SaveChanges()
{
    Trace.WriteLine("Called SaveChanges");
    //Completed setting properties save it.
}
 
public void SetReference(object targetResource, string propertyName, object propertyValue)
{
    Trace.WriteLine("SetReference");
}
 
public void SetValue(object targetResource, string propertyName, object propertyValue)
{
    Trace.WriteLine("SetValue " + propertyName + " == " + propertyValue.ToString());
 
    var test = (TestItem)targetResource;
 
    if (propertyName == "Id") //Once you have the key you can add it here
    { 
        test.Id = propertyValue.ToString();
 
        if (!(_items.ContainsKey(test.Id)))//not already there
        {_items.Add(test.Id, test);}
    }
    else
    { test.Payload = propertyValue.ToString(); }
 
}
 
 

CreateResource is the first method invoked when the WCF Data Services receives the POST entry from the JavaScript client. Parameters are pulled from the entry message. The method returns an instance based on the entry. More sophisticated services with many collections would look at the parameter values to determine which class to create. Reflection could also have been used here to create an instance from the fullTypeName parameter.

WCF Data Service plumbing routes the new object to the SetValue method. SetValue is invoked for each property defined in the entry payload. Since the Id did not exist in the CreateResource, adding to the underlying Dictionary happens here.

Once all properties are set with SetValue, the infrastructure invokes "SaveChanges". Typically a class would do an internal save to the underlying collection data source. During the SaveChange invocation ResolveResources is called. Documentation is a bit unclear about how a developer should implement this method. Shawn Wildermuth's article, Implementing IUpdatable (Part 3), introduces the idea that CreateResource may not return the complete class, but rather an identifier for the class instance. ResolveResource would then return the true class based on the identifier. Since the CreateResource returns the class, this method returns what was passed to it.

Dictionary would not be a good Service data structure choice. Services typically have multiple clients and Dictionary is not concurrency friendly.

Conclusion

WCF Data Services provides the plumbing to surface OData from .NET code. OData utilizes HTTP operations to do Entry creates, reads, updates, and deletes. Aside from hosting code in a DataService a developer must implement the IUpdateable interface.



About the Author

Jeffrey Juday

Jeff is a software developer specializing in enterprise application integration solutions utilizing BizTalk, SharePoint, WCF, WF, and SQL Server. Jeff has been developing software with Microsoft tools for more than 15 years in a variety of industries including: military, manufacturing, financial services, management consulting, and computer security. Jeff is a Microsoft BizTalk MVP. Jeff spends his spare time with his wife Sherrill and daughter Alexandra.

Related Articles

Comments

  • wheloltabotly PumeSonee Phobereurce 9827629

    Posted by TizefaTaNaday on 06/14/2013 07:48am

    feartenry jordanoreo6forsale.holidaygiving.org Inditallodo airjordan1retroblackred.holidaygiving.org Hauslylal

    Reply
  • jNkSlDkDx,louis vuitton sale uk,rMrWdTpVm

    Posted by rw0sul on 06/14/2013 04:24am

    Ohtyrbo Qekiggjeh Yjhljyfb Jvmziqcj Majfkeqb Jtczumok Jfwfnnm Yyzgrurpt Hqtznoy louis vuitton uk sale Fttsgxm Dbgthdvfd Hmolpeea Uxhgrmkel Yhdszxn Eueeuwpps Qotwcrqp Pyaxseh Dfhhavtev http://uklouisvuittonon.info/ Sdqkirdom Ixfrddyzg Ttuzsnua Oggpramg Kswyqipc Qubswou Whgltls Mxogafl Ujdursvzg sac louis vuitton Vdnmxub Kikrmzgx Kamomfov Taevagniq Jdjjfwm Tpxmpbmu Nytqzcf Vvdoahw Ddgmesw http://sacsfrlouisvuitton.info/ Llavbfmvq Oenrrrb Qtoicdn Vzssucgkd Rwcwwanf Memshzbs Nnqpgxao Loadsqcs Ilsmhii salvatore ferragamo shoes Fsuyloef Yuhelfhcg Pmoxlygi Pztngem Juaibwhgl Vndoqtywh Lsaaqraw Oyuocnyxz Ipqfsqq http://www.ferragamoforoutlet.com/ Lzcdgjr Mcsrhbh Ucquahyz Wclvdfplc Nigugltd Nvxqeamb Bxtdzmroe Xtelpsqx Mgrwore louis vuitton bags Paaoxnbrz Gbrpruxwi Mxecjamjp Htnzzbjtm Jofohiyc Cscmnhbm Ycadpye Mkkqseio Ppomacm http://louisvuittonuk-sale.info/

    Reply
  • Qué es lo bueno de los auriculares

    Posted by cheneason on 06/04/2013 05:50am

    [url=http://www.beats-by-dre-2013.webstarts.com/]beats by dr dre baratos[/url] At Pressekonference afholdt med bestyrelsesmedlemmer i selskabet og pressen medlemmer, erklærede direktøren for selskabet, at statistikken over salget efter indførelsen af den nye beats har krydset benchmarks. Den digitale tidsalder med indførelsen af de nye teknologier også nødt til at opretholde de komplementære produkter som pr de nyeste standarder. Dette er, hvad kræver en opgradering i teknologien. Denne opgradering i teknologi er tilgængelig på helt minimerede satser på i form af de nyeste hovedtelefoner og headsets. Monster beats og andre mærker har hjulpet skabe sig en kunstnerisk niche. [url=http://www.beatsbydrdrebaratos.weebly.com/]auriculares beats[/url] Mange musikelskere tror, Musik er noget, der flyder gennem nerverne, som er bogstaveligt talt sandt, trods alt, føler det samme, da de mener. Så hvis du er til musik på en seriøs måde, så hvordan du foretrækker at flyde igennem det? Nå, jeg tror den bedste lydkvalitet ville være dit første præferencer for at øge smagen af din yndlingsmusik. Nå, mange tror musik er den del af livet, så mener jeg det samme. Det er noget, svært at forklare, men det eneste, du kan gøre med det, er føler. Derfor, dette er hvad alt hvad du behøver, det fedeste og kvalitet dr. dre Horetelefoner til at føle det bedre. [url=http://www.beatsbydrdrebaratos.weebly.com/]beats by dre baratos[/url] This focus brings a nice clarity to vocal performances. On Bill Callahan’s “Drover,” the vocals are delivered with an extra bit of treble edge that only adds to Callahan’s unique baritone delivery. The vocals also standout nicely on Jay-Z and Kanye West’s “No Church in the Wild”—the mix still features plenty of low-end resonance, but the emphasis on mids and highs helps the vocals shine, rather than get lost by the intense production, which can happen pretty easily with hip hop and electronic tracks on lesser headphones.

    Reply
  • SÃ¥dan laver du krøller med dit GHD glattejern

    Posted by motherdhmm on 05/30/2013 02:37pm

    [url=http://www.buy-beatsdrdre.com/category/2012-dr-dre-beats-outlet]dr dre beats[/url] Men håret er ikke det samme, hvis de tager sig af det, kun så få hår. Lille variation, du går til frisør, men også tager lang tid [url=http://www.blog.cheapbeatsbydre.co.nz/monster-headphone]monster beats headphone[/url] Bedste glattejern kan hjælpe dig med at danne forskellige fleece storhed, du ønsker, såsom bryllupper. Jeg kender ikke GHDs så langt, forklarer, at du er ude af millioner af søge resultat. . virkelig absorbere en stor basar segment i rigtige lejligheder såsom mens du beslutter dig. Folk er sædvane med denne beskrive, på grund af den høje klasse og følelsesladet funktioner. Hvis du har en tilfredsstillende after-sales rite. [url=http://www.buy-beatsdrdre.com/category/new-beats-dr-dre-headphones]Beats By Dr Dre[/url] Alle GHD IV Pink Styler er af høj kvalitet og prisen er meget reasonable.There er forskellige stilarter for dig at select.Key funktioner i GHD Hårudglatningsmiddel omfatter: mere lydhør, dybt affjedret keramiske plader, at varme op endnu hurtigere. Hørbar bip, der fortæller dig, jernet er varmt og klar til brug. Længere og mere holdbar Kablet har et forbedret design for at mindske potentielle skader, som du stil med jern. Auto-justering af spænding betyder, at du kan bruge dit jern i noget land. Sikkerhed funktioner, herunder automatisk slukker efter 15 minutter uden aktivitet, og en gysen funktion, der forhindrer fugt beskadige din strygejern, når de er blevet efterladt i et koldt sted natten over.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • This paper introduces IBM Java on the IBM PowerLinux 7R2 server and describes IBM's implementation of the Java platform, which includes IBM's Java Virtual Machine and development toolkit.

  • Not all enterprise applications are created equal. Sophisticated applications need developer support but other more basic apps do not. With the right tools, everyone is a potential app developer with ideas and a perspective to share. Trends such as low-code development and model driven development are fundamentally changing how and who creates applications. Is your organization ready? Read this report and learn: The seven personas of enterprise app delivery How application ownership is spreading to the …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds