New Posts New Posts RSS Feed: OData samples
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

OData samples

 Post Reply Post Reply Page  12>
Author
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Topic: OData samples
    Posted: 10-Dec-2010 at 9:17pm
Any word on a basic sample or tutorial on using the new OData capabilities?

Wow this is going to be easy! I have it exposed and I can see the entities and their definitions in LINQPad when browsing to the service.

Had some errors in the beginning, but it turned out to be a connection string problem. This is awesome!!!


Edited by smi-mark - 10-Dec-2010 at 10:14pm
Back to Top
benmcneill View Drop Down
Newbie
Newbie
Avatar

Joined: 26-Aug-2010
Posts: 11
Post Options Post Options   Quote benmcneill Quote  Post ReplyReply Direct Link To This Post Posted: 12-Dec-2010 at 6:43am
A sample would be great indeed! :)
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 12-Dec-2010 at 4:22pm
It's actually very simple. This is what I did:

1) Create a web project in Visual Studio
2) Either create a separate model project, or add the edmx to the web project
3) Map it to Northwind or your own database
4) In the edmx properties make sure to enable OData
5) Create a new WCF Data Serive in your web project called OData.svc or whatever you like
6) Inherit this new class from your entity manager. Example "public class OData : DataService<NorthwindIBEntities>"
7) In the static InitializeService, set your access rules. Example "config.SetEntitySetAccessRule("Employees", EntitySetRights.All);"
8) Test it out :)


Edited by smi-mark - 12-Dec-2010 at 4:22pm
Back to Top
benmcneill View Drop Down
Newbie
Newbie
Avatar

Joined: 26-Aug-2010
Posts: 11
Post Options Post Options   Quote benmcneill Quote  Post ReplyReply Direct Link To This Post Posted: 12-Dec-2010 at 9:46pm
Thanks!

Where do I find initializeservice?

And then do I just build, then go to my client Silverlight project, and call, for example: (Where EncryptMethod is a Service Method):

TestENTITIES test = new TestENTITIES();
string unencrypted = "unencryptedtext";
string EncryptedText = test.EncryptMethod(unencrypted);

The TestENTITIES isn't givng me the Service Methods on the client yet.
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 12-Dec-2010 at 11:20pm
Silverlight project? This is to expose your DevForce object as an OData source. I'm not sure what you are doing with a Silverlight client?
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 13-Dec-2010 at 11:24am
Hi all,
Just a quick post. Tutorial and samples are coming shortly. In the meantime as smi-mark posted, there isn't much involved in getting your domain model exposed through OData. Microsoft provides the WCF Data Services, which implement all the OData goodies. Once you have OData enabled in the edmx, all you need to do is add a WCF Data Service to your project like this one:
    public class MyData : DataService<NorthwindIBEntities>
    {
        // This method is called only once to initialize service-wide policies.
        public static void InitializeService(DataServiceConfiguration config)
        {
            config.UseVerboseErrors = true;
            // TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
            config.SetEntitySetAccessRule("Customers"EntitySetRights.All);
            config.SetEntitySetAccessRule("Orders"EntitySetRights.All);
            config.SetEntitySetAccessRule("Employees"EntitySetRights.All);

            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
        }
    }
}
This example exposes the NorthwindIB Customer, Order and Employee entities with full CRUD over OData.
 
There are various OData client libraries for all kinds of platforms that make it easy to consume an OData service on the client. The first example will be a little Windows Phone 7 demo.
 
If you are running into any issues, I'd love to hear about them.
 
Marcel Good
Senior Director of Professional Services
IdeaBlade
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 13-Dec-2010 at 11:38am
Originally posted by benmcneill

Thanks!

Where do I find initializeservice?

And then do I just build, then go to my client Silverlight project, and call, for example: (Where EncryptMethod is a Service Method):

TestENTITIES test = new TestENTITIES();
string unencrypted = "unencryptedtext";
string EncryptedText = test.EncryptMethod(unencrypted);

The TestENTITIES isn't givng me the Service Methods on the client yet.
 
