In Visual Studio 2012, LightSwitch data services publish OData feeds and LightSwitch clients consume the OData feeds. This is an implementation change from LightSwitch 2011 where we used WCF RIA Services as the data protocol between client and server.
In this post we’ll take a look at the OData protocol itself and why it is valuable to LightSwitch applications. And we’ll cover a lot of ground related to producing and consuming OData feeds with LightSwitch, including the ability to consume LightSwitch OData feeds from non-LightSwitch clients.
What is OData?
OData is an open REST-ful protocol for exposing and consuming data on the web. It attempts to break down the silos of data that are common across the web by standardizing on the way that data is accessed. Instead of requiring application-specific APIs to access data specific to each application’s web service, OData provides a common way to query and update data via REST. Beth Massi has already published a good introduction to OData and LightSwitch:
By moving the LightSwitch middle-tier services to OData we open up the LightSwitch to a growing ecosystem of OData producers and consumers. A LightSwitch application no longer lives in a silo.
OData allows LightSwitch applications to consume more data sources. There is a growing list of live services and systems support the OData protocol. Some interesting producers for business applications include SAP NetWeaver Gateway and SQL Server Reporting Services.
OData is a a REST protocol based on existing internet standards including HTTP, AtomPub, JSON, and hyper-media design patterns. A main feature of REST APIs is the use of existing HTTP verbs against addressable resources identified in the URI. Conceptually, OData is a way of performing database-style CRUD using HTTP verbs:
Create : POST
The URI specifies the resource (entity set or entity) and the body of the request or response encodes the entity data in AtomPub or JSON format. The top level resource in an OData feed is an entity container. The entity container has one or more entity sets. An entity set contains instances of entities of a given entity type. Entity sets are analogous to Lists or Tables. Entities within the entity set can be addressed individually via key values, or as collections via query options.
OData specifies URI conventions for addressing entity sets, individual entities, and paths to linked entities via navigation properties. It also specifies a simple query language that allows a client to request arbitrary filtering, sorting, and paging. The entity data is encoded in the body of the request or response using uniform AtomPub or JSON formats.
OData is strongly typed. It uses the Entity Data Model (EDM) to describe the entity types, entity sets, and entity relationships in the entity container. The data schema is typically referred to as the metadata. A live OData feed can return a metadata document so that any consumer can discover the resources available and can use the protocol’s URI conventions to address them.
- Get the feed metadata
HTTP GET http://services.odata.org/OData/OData.svc/$metadata
- Get all products
HTTP GET http://services.odata.org/OData/OData.svc/Products
- Get a specific product
HTTP GET http://services.odata.org/OData/OData.svc/Products(1)
- Get the category related to a product
HTTP GET http://services.odata.org/OData/OData.svc/Products(1)/Category
- Get all products where the Rating is >= 3 sorted by Price
HTTP GET http://services.odata.org/OData/OData.svc/Products?$filter=Rating ge 3&$orderby=Price
- Delete a product
HTTP DELETE http://services.odata.org/OData/OData.svc/Products(1)
(TIP: Your browser might have formatted feed reading enabled. To see the XML formatting for these links, turn off feed reading in your browser options.)
You can learn a lot more about OData at www.odata.org.
Producing OData Feeds with LightSwitch
LightSwitch automatically publishes one OData feed per data source that you create or attach to in your LightSwitch project. There is no additional configuration or coding required. LightSwitch exposes the same data model that you define using the LightSwitch entity designer.
Mapping the LightSwitch data model to OData is trivial because both LightSwitch and OData are based on the EDM type system. The entity types, relationships, entity sets and queries that you define in LightSwitch are exposed as resources in the OData feed.
|LightSwitch Element||OData Element|
|Product entity||Product entity type|
|Product.Category navigation property||Product.Category navigation property|
|Products table||Products entity set|
|AvailableProducts query||AvailableProducts function import|
As you can see, there is a fairly direct correspondence between the LightSwitch elements and the corresponding OData elements.
When you publish your LightSwitch application, LightSwitch uses the data source name to construct the base feed URL. By default the “intrinsic” data source is called “ApplicationData”. This is created when you define hew tables in the LightSwitch Data Designer. LightSwitch will use “/ApplicationData.svc” as the feed URL. If you attach to an external SQL database and call the data source “NorthwindData”, LightSwitch will use “/NorthwindData.svc” as the feed URL. To access the Products table in the NorthwindData data source, you’d construct the URL using your web-sites base address.
During F5, these services are addressable via http://localhost at port number selected by the project. This port number will be visible in the Browser URL and in the Windows tray icon. Say the port number is 1234. You can view the OData metadata for your ApplicationData at the following URL.
Securing LightSwitch OData Feeds
Opening your application data via OData raises the obvious question: How do I secure access to my application data?
You can turn on access control for LightSwitch applications using the project settings. LightSwitch supports three authentication settings: None, Forms, and Windows.
When you select Forms, LightSwitch enables two modes of authentication. One is a custom protocol used by the LightSwitch clients Login dialog. This uses a custom web service API to pass credentials and obtain a forms-authentication cookie. If a request for data doesn’t have a valid forms-authentication cookie, LightSwitch will respond with an HTTP Basic challenge. This allows non-LightSwitch clients to pass credentials via a standard HTTP protocol.
If you choose Windows authentication, LightSwitch will require an authenticated Windows user. This works great for in-house applications. LightSwitch doesn’t currently support this option for Azure-hosted services, although you can configure ADFS manually outside of LightSwitch.
Whatever authentication mechanism you use, you should considering transport-level security, via HTTPS, to secure any credentials, tokens, and data that pass on the wire. Without HTTPS, forms and basic credentials will pass in clear text, as will forms-authentication tokens. Windows authentication is more secure, but without HTTPS, any data flowing between client and server will still be clear text. To mitigate this, LightSwitch has a publish setting that causes the runtime to require a secure connection.
With this setting On, LightSwitch will redirect requests from HTTP to HTTPS. But you still need to obtain and configure the HTTPS certificate on your web site.
This version of LightSwitch doesn’t provide a direct mechanism for hiding or excluding entity sets or entity properties from the OData endpoint. Whatever you connect to on the back-end will be visible on the front-end of your service. You can control access to those resources by using the
CanXxx access control methods in your data service code. We have also added true row-level filtering in this release using the
entity_Filter query method, so you can filter out any or all entities from escaping the service interface. Unfortunately, we have no column-level filtering, so a client will either get all or none of the entity.
Here is an example of how to prevent all Update, Delete and Insert from the Animals table.
Consuming LightSwitch OData Feeds from Non-LightSwitch Clients
The OData protocol isn’t specific to .NET or Microsoft. OData feeds published by LightSwitch can be consumed by any OData client on a variety of platforms. By using HTTP Basic authentication, most existing clients will be able to attach to your feed securely.
The two main opportunities this opens up for LightSwitch developers are generic OData clients and custom OData clients.
Many new products like Microsoft PowerPivot and Microsoft Codename “Data Explorer” are generic OData consumers. They are designed for ad-hoc query and analysis of OData feeds. You’ll find several more from on the OData ecosystem web site.
Attaching to External OData Feeds
You can attach to external OData feeds as data sources in your LightSwitch projects. When you attach to another OData feed, LightSwitch fetches the $metadata and imports the external data schema into your LightSwitch project. LightSwitch will list any unsupported data elements at attach time and will not import these into the LightSwitch project. Unfortunately, these data elements will be unavailable to your LightSwitch application. (See Protocol Support below.)
Some OData producers are known to work well with LightSwitch. These are SharePoint 2010 (using the SharePoint option at in the Attach dialog), most feeds produced in Visual Studio with WCF Data Services and Entity Framework, and of course feeds produced by LightSwitch.
Not all OData feeds in the wild support the same level of functionality. Some don’t support pagination, or sorting, or certain kinds of query filters, features that screens use by default. We are still working out the best way to give a great experience using these feeds. Our current thinking is to disable a lot of the built-in query functionality for unknown OData feeds. The developer can progressively turn these features back on after experimenting with the feed and determining what works and what doesn’t.
In the meantime, the LightSwitch team is working with the OData community to find better ways for arbitrary consumers to negotiate capabilities with arbitrary feeds. We are big fans of OData and we want to improve the experience for LightSwitch customers and for other products that adopt OData.
Upgrading from LightSwitch 2011
It was a design principle in LightSwitch 2011 to hide the data-access implementation details, to avoid lock-in to any one data access technology. That decision as paid off. The LightSwitch engineers were able to re-plumb both the LightSwitch client and server using OData and to maintain an extremely high degree of compatibility with earlier APIs and runtime semantics. We replaced our earlier dependency on WCF RIA Services with WCF Data Services (the .NET implementation of OData). We considered the prior WCF RIA Service endpoints to be private, so they no longer exist, but that shouldn’t break anyone. On the server, they are replaced with public OData endpoints.
When you upgrade to Visual Studio 2012, your data model remains the same and any entity and data service pipeline code you wrote stays the same. LightSwitch simply changes the code-generation for the underlying plumbing to use OData instead of WCF RIA Services, as well as updating the LightSwitch runtime libraries.
You might be wondering about custom data sources. Did these go the way of the dodo when we took out WCF RIA Services as our service endpoint? No, we still support using the WCF RIA Services DomainService as a back-end data adapter. These will upgrade and continue to work as-is.
If you’re interested in some low-level details, I’m going to look at the features of the OData protocol that LightSwitch supports, the general runtime architecture, and some client-side optimizations that enhance our use of OData.
OData Protocol Support
OData has published v2.0 of the protocol and has recently announced OData v3.0. The v3.0 protocol isn’t yet finalized and LightSwitch isn’t taking advantage of any v3.0 capabilities.
LightSwitch supports a broad set of the OData 2.0 capabilities:
|Data Types||Most primitive EDM data types, entity types|
|Relationships||Associations, navigation properties, links|
|Feed Formats||atom, json|
|Query Options||Filtering, sorting, paging, count, selection, expansion|
|Query Expressions||OData comparison operators; OData string, date, and math functions|
|Update and Batch||http put, patch, delete, post|
|Concurrency Control||ETags and If-Match headers|
There are certain OData v1.0 and v2.0 features that LightSwitch doesn’t support. These include the DataTimeOffset data type, complex types, inheritance, many-many relationships, media resources, open types, and custom service operations. Each of these has value in certain scenarios. We haven’t excluded any of these on principle or merits. It is just a matter of resources and investment to get new scenarios lit up.
The overall architecture of the LightSwitch client and server doesn’t change too much from LightSwitch 2011. The simplified architecture stacks for client (presentation) and server (logic) tiers now look like the following:
Note that for LightSwitch 2011 you would have seen WCF RIA Services playing a prominent role in both the client and the server. You’ll see that these are simply replaced by WCF Data Services.
Under the hood, we did a lot to ensure that our use of OData maintained compatibility and is as efficient as possible. The OData protocol allows a client to request which related entities should be included in a query by using the $expand option. To avoid server round trips when loading screens, LightSwitch automatically expands screen queries to include related entities that are used in the screen—for example, including the customer and the order lines with the order record. The screen designer has advanced options where you can explicitly control this.
Another optimization we made is to include a RowVersion property for LightSwitch entities. OData uses ETags to handle data concurrency. These ETags can get large if they include original values from all of the entity properties—sometimes too large to fit in the request headers. By using RowVersion, we shrink the ETag to just one property value, while maintaining full support for concurrency checking and resolution. The introduction of a RowVersion also makes concurrency more robust because all properties are considered whereas in the past we excluded potentially large values like text, binary, and images.
The LightSwitch data pipeline lets you publish OData safely. You can secure your feeds via HTTPS and use LightSwitch access control mechanisms like Basic and Windows authentication and permissions-based authorization. You can use the LightSwitch query and update pipelines to control access to data, keep the data clean, and manage business rules—regardless of which client is using the data.
How will you use OData with LightSwitch in your business applications? What new scenarios can you accomplish? What else do you need in OData in specific and data access in general? Give it a try, and let us know what you think!
John Rivard, LightSwitch Team