WCF Data Service can't handle UPDATE on feed entries

Me and some buddy of mine are trying to get started with WCF Data Services, so let me first describe what we have done so far:

  1. We have created a fairly simple WCF Data Service with a data source that implements the IUpdatable interface and exposes some data through some public IQueryable<> attributes (the code is attached at the bottom). Using Visual Studio 2010, at first we ran our service in IIS 7, but due to errors we couldn't figure out, we decided to run it with Cassini (Webdev webserver) instead.

  2. We wrote a client in C# to consume the service. The client works as supposed with all the different data operations (create, read, update and delete). So far so good! When hosting the service at the IIS 7 webserver we had to use POST tunnelling to make updates and deletes work, but now it's working as intended.

  3. Our problem arises when we try to consume the service with our Java (Restlet) and Ruby (ruby_odata) clients: we are unable to update data with these clients (we get a “500 Internal Server Error” and “Method Not Allowed” reply from the server) . We used two fairly simple tutorials[a,b] which both seems pretty straight forward, to create our clients. We therefore believe our problems lies within our service.

a. ruby_odata: http: //rdoc.info/projects/visoft/ruby_odata b. restlet: http: //wiki.restlet.org/docs_2.0/13-restlet/28-restlet/287-restlet/288-restlet.html

Both those clients are listed as OData SDKs ( http://www.odata.org/developers/odata-sdk ) and should be working fine to consume the OData feed.

One thing we noticed when monitoring the HTTP requests, is that the C# client uses HTTP MERGE verb for updates (take a look here for more information: http: //blogs.msdn.com/b/astoriateam/archive/2008/05/20/merge-vs-replace-semantics-for-update-operations.aspx), while both Java and Ruby uses HTTP PUT for updates. Could this be the reason why only our C# client works? What can we do to enable PUT updates?

We've just started with .NET, and would appreciate if that could be taken into consideration when you answer

using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Linq;
using System.Data.Services.Providers;
using System.Reflection;
using System.ServiceModel.Web;
using System.Data.Services.Common;

namespace WCFDataServiceApp
{

    public class Product
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Color { get; set; }
        public Category ProductCategory { get; set; }
    }

    public class Category
    {
        public int ID { get; set; }
        public string Name { get; set; }


    }

    public class AWData : IUpdatable
    {

        static List<Category> categories;
        static List<Product> products;

        static AWData()
        {

            categories = new List<Category>() {
                new Category { ID = 1, Name = "Bikes" },
                new Category { ID = 2, Name = "Parts" },
                new Category { ID = 3, Name = "Wheels"},
            };

            products = new List<Product>() {
                new Product { ID = 1, Name = "Red Bike", Color = "Red", ProductCategory = categories[0] },
                new Product { ID = 2, Name = "Blue Bike", Color = "Blue", ProductCategory = categories[0] },
                new Product { ID = 3, Name = "Green Bike", Color = "Green", ProductCategory = categories[0] },
                new Product { ID = 4, Name = "Yellow Bike", Color = "Yellow", ProductCategory = categories[0] },
                new Product { ID = 5, Name = "Pink Bike", Color = "Pink", ProductCategory = categories[0] },
                new Product { ID = 6, Name = "Black Bike", Color = "Black", ProductCategory = categories[0] }
            };           

        }

        public IQueryable<Category> Categories
        {
            get { return categories.AsQueryable(); }
        }

        public IQueryable<Product> Products
        {
            get { return products.AsQueryable(); }
        }




        void IUpdatable.AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)
        {
            System.Diagnostics.Debug.WriteLine("No support for AddReferenceToCollection(object targetResource, string propertyName, object resourceToBeAdded)");
        }

        void IUpdatable.ClearChanges()
        {
            System.Diagnostics.Debug.WriteLine("ClearChanges()");
        }

        public object CreateResource(string containerName, string fullTypeName)
        {
            System.Diagnostics.Debug.WriteLine("CreateResource(string containerName, string fullTypeName)");
            Type t = Type.GetType(fullTypeName);

            // Check if resource exists
            if (t != null)
            {
                object resource = Activator.CreateInstance(t);
                if (containerName.Equals("Categories"))
                {
                    categories.Add((Category)resource);
                }
                else if (containerName.Equals("Products"))
                {
                    products.Add((Product)resource);
                }
                return resource;
            }
            // Current resource does not exist
            return new Exception("Could not create a resource of type " + containerName);

        }

        void IUpdatable.DeleteResource(object targetResource)
        {
            // 1. Check object type

            if (targetResource.GetType().IsInstanceOfType(new Category()))
            {
                System.Diagnostics.Debug.WriteLine("Category deleted!");
                categories.Remove((Category)targetResource);
            }
            else if (targetResource.GetType().IsInstanceOfType(new Product()))
            {
                System.Diagnostics.Debug.WriteLine("Product deleted!");
                products.Remove((Product)targetResource);
            }

        }

        object IUpdatable.GetResource(IQueryable query, string fullTypeName)
        {
            System.Diagnostics.Debug.WriteLine("GetResource(IQueryable query, string fullTypeName)");
            object obj = null;
            foreach (object o in query)
            {
                obj = o;
            }
            return obj;

        }



        object IUpdatable.GetValue(object targetResource, string propertyName)
        {
            System.Diagnostics.Debug.WriteLine("GetValue(object targetResource, string propertyName)");
            return null;
        }

        void IUpdatable.RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)
        {
            System.Diagnostics.Debug.WriteLine("RemoveReferenceFromCollection(object targetResource, string propertyName, object resourceToBeRemoved)");
        }

        object IUpdatable.ResetResource(object resource)
        {

            System.Diagnostics.Debug.WriteLine("ResetResource(object resource)");
            return null;
        }

        object IUpdatable.ResolveResource(object resource)
        {
            return resource;
        }

        void IUpdatable.SaveChanges()
        {
            System.Diagnostics.Debug.WriteLine("SaveChanges()");
        }

        void IUpdatable.SetReference(object targetResource, string propertyName, object propertyValue)
        {
            System.Diagnostics.Debug.WriteLine("SetReference(object targetResource, string propertyName, object propertyValue)");
        }

        void IUpdatable.SetValue(object targetResource, string propertyName, object propertyValue)
        {
            PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);

            if (pi == null)
                throw new Exception("Can't find property");
            pi.SetValue(targetResource, propertyValue, null);

            System.Diagnostics.Debug.WriteLine("Object " + targetResource + " updated value " + propertyName + " to " + propertyValue);
        }

        public void SetConcurrencyValues(object resourceCookie, bool? checkForEquality, IEnumerable<KeyValuePair<string, object>> concurrencyValues)
        {
            System.Diagnostics.Debug.WriteLine("SetConcurrencyValues(object resourceCookie, bool? checkForEquality, IEnumerable<KeyValuePair<string, object>> concurrencyValues) was called");
            throw new Exception("SetConcurrencyValues(object resourceCookie, bool? checkForEquality, IEnumerable<KeyValuePair<string, object>> concurrencyValues) not implemented");
        }
    }

    public class aw : DataService<AWData> //, IServiceProvider
    {
        // This method is called only once to initialize service-wide policies.
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.SetEntitySetAccessRule("*", EntitySetRights.All);
            //config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;

        }
        /*
        public object GetService(Type serviceType)
        {

            System.Diagnostics.Debug.WriteLine(serviceType.ToString());
            return this;
        }*/
    }
}

Answers


The same question answered here: http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataservices/thread/31d3f2f0-3dd2-479f-8b44-45f59eef0c53/

The problem is that PUT will end up calling ResetResource which is expected to return a valid resource instance and not null.


Need Your Help

Submitting jobs to different fair scheduler pools while using jar option

hadoop mapreduce

I am relatively new to Hadoop and was trying to have different jobs of the same user submitted to different pools of the fair scheduler at run time while using the hadoop jar option.

Coredump at sem_wait

c linux synchronization ipc fedora

I have a rather strange issue here or I am be ignorant of the way it works, but any way I have the program below that creates the semaphore properly and runs to the end for the first time. But SEGF...