If you want to call an OData service from Silverlight or full .NET for that matter, just add a service reference to your project. Visual Studio will recognize that it is an OData web service and create the propery client classes.
 
Here's an example of a .NET TestClass that exercies the NorthwindIB OData service from my earlier post.
 
    [TestClass]
    public class ODataCRUDTests
    {
        public ODataCRUDTests()
        {
            context = new NorthwindIBEntities(new Uri("http://localhost:9009/MyData.svc"));
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        // Use TestInitialize to run code before running each test 
        // [TestInitialize()]
        // public void MyTestInitialize() { }
        //
        // Use TestCleanup to run code after each test has run
        // [TestCleanup()]
        // public void MyTestCleanup() { }
        //
        #endregion

        [TestMethod]
        public void then_can_get_Customers()
        {
            var customers = context.Customers.ToList();

            Assert.IsTrue(customers.Any(), "Should have some customers");
        }

        [TestMethod]
        public void then_can_get_Customer_Orders()
        {
            var customer = context.Customers.First();
            Assert.IsTrue(customer != null"We should have a customer");

            context.LoadProperty(customer, "Orders");
            Assert.IsTrue(customer.Orders.Any(), "We should have orders");
        }

        [TestMethod]
        public void then_can_modify_Customer()
        {
            var customer1 = context.Customers.First();
            string newRegion = Guid.NewGuid().ToString().Substring(0, 15);

            customer1.Region = newRegion;

            context.UpdateObject(customer1);
            context.SaveChanges();

            var query = from c in context.Customers
                        where c.CustomerID == customer1.CustomerID
                        select c;

            var customer2 = query.FirstOrDefault();

            Assert.IsTrue(customer2 != null && customer2.Region == newRegion, "Customer should have been updated");
        }

        [TestMethod]
        public void then_can_add_Customer()
        {
            Customer customer = Customer.CreateCustomer(Guid.NewGuid());

            string companyName = Guid.NewGuid().ToString();
            customer.CompanyName = companyName;

            context.AddToCustomers(customer);
            context.SaveChanges();

            Assert.IsTrue(context.Customers.Where(c => c.CompanyName == companyName).ToList().Any(),
                          "The new customer should have been added");
        }

        [TestMethod]
        public void then_can_delete_Customer()
        {
            var customers = (from c in context.Customers
                             where c.CustomerID_OLD == null
                             select c).ToList();

            Assert.IsTrue(customers.Any(), "No customers to delete. Please add a test customer first");

            context.DeleteObject(customers.First());
            context.SaveChanges();

            var customers2 = (from c in context.Customers
                              where c.CustomerID_OLD == null
                              select c).ToList();

            Assert.IsTrue(customers2.Count == customers.Count - 1, "We should have one less customers");
        }

        [TestMethod]
        public void then_can_add_new_Order_to_Customer()
        {
            var customer = context.Customers.FirstOrDefault();
            Assert.IsTrue(customer != null"Should have a customer");

            context.LoadProperty(customer, "Orders");
            var numberOfOrders = customer.Orders.Count();

            var shippingAddress = new ShippingAddress();
            shippingAddress.ShipAddress = "111";
            shippingAddress.ShipCity = "Emeryville";
            shippingAddress.ShipPostalCode = "11111";

            var order = Order.CreateOrder(-1, 1, shippingAddress);
            context.AddRelatedObject(customer, "Orders", order);
            context.SaveChanges();

            context.LoadProperty(customer, "Orders");
            Assert.IsTrue(customer.Orders.Count() == numberOfOrders + 1, "This customer should have one more order");
        }

        [TestMethod]
        public void then_can_support_calculated_Properties_in_partial_Entity_Class()
        {
            var customer = context.Customers.FirstOrDefault();

            Assert.IsTrue(customer.TestCalculatedProperty == "Test""Calculated property should be set");
        }

        [TestMethod]
        public void then_can_set_Employee_Birthday_to_null()
        {
            var employee = context.Employees.Where(e => e.BirthDate != null).First();
            Assert.IsNotNull(employee, "We need an employee with a BirthDate");

            employee.BirthDate = null;

            context.UpdateObject(employee);
            context.SaveChanges();

            var query = from e in context.Employees
                        where e.EmployeeID == employee.EmployeeID
                        select e;

            var employee2 = query.FirstOrDefault();
            Assert.IsNull(employee2.BirthDate, "Birthdate should be null");
        }

        private NorthwindIBEntities context;
    }
}
Back to Top
chuckc View Drop Down
Groupie
Groupie


Joined: 27-Feb-2010
Posts: 54
Post Options Post Options   Quote chuckc Quote  Post ReplyReply Direct Link To This Post Posted: 07-Jan-2011 at 8:52pm
Thanks for the sample - good stuff!

I've been able to get things working when including the edmx / data model in the same project as the odata webservice, but no success when separating the data model into a different assembly.  I get "The server encountered an error processing the request. See server logs for more details."  I did set  includeExceptionDetailInFaults="true" in the web config, but that doesn't provide any additional information.  The InitializeService() method in the web service project isn't even getting called.  
Any ideas?  Are there additional configuration steps required when using a separate data assembly?

Thanks much.
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 11-Jan-2011 at 12:08pm
Originally posted by chuckc

Thanks for the sample - good stuff!

I've been able to get things working when including the edmx / data model in the same project as the odata webservice, but no success when separating the data model into a different assembly.  I get "The server encountered an error processing the request. See server logs for more details."  I did set  includeExceptionDetailInFaults="true" in the web config, but that doesn't provide any additional information.  The InitializeService() method in the web service project isn't even getting called.  
Any ideas?  Are there additional configuration steps required when using a separate data assembly?

Thanks much.
My hunch is your namespaces are messed up and the DevForce code needs to be re-generated.
 
To rule out any other issues, set the default namespace of the data model assembly to the same namespace as the OData webservice. Then delete the edmx.tt file and <EntityManager>_IUpdatable.cs from the project and file system. Open up the edmx file and set "OData Enabled" to false. Save the edmx. Then change "OData Enabled" back to true and save again.
 
If you run the server in the debugger, you should see a more detailed exception and it probably says something that it can't find a certain class in your model.
 
Generally, when you break out the model into a seperate assembly you have to set the default namespace correctly in the new assembly and re-generate the DevForce code. This is true for non-OData projects as well.
Back to Top
GeorgeB View Drop Down
Groupie
Groupie


Joined: 03-May-2010
Posts: 66
Post Options Post Options   Quote GeorgeB Quote  Post ReplyReply Direct Link To This Post Posted: 12-Jan-2011 at 6:14am
How do we handle security?
 
I have implemented IEntityLoginManager for my Silverlight application.
 
I tried setting NetworkCredential with no luck.
 
Kr
George
Back to Top
mgood View Drop Down
IdeaBlade
IdeaBlade
Avatar

Joined: 18-Nov-2010
Location: Emeryville, CA
Posts: 583
Post Options Post Options   Quote mgood Quote  Post ReplyReply Direct Link To This Post Posted: 12-Jan-2011 at 6:32am
Originally posted by GeorgeB

How do we handle security?
 
I have implemented IEntityLoginManager for my Silverlight application.
 
I tried setting NetworkCredential with no luck.
 
Kr
George
You have to use ASP.NET security and enable ASP.NET authentication in DevForce, so both WCF and DevForce use the same security provider. Because the WCF Data Service is outside of DevForce, it is not going to work with a DevForce custom login. You have to handle security at the WCF layer. See our wiki for more information on ASP.NET security.
Back to Top
GeorgeB View Drop Down
Groupie
Groupie


Joined: 03-May-2010
Posts: 66
Post Options Post Options   Quote GeorgeB Quote  Post ReplyReply Direct Link To This Post Posted: 12-Jan-2011 at 6:37am
I was worried you would say that.
 
I'm hosting in Windows Azure and really don't want to go the route of using ASP.Net Authentication.
Back to Top
chuckc View Drop Down
Groupie
Groupie


Joined: 27-Feb-2010
Posts: 54
Post Options Post Options   Quote chuckc Quote  Post ReplyReply Direct Link To This Post Posted: 06-Feb-2012 at 1:52pm
 Finally getting back to this, and have discovered that my Entity base class is causing the problem.  I've stripped it down to the minimum that causes the failure, which is:

using IdeaBlade.EntityModel;

namespace DomainModel
{

    public partial  class SimpleBase : Entity
    {
        public iCatEntityManager iCatalystEntityManager
        {
            get
            {
                if (null != this.EntityAspect.EntityManager)
                {
                    return (this.EntityAspect.EntityManager as iCatEntityManager);
                }
                else
                {
                    return null;
                }
            }
        }

    }
}

Converting the property to a Get iCatalystEntityManager() method seems to fix it.  So is this a serialization issue?

It took way too much trial and error to figure this out.  Is there some way to get decent debug info?

Thanks

Back to Top
chuckc View Drop Down
Groupie
Groupie


Joined: 27-Feb-2010
Posts: 54
Post Options Post Options   Quote chuckc Quote  Post ReplyReply Direct Link To This Post Posted: 06-Feb-2012 at 2:02pm
Also discovered that having a property such as the following causes the odata service to silently fail, too.

private Dictionary<string, string> _errors;
        public Dictionary<string, string> Errors
        {
            get { return _errors ?? (_errors = new Dictionary<string, string>()); }
        }

So evidently Dictionary<string, string> can't be serialized out through odata.  Is that correct?  Or is there some attribute that can be added to the property declaration to fix things up?  Something like [ODataIgnore]?

Thanks
Back to Top
chuckc View Drop Down
Groupie
Groupie


Joined: 27-Feb-2010
Posts: 54
Post Options Post Options   Quote chuckc Quote  Post ReplyReply Direct Link To This Post Posted: 06-Feb-2012 at 2:26pm
Tried a couple things, with no success.

  [IgnoreProperties(@"Errors")]

at the class level, and 

        [IgnoreDataMember]
        public Dictionary<string, string> Errors
        {
            get { return _errors ?? (_errors = new Dictionary<string, string>()); }
        }

Neither attribute appears to be recognized by the odata service serializer.
Back to Top
chuckc View Drop Down
Groupie
Groupie


Joined: 27-Feb-2010
Posts: 54
Post Options Post Options   Quote chuckc Quote  Post ReplyReply Direct Link To This Post Posted: 07-Feb-2012 at 7:17am

Here's some info I found helpful in debugging odata.

http://blogs.msdn.com/b/phaniraj/archive/2008/06/18/debugging-ado-net-data-services.aspx

With this debugging turned on, I get the following, actually helpful, debug info:


The server encountered an error processing the request. The exception message is 'The property 'Errors' on type 'DomainModel.User' is not a valid property. Make sure that the type of the property is a public type and a supported primitive type or a entity type with a valid key or a complex type.'. See server logs for more details. The exception stack trace is:

at System.Data.Services.Providers.ReflectionServiceProvider.BuildTypeProperties(ResourceType parentResourceType, IDictionary`2 knownTypes, IDictionary`2 childTypes, Queue`1 unvisitedTypes, IEnumerable`1 entitySets) at System.Data.Services.Providers.ReflectionServiceProvider.PopulateMetadataForTypes(IDictionary`2 knownTypes, IDictionary`2 childTypes, Queue`1 unvisitedTypes, IEnumerable`1 entitySets) at System.Data.Services.Providers.ReflectionServiceProvider.PopulateMetadata(IDictionary`2 knownTypes, IDictionary`2 childTypes, IDictionary`2 entitySets) at System.Data.Services.Providers.BaseServiceProvider.PopulateMetadata() at System.Data.Services.DataService`1.CreateProvider() at System.Data.Services.DataService`1.HandleRequest() at System.Data.Services.DataService`1.ProcessRequestForMessage(Stream messageBody) at SyncInvokeProcessRequestForMessage(Object , Object[] , Object[] ) at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs) at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc& rpc) at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc& rpc) at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)

Back to Top
 Post Reply Post Reply Page  12>

Forum Jump Forum Permissions View Drop Down