Welcome to MSDN Blogs Sign in | Join | Help

What is the OData Explorer ?

As the name suggests, its a Silverlight application that can be installed in-browser and out of browser , and allows
you to perform ad-hoc and guided queries across a given OData Service.

Where can I get the sources for the OData Explorer ?

In the “OData SDK - Sample Code” section of http://www.odata.org/developers/odata-sdk

The Service I am browsing to doesn’t have a ClientAccessPolicy.xml or CrossDomain.xml file , Can I use the ODataExplorer against it ?

Yes, install the application out of browser by clicking the “Install” button and you will not need to have the CAP.xml or CrossDomain.xml file on the server-side to allow querying the OData Service.

Depending on whether you have a previous version of Silverlight installed, browsing to http://Silverlight.net/ODataExplorer will have one of the following effects :

a) If you have an older version of SL is installed, it will prompt you to upgrade to the required version of Silverlight and clicking on it will take you to the window shown below.

b) If you don’t have any version of Silverlight installed, you will see this icon :

Install_SL_NotInstalled

Clicking the “Upgrade” or “Install” button will take you to this screen.

Install_SL4

Now , don’t panic, since this is a Developer-only release of Silverlight 4 , you will need to install the developer runtime.

Click  the link highlighted in the picture about , and you will be taken to this page : http://silverlight.net/getstarted/silverlight-4/

In this page , select the “Windows Runtime” link under the “Get the Tools” section.

For brevity , here is the download link for the SL4 runtime.

Let’s look at an example of browsing to an OData Service using the explorer.

Browsing the Netflix OData Service using the explorer

1. Navigate to http://silverlight.net/ODataExplorer

2. In the prompt that turns up , enter details for the Netflix service as shown below

Enter_netflix_DataService

Clicking “Ok” in the above dialog box will download the metadata and the service document for the
netflix Data Service and show the Collections available in the Service document.

netflix_DataService_ReadyToUse

Selecting the name of a collection is going to cause the Explorer to hit the Collection root
and download the OData feed for that collection.
For example , selecting the CatalogTitles collection gives us this : 
CatalogTitlesSet_Downloaded

The navigation properties which are Links in the Data grid should allow you to drill further into the set.

Clicking on the “Raw” tab is going to show you details about the request and the raw view of the data.

You can change the content-type  to be JSON and see the response in JSON format.

rawView

I’ll be doing more blog posts about using the Explorer and look forward to your comments/feedback.
I’d be happy to answer any questions about the tech behind this tool and how you can use the
metadata parser library which we use in this tool to discover entity sets and other associated metadata.

Yep , we now have open positions for a few testers who get to work on the next generation of Data Protocols.
Some advantages of working on the team :

1. You get to work with Pablo Castro

2. We have annual ski events which are always fun

3. The team is filled with some of the smartest people you’ll come to know

4.  You get to own and deliver key components of the Astoria runtime while learning a lot about data and REST

How do I apply ?

Send an email to PhaniRaj@Microsoft.com with your resume and “Astoria/EF Team Referal" :<YourNameHere>” in the subject.

   ( or )

Apply via the Job site and put in my alias “PhaniRaj” as the referal .

The job descriptions :

Open positions on the Astoria Team:

https://careers.microsoft.com/JobDetails.aspx?ss=&pg=0&so=&rw=1&jid=11878&jlang=EN

Open positions on the EF Team :

https://careers.microsoft.com/JobDetails.aspx?ss=&pg=0&so=&rw=1&jid=11877&jlang=EN

While developing an application that spans multiple tiers , it is important that you be able to flow error information through the tiers without losing
any context or details in the tiers. With ADO.NET Data Services , we have an error contract which guarantees that all errors thrown from the Data Service ,
wrapped inside a DataServiceException , will be represented in a standard way on the wire when we send the error down to the client.

For example , consider the Query Interceptor shown below .

[QueryInterceptor("Customers")]
public Expression<Func<Customers, bool>> OnQueryCustomers()
{
        string loggedInUser = HttpContext.Current.User.Identity.Name;
        if (UserHasAccessToSet("Customers", loggedInUser))
        {
            //Filter Expression goes here
            return entity => true;
        }
        else //User does not have access to '/Customers' , throw AccessViolationException
        {
            throw new DataServiceException(403,
                "Forbidden",
                String.Format("User '{0}' cannot request data from '{1}' table", loggedInUser, "Customers"),
                "en-US");
        }
}

When the Astoria server runtime throws the above exception , the 403 value specified above  gets turned into the response status code of the request
which caused this exception.

StatusCodeInFiddler 

and the error message is serialized out to be in this format :

<?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code>Forbidden</code> 
  <message xml:lang="en-US">User 'NoPermissions' cannot request data from 'Customers' table</message> 
</error>

At this point , the service has not lost any information that the service author intended to convey to a service consumer.

Now , lets consider the client library and how it handles this case.
Lets consider a query for the “Customers” set to which the currently logged-in user doesn't have permissions.

foreach (Customers customerEntity in northwindContext.CreateQuery<Customers>("Customers") ) {
 //Do something with the customerEntity here
}

In this case, running the above code  would result in a DataServiceQueryException being thrown.

System.Data.Services.Client.DataServiceQueryException: 
  An error occurred while processing this request. --->        
System.Data.Services.Client.DataServiceClientException: <?xml version="1.0" encoding="utf-8" standalone="yes"?> <error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"> <code>Forbidden</code> <message xml:lang="en-US">User 'NoPermissions' cannot request data from 'Customers' table</message> </error>

Note that the DataServiceException thrown by the server is now set to the Message property of the InnerException of the DataServiceQueryException.
We do not de-serialize the DataServiceException into an exception type on the client side.
By default , since the exception is now a string on the client side , you don’t have direct  access to the information contained inside the Exception.
The information is all still there , just not easily accessible anymore. Since the error contract is documented and follows a standard pattern ,
we can easily write a visitor that de-serializes an exception object from the “Message” property  of the Inner Exception.

One such de-serializer for Error contracts is shown at the bottom of this post
It contains two methods :

  1. TryParse : which takes in an exception caused during Querying or updating via the client library and
    returns a DataServiceException that was thrown by the Server
  2. Throw : which takes in an exception caused during Querying or updating via the client library and
    re-throws the DataServiceException that was thrown by the Server


The new Java client joins a growing family of clients for ADO.NET Data Services, which include:

Ajax , Silverlight , .Net FX ,Dynamic Data, PHP .

Here’s some documentation about the Java client http://wiki.restlet.org/docs_2.0/13-restlet/28-restlet/287-restlet.html.

Click here to download sample application 

Using the ADO.NET Data Services Silverlight client library in x-domain and out of browser scenarios – II (Forms Authentication)
In this blog post, we will talk about using the Silverlight Client Library against a Data Service that is secured with Asp.Net Forms Authentication
In short, the whole process of authenticating against a Forms Authentication protected Data Service looks like this.
image

Server Setup

  1. Setup Forms Authentication on the Data Service Server
  2. Enable the WCF Authentication Service by following the reference here : How to: Enable the WCF Authentication Service
  3. Exclude the following resources from requiring authentication ,

3.1 The WCF Authentication Service
3.2 The ClientAccessPolicy.xml File
Ex:

<!-- The ClientAccessPolicy.xml file is required for the client to confirm if the server allows X-Domain callers.
       This should be downloadable without authenticating-->
 <location path="clientaccesspolicy.xml">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
  </location>
 <!--This should be downloadable without authenticating.-->
  <location path="AuthenticationService.svc">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
  </location>

4. If the DataServiceHost does not have a global.asax file, add one to the project.
5. In the Global.asax file, we need to listen on the AuthenticationService.CreatingCookie event to customize the FormsAuth Cookie that the service creates.

Why do we need to customize the FormsAuth cookie?
The WCF Authentication service by default creates HTTPOnly Cookies.
This means that the cookie isn’t accessible by client-script.
It generally isn’t a problem when the client application is running in the same domain as the Website,
as the browser handles cookie management for us transparently.
When the client is not in the same domain as the Website, and we use the ClientHttpWebRequest networking stack,
we are unable to access any cookies marked as HttpOnly.
To work around this limitation, we recreate the FormsAuth cookie with HttpOnly set to false in the CreatingCookie event handler.
For more details: How to: Customize the Authentication Cookie from the WCF Authentication Service
Example code:

protected void Application_Start(object sender, EventArgs e)
{
//Handle the CreatingCookie event so that we can create a custom cookie with HttpOnly set to false.
//AuthenticationService.CreatingCookie on MSDN :
//http://msdn.microsoft.com/enus/library/system.web.applicationservices.authenticationservice.creatingcookie.aspx
AuthenticationService.CreatingCookie += new EventHandler<CreatingCookieEventArgs>(CreateSilverlightCompatibleHttpCookie);
}


/// <summary>
/// Creates a HttpCookie that can be read by the managed CookieContainer in ClientHttpWebRequest in Silverlight
/// </summary>
/// <param name="sender">The calling context for this event</param>
/// <param name="e">a property bag containing useful information about the HttpCookie to create</param>
void CreateSilverlightCompatibleHttpCookie(object sender, System.Web.ApplicationServices.CreatingCookieEventArgs e)
{
  int cookieVersion = 1;
  //The time at which the cookie was issued by the server
  DateTime cookieIssueDate = DateTime.Now;
  //The relative time from now when the cookie will expire and the client will have to re-authenticate.
  DateTime cookieExpiryDate = DateTime.Now.AddMinutes(30);
  //The Forms Auth ticket which uniquely identifies a user 
  //FormsAuthenticationTicket on MSDN : http://msdn.microsoft.com/en-us/library/system.web.security.formsauthenticationticket.aspx
  FormsAuthenticationTicket ticket = new FormsAuthenticationTicket
                (cookieVersion,
                 e.UserName,
                 cookieIssueDate,
                 cookieExpiryDate,
                 e.IsPersistent, /*Indicates whether the authentication cookie should be retained beyond the current session*/
                 e.CustomCredential,
                 FormsAuthentication.FormsCookiePath);
 //Creates a string containing an encrypted forms-authentication ticket suitable for use in an HTTP cookie.
 //FormsAuthentication.Encrypt on MSDN : http://msdn.microsoft.com/en-us/library/system.web.security.formsauthentication.encrypt.aspx
  string encryptedTicket = FormsAuthentication.Encrypt(ticket);
  HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
  //set HttpOnly to false so that the managed CookieContainer can read the FormsAuth cookie from the response.
  cookie.HttpOnly = false;
  cookie.Expires = cookieExpiryDate;
  HttpContext.Current.Response.Cookies.Add(cookie);
  e.CookieIsSet = true;
 }

Silverlight Client Setup

We will follow an adapter pattern which is responsible for logging in the user and injecting the FormsAuth cookie as the client library makes requests.
To start with, add a Service reference to the WCF Authentication service in the Silverlight Client application or use the one in the sample.

The FormsAuthAdapter will use the client side proxy generated for the WCF Authentication service to login the user
and hook into any attached DataServiceContext instance’s SendingRequest event to inject the FormsAuth cookie.
An instance of the FormsAuthenticationAdapter is declared at the application level.

public partial class App : Application
{
/// <summary>
/// FormsAuthenticationAdapter instance to manage authentication against a WCF Authentication Service
/// </summary>
public static FormsAuthenticationAdapter FormsAuthAdapter;


This is initialized when the Application starts.

private void Application_Startup(object sender, StartupEventArgs e)
{
string authServiceUri = String.Empty;
//extract the AuthenticationService Uri from the App.XAML file
if (this.Resources.Contains("AuthenticationServiceUri"))
{
authServiceUri = this.Resources["AuthenticationServiceUri"].ToString();
}
FormsAuthAdapter = new FormsAuthenticationAdapter(new Uri(authServiceUri, UriKind.RelativeOrAbsolute));
//The FormsAuthCookieName  should be the same value as declared in the Web.config of the server
//ex: If your web.config on the server requiring Forms Authentication is :
//<authentication mode="Forms">
//  <forms loginUrl="LoginForm.aspx" name=".ASPXFormsAUTH" protection="All" path="/" />
//</authentication>
    FormsAuthAdapter.FormsAuthCookieName = ".ASPXFormsAUTH";
    this.RootVisual = new MainPage();
    //Uncomment the below 2 lines to show the Loginwindow on application startup
    //LoginWindow login = new LoginWindow();
    //login.Show();
}

This is what our client application looks like:
image

As you can see, along with the “Install me” button, we now have a “Login” button.

When the page loads, we attach an instance of the DataServiceContext which we want to get the FormsAuth Cookie injected while
making requests to the Data Service.

//Attach the DataServiceContext instance so that we can inject the FormsAuth cookie for each request
App.FormsAuthAdapter.Attach(publicationContext);
Where the Attach Method’s signature is :
/// <summary>
/// Injects the FormsAuth cookie when the contextInstance makes a request to the DataService
/// </summary>
/// <param name="contextInstance">The DataServiceContext instance to observe</param>
public void Attach(DataServiceContext contextInstance)

Clicking the login button on the main page opens up a ChildWindow instance that we created which emulates the Login Screen.

Login button click handler:

void LoginUser(object sender, RoutedEventArgs e)
{
    LoginWindow login = new LoginWindow();
    login.Show();
    //The LoginWindow only closes if Authentication succeeds
    login.Closing += (s, eArgs) =>
    {
       /*If auth succeeds,hide the button*/
       btnLogin.Visibility = Visibility.Collapsed;
    };
  }

image
The LoginWindow’s “Login” button uses the application wide FormsAuthenticationAdapter instance, discussed above, to login the user.

private void LoginUser(object sender, RoutedEventArgs e)
{
App.FormsAuthAdapter.LoginAsync(txtUserName.Text, txtPassword.Password,
    (loginEventArgs) =>
    {
      if (loginEventArgs.Result)
       {
         /*Login succeeded*/
         this.DialogResult = true;
       }
       else
      {
         /*Login failed*/
      }
    }
    );
}
The LoginAsync method’s signature is:
  /// <summary>
/// Logs in the User and calls the LoginComplete handler
/// </summary>
/// <param name="userName">UserName to login </param>
/// <param name="passWord">password for the user account</param>
/// <param name="pLoginComplete">Called when the login process is complete</param>
public void LoginAsync(string userName, string passWord, Action<LoginCompletedEventArgs> pLoginComplete)



Once the user types in his/her username and password and hits “Login” , the Login window hits the WCF authentication service
and extracts the FormsAuth cookie from the response.When the client library makes a request to the Data Service , the FormsAuthenticationAdapter
injects the FormsAuth cookie

Common errors:

1. You receive an ArgumentException when trying to set the cookie header in the SendingRequest event.

a. System.ArgumentException occurred
  Message="The 'Cookie' header cannot be modified directly.\r\nParameter name: name"
  StackTrace:
       at System.Net.WebHeaderCollection.ThrowOnRestrictedHeader(String name, String value)
  InnerException:

Resolution: The reason you get this is because the client library is using the classic networking stack (based on XmlHttpRequest)
to make the request. In this case, the Cookie header isn’t accessible and the above exception is valid.
This is probably the only case where we would ask you to set the HttpStack property on the Client library.
To fix this:
//Set the HttpStack on the client Context instance to force the client library

//to use the ClientHttpWebRequest stack for network access
publicationContext.HttpStack = HttpStack.ClientHttp;

Additional resources:

How do I authenticate my users against the Active Directory from my Silverlight application?
In ASP.NET Forms Authentication, the Membership provider is responsible for accessing the Credential store and validating the user name and password.
By setting the Membership provider to be the ActiveDirectoryMembershipProvider , you can authenticate the user name and password the user enters
with the credentials stored in Active Directory. For more details , please refer to this MSDN article :

Using the ActiveDirectoryMembershipProvider
References :

About ClientAccessPolicy.xml files
ASP.NET Application Services.
ASP.NET Forms Authentication
Membership Providers

  1. Setup PHP on your windows machine
  2. Setup the PHP Toolkit
  3. Setting up the PHP samples on IIS
  4. Running the sample ADO.NET Data Services
  5. PHP Sample Applications Walkthrough

Setup PHP on your windows machine

The following steps show you how to setup your windows machine to host PHP applications.
We will be talking about hosting the only supported ( by MS Support ) PHP CGI application on IIS .

Using FastCGI to Host PHP Applications on IIS 7.0

  1. If you don’t find the php.ini-recommended file , then rename the php.ini-development file from your PHP folder.
  2. Once you are setup , if you get a HTTP 500 internal server error when browsing to the Php.ini file ,
    then you need setup your timezone in the PHP.ini file .
  3. To do this , find the line in the php.ini file “date.timezone” .
  4. If it has a semi-colon before it , remove it .
  5. Set the date.timezone’s  value to be a valid value from this list : List of Supported Timezones

In my php.ini , I have set the value to be date.timezone = "America/Los_Angeles"

Setup the PHP Toolkit

Follow the instructions on the codeplex site to setup your machine.
Installation and Configuration

Setting up the PHP samples on IIS

I have copied the phpsamples folder from the downloaded phpdataservices1.0 folder
into the %SystemDrive%\inetpub\wwwroot folder.This is just so that I dont need to configure any permissions
for the IIS accounts.
Open the IIS manager by running “INETMGR” from the “run” prompt on the start menu

Select the PHPSamples folder from the “Default Web Site”
Samples_Not_Application

Right-Click the Virtual directory and select “Convert to Application”
Samples_To_Application

Confirm creating the virtual directory by  pressing “OK” in the next dialog that turns up
Samples_To_Application_Confirm

This sets up the PHP applications that access the ADO.NET Data Service,
We still need to setup the actual Data Services that the PHP Samples access.

Running the sample  ADO.NET Data Services

Find the ADODotNetDataServices folder in the PHPDataServices1.0 download.
This should be under the “samples” directory.
i.e PHPDataServices1.0\samples\ADODotNetDataServices

Setup the Databases required for the project to run

1) Unzip the zipped database files from the

PHPDataServices1.0\samples\ADODotNetDataServices\data folder.
2)   Open up SQL management studio and Connect to your Database server
3) Right–click the databases node and select “Attach…”

Attach_DB_Step_1

4) In the “Attach Database” dialog , press “Add” and select the unzipped “VideoGameStore_Data.mdf” file.
You will notice that once you select the MDF file  , the dialog will complain about a missing .ldf file.
5) This is a routine warning , select the ldf file row in the dialog and press “Remove”
 Attach_DB_Step_2

For the other database Northwind, you can use the sample database that are available from Download.Microsoft.com
Here’s a link to download the Northwind sample database : Northwind and pubs Sample Databases for SQL Server 2000
Installation should be straight-forward as it comes with an MSI that is supposed to setup the database for you.

Disclaimer : I already had a copy of the Northwind database on my machine and didn’t use the installer above.
 
Once you have your databases setup , modify the respective connection strings web.config file from the ADODotNetDataServices project.

<connectionStrings>
    <add name="NorthwindEntities" 
connectionString="metadata=res://*/NorthwindModel.csdl|res://*/NorthwindModel.ssdl|res://*/NorthwindModel.msl;
provider=System.Data.SqlClient;
provider connection string=
&quot;YOURCONNECTIONSTRINGHERE&quot;"
providerName="System.Data.EntityClient" /> <add name="VideoGameStoreEntities"
connectionString="metadata=res://*/VideoGameStoreModel.csdl|res://*/VideoGameStoreModel.ssdl|res://*/VideoGameStoreModel.msl;
provider=System.Data.SqlClient;
provider connection string=
&quot;YOURCONNECTIONSTRINGHERE&quot;"
providerName="System.Data.EntityClient" /> </connectionStrings>
  1. Once you have the database and the Data Service setup, then configure the project to only run on the URL that the PHP Samples expect to find the Data Service on.
    To do this :
    In Visual Studio,Go to the properties of the Project.
  2. Click on the “Web” Tab in the left-hand pane.
  3. Under the “Servers” section , Select the “Specific Port”  option and enter “8080” for the port number.
    Setup_DataService_Select_Port
  4. Now, run the project in Visual studio and launch the PHP samples by browsing to the Index.php page
    in the PHPSamples virtual directory.

PHP Sample Applications Walkthrough

You should see this as the startup page when you run the PHP Samples
PHP_SAMPles_Screen1
Demo tab contents
PHP_SAMPles_Screen_Samples1

Select the ADO.NET Data Services Editor Sample to see some pure PHP awesomeness
PHP_SAMPles_Screen2

Here’s an editor page for the Customers Entity Set:
Customers_Edit_Screen

See that little text box over there ?
Yeah , it allows me to enter the Astoria URI operators like top , skip , filter to filter the rows bound to the grid below.
The gird is editable too , Clicking on the “Detail” link in the first column of the grid brings up an editor for the customers
entity that was selected.
Customers_Edit_Screen_2

So , there you have it , instructions to setup the samples and some tours of the sample applications.
Since I know next to nothing about PHP , I have a few questions for our PHP-Savvy users.

  1. Which application framework(s) do you use  to build PHP applications? I know about CAKE and ZEND , any others?
  2. Do you use a specific Validation framework or do you use the one that came with the  application framework?

The first in my two part blog posts about the new Silverlight Client Library we released in CTP2 is up on the team blog.

Using the ADO.NET Data Services Silverlight client in x-domain and out of browser scenarios – I

Stay tuned to the team blog for the the second  part which talks about using the client library X-Domain and Out Of Browser
to access a data service which is authenticated with Forms Authentication.

Announcement on the team blog :

http://blogs.msdn.com/astoriateam/archive/2009/08/31/ado-net-data-services-v1-5-ctp2-now-available-for-download.aspx

Download the bits here :

http://www.microsoft.com/downloads/details.aspx?FamilyID=a71060eb-454e-4475-81a6-e9552b1034fc&displaylang=en

I’ve also updated my blog posts about using the Friendly Feeds features here :

Introducing Web Friendly Feeds aka Friendly Feeds (Updated for CTP2)

ADO.NET Data Services Friendly Feeds , Mapping EDM Types – I

ADO.NET Data Services Friendly Feeds , Mapping CLR Types 

Look forward to more exciting blog posts on the team blog about some of the new features in our CTP2 release .

Hello all , with the recent release of ADO.NET Data v1.5 Services CTP 1 , we introduced a new feature called as “Web Friendly Feeds”.
With the release of CTP2 , we have introduced support for 2 additional ATOM:Entry elements you can map to:

  1. entry:Summary
  2. entry:Updated

What is this feature about ?

This is what the markup for one of the the resources of Customers looks like in ADO.NET Data Services v1 .

<?xml version="1.0" encoding="utf-8" standalone="yes" ?> 
<entry 
xml:base=http://localhost:26503/northwind.svc/ 

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"> <id>http://localhost:26503/northwind.svc/Customers('ALFKI')</id> <title type="text" /> <updated>2009-03-18T20:30:20Z</updated> <author> <name /> </author> <category term="NorthwindModel.Customers" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> <content type="application/xml"> <m:properties> <d:CustomerID>ALFKI</d:CustomerID> <d:CompanyName>Alfreds Futterkiste</d:CompanyName> <d:ContactName>Maria Anders</d:ContactName> <d:ContactTitle>Sales Representative</d:ContactTitle> <d:Address>Obere Str. 57</d:Address> <d:City>Berlin</d:City> <d:Region m:null="true" /> <d:PostalCode>12209</d:PostalCode> <d:Country>Germany</d:Country> <d:Phone>030-0074321</d:Phone> <d:Fax>030-0076545</d:Fax> </m:properties> </content> </entry>

In the markup above , a couple of things are missing

1) The <title> element is empty

<title type="text" />

2) The author/name element is empty

<author>
    <name /> 
</author>
In v 1.5 , through Friendly Feeds , we will now be able to assign a property of the “Customers” entity type to turn up in these element locations in the atom:entry payload.

Now , let’s say that we wanted to map the “ContactName” as the author name element of the entry element and Title to be “ContactTitle” as the title of the entry element.
Then , the payload would look like this :

<entry >
  <id>http://localhost:26503/northwind.svc/Customers('ALFKI')</id> 
  <title type="text">Sales Representative</title> 
  <updated>2009-03-18T20:46:42Z</updated> 
 <author>
  <name>Maria Anders</name> 
  </author>
<category term="NorthwindModel.Customers" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
 <content type="application/xml">
 <m:properties>
  <d:CustomerID>ALFKI</d:CustomerID> 
  <d:CompanyName>Alfreds Futterkiste</d:CompanyName> 
  <d:ContactName>Maria Anders</d:ContactName> 
  <d:ContactTitle>Sales Representative</d:ContactTitle> 
  <d:Address>Obere Str. 57</d:Address> 
  <d:City>Berlin</d:City> 
  <d:Region m:null="true" /> 
  <d:PostalCode>12209</d:PostalCode> 
  <d:Country>Germany</d:Country> 
  <d:Phone>030-0074321</d:Phone> 
  <d:Fax>030-0076545</d:Fax> 
  </m:properties>
  </content>
</entry>

This also means , that IE now displays the Title & author Name elements when you browse to the “Customers” entity set .

AStoria_Feed_Reading_View

Which elements in the atom:entry element can I map to an entity type properties ?

  1. entry:author/email
  2. entry:author/name
  3. entry:author/uri
  4. entry:published
  5. entry:rights
  6. entry:summary
  7. entry:title
  8. entry:updated
  9. entry:summary

Once a property is mapped , if keeping the value of the property  in the entry:contents section doesn’t make sense,can I remove it ?
Yes , absolutely , in the above case , we can remove the ContactName & ContactTitle elements from being repeated in the <contents> section.
Ex:

<entry>
  <id>http://localhost:26503/northwind.svc/Customers('ALFKI')</id> 
  <title type="text">Sales Representative</title> 
  <updated>2009-03-18T21:04:20Z</updated> 
  <author>
  <name>Maria Anders</name> 
  </author>
  <category term="NorthwindModel.Customers" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
 <content type="application/xml">
 <m:properties>
  <d:CustomerID>ALFKI</d:CustomerID> 
  <d:CompanyName>Alfreds Futterkiste</d:CompanyName> 
  <d:Address>Obere Str. 57</d:Address> 
  <d:City>Berlin</d:City> 
  <d:Region m:null="true" /> 
  <d:PostalCode>12209</d:PostalCode> 
  <d:Country>Germany</d:Country> 
  <d:Phone>030-0074321</d:Phone> 
  <d:Fax>030-0076545</d:Fax> 
  </m:properties>
  </content>
  </entry>

Great , what else can I do with this new feature ?
Well, did I mention you can embed your own markup in the <entry> element for an entity type !!!

consider the following entity type , BlogPost , which looks like this

public class BlogPost {
        public double Lat { get; set; }
        public double Long { get; set; }
        public int BlogPostID { get; set; }
        public string Title { get; set; }
        public string Body { get; set; }
        public string Author { get; set; }
        public string PostURI { get; set; }
        public string ContentSummary{get;set;}
}

This type represents the entry for a blog post , and also contains the Geographical location information about where the post was made ( Lat /Long)
and also the author information. Now , if this data was exposed via a Data Service, the payload would contain the Lat/Long/Published fields as part of 
the entry:content element and wouldn’t have any special meaning.
The author element should be the Author field of the atom:entry , and the Published field to be the atom:published.
the Lat & Long fields should be a georss element that shows the location at which the Blog Post was made.
In short , it should look like this :

<entry>
  <id>http://localhost/AstoriaBoard/Services/BlogSvc.svc/Posts(1)</id> 
  <title type="text">Entities, How many ways do I count thee ?</title> 
  <summary type="html">
<
img class='imgClass' width='150px' height='150px' src='/AStoriaBoard/mug.jpg'/><br/>Its a common ask that we introduce aggregatin
</summary> <published>2009-03-18T14:29:43-07:00</published> <updated>2009-03-18T21:29:43Z</updated> <author> <name>Phani Raj</name> </author> <link rel="edit" title="BlogPost" href="Posts(1)" /> <category term="Blogs.BlogPost" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> <content type="application/xml"> <m:properties> <d:BlogPostID m:type="Edm.Int32">1</d:BlogPostID> <d:Body>Its a common ask that we introduce aggregating mechanisms in Data services
so that one can do a Count of the number of entities present in an EntitySet easily.
In this blog post , I will outline one method of implementing a “Count” method that works for you.
The interface to the count method will be</d:Body> <d:Author>Phani Raj</d:Author> <d:PostURI m:null="true" /> </m:properties> </content> <geo xmlns="http://www.georss.org/georss"> <long>-80.244445</long> <lat>25.730752</lat> </geo> </entry>

Now that we got this markup , I feel like we should do something with it . How about showing this information on a MAP ?
I know !! We have a mapping solution , Virtual Earth , lets try and see if we can feed this feed to Virtual Earth and make it see our GeoRss markup.
Recently , ( November 2008 ), the Live team released the Map control as an asp.net control . Download it here :http://dev.live.com/tools/

Add this control to an aspx page in the same website as the Data Service .

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style>
        .imgClass{
            border: solid 2px #99ccff;}
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <script language="javascript">
        function pageLoad() {
            HookUpWorkAround();
        }
    </script>
    <div id="mapContainer">
        <ve:Map ID="geoRssMap" runat="server" Height="600px" Width="75%" ZoomLevel="4" />
    </div>
    <asp:ScriptManager ID="scrpManager" runat="server">
        <Scripts>
            <asp:ScriptReference Path="~/Scripts/VEWorkAround.js" />
        </Scripts>
    </asp:ScriptManager>
    </form>
</body>
</html>

In the code-behind file ,

using System;
using Microsoft.Live.ServerControls.VE;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //Clear out any mapped locations 
        geoRssMap.Clear();
        //Create a new shapelayer to import
        ShapeLayer geoRssLayer = new ShapeLayer();
        //Point the shape layer at the data source returning the mapping information
        ShapeSourceSpecification georssSpec = new ShapeSourceSpecification(
                    DataType.GeoRSS, "Services/BlogSvc.svc/Posts", geoRssLayer
                    );
        //Bind the feed to the map
        geoRssMap.ImportShapeLayerData(georssSpec, null, false);
    }
}

You might be wondering why we need the HookUpWorkAround() function and what it does , I’ll explain that in a later blog post .
After this , set the web page as the startup page and browse to the page in FireFox , I’ll explain why Firefox in a later blog post .
And voila !! This is what the page looks like :
FF_Ve_Firefox

You can download the  sample project that demonstrates this feature by clicking on the link at the bottom of this post

All this demonstrates the what and not the how , we shall discuss the how in future blog posts.

In the meantime ,enjoy this sample app and try out your own mashups.

Phastoria

More details here : Announcing the PHP Toolkit for ADO.NET Data Services

Look forward to future posts on this blog about working with the PHP library and Astoria Services.

Download sample project here :

In part 2 of this series , we will look at using the Astoria client library to create a drill down chart using the chart types available in the Silverlight toolkit.
You can take a look at the complete samples for the Silverlight toolkit here.

This sample builds a UI that looks like this :

ChartDrillDownAstoria_2

The Pie chart represents the distribution of Employees across departments.
Clicking on a specific piece of the pie  brings up the list of the employees in that department.

Binding the Pie chart
The Chart control has a Pie series that has the DependentValuePath set to the Count of employees in the department
and the IndependentValuePath set to the name of the department.

Setting the IndependentValuePath is straightforward ,set the IndependentValuePath to the “DepartMentName” property of the Department entity type. The DependentValuePath is a little tricky , as the Department entity doesnt contain aggregation information regarding the employees in the Department . But , it does have the employees as an ObservableCollection of Employee types . So , we can get the count by assigning the DependentValuePath to be the expression “Employees.Count” which gets the Count property of the IList. Unfortunately ,  this means that the Employees will also have to be downloaded when you bind the Departments. In another post , I will discuss how to lazy load the employees list and still get this aggregation.

XAML for Pie Series in Chart

  <chartingToolkit:Chart x:Name="chEmployeesByDepartment" 
Title="# Employees/Department" IsEnabled="true" Height="300"> <chartingToolkit:Chart.Series> <chartingToolkit:PieSeries
x:Name="lnSeries" IndependentValuePath ="DepartMentName" DependentValuePath ="Employees.Count" SelectionChanged="DepartmentSelected" IsSelectionEnabled ="True" > </chartingToolkit:PieSeries> </chartingToolkit:Chart.Series> </chartingToolkit:Chart>


The function to bind the Pie series with the Department information

 private void LoadDepartmentsAndEmployees() {
    DataServiceQuery<Department> deptQueryWithEmployees = context.Departments.Expand("Employees") 
as DataServiceQuery<Department>; deptQueryWithEmployees.QueryAndCall( (deparmentStatistics) => { Dispatcher.BeginInvoke( () => { PieSeries series = chEmployeesByDepartment.Series[0] as PieSeries; series.ItemsSource = deparmentStatistics; } ); }); }

Populating employee information when a department is selected in the Pie Series
We need to setup the Pie Series in the chart control to allow selection of chart points  and hook into the
SelectionChanged event of the Pie Series. We do this by:

  1. Setting IsSelectionEnabled to true on the Pie Series
  2. Hooking up to the SelectionChanged event of the Pie Series
        private void DepartmentSelected(object sender, SelectionChangedEventArgs e) {  
            //Get the series that caused this  event to be raised
            PieSeries series = sender as PieSeries;
            //Get the current selected department in the Series
            Department selectedDepartment = series.SelectedItem as Department;
            if (selectedDepartment != null) { 
                //Set the title of the data grid
                lblSelectedDepartment.Text = String.Format(strSelectedDepartmentMessage, selectedDepartment.DepartMentName);
                //Bind the employee grid with the employees for this department
                dgEmployees.ItemsSource = selectedDepartment.Employees;
            }  
        }      

Download sample project here :

Download the sample Silverlight project here :

About the Silverlight toolkit  ,

From their Codeplex page : http://silverlight.codeplex.com/

“The Silverlight Toolkit is a collection of Silverlight controls, components and utilities made available outside the normal Silverlight release cycle”

In the first of a series I am planning , we will talk about how to achieve a Master-Child display using the Accordion control 
from the Silverlight Toolkit control.

The data model we will be binding looks like this :

SLToolkitAccordion_DataModel

Type Employee has a property called Department of type Department.
Type Department has a collection of type Employee called Employees.

Employee and Department are related 1..1
Department and Employee are related 1..M

We want to bind the Department names to the header of the Accordion and
the employees as a list inside the content of the accordion.
When we are done , the final output should look like this :

SLTOolkit_Accordionoutput

Configuring the header to show the DepartmentName

The Header template of the Accordion has a textblock which binds to the DepartMentName property of the
Department entity.

 <layoutToolkit:Accordion.HeaderTemplate >
       <DataTemplate>
            <TextBlock Text="{Binding Path=DepartMentName}"></TextBlock>
       </DataTemplate>
 </layoutToolkit:Accordion.HeaderTemplate>

Configuring the content to show the names of the employees working in the department.

The content of the Accordion pane would be a list box which is bound to the Employees collection of the Department
entity type and shows the EmployeeName as the DisplayMember.

<layoutToolkit:Accordion.ContentTemplate>
      <DataTemplate>
          <ListBox ItemsSource="{Binding Employees}" DisplayMemberPath="EmployeeName">
          </ListBox>
      </DataTemplate>
</layoutToolkit:Accordion.ContentTemplate>

To write the Silverlight client code for this project ,we will need to generate the Client classes with Databinding enabled.
As shown in this article on our team blog .

Once this is done , we have two ways of binding the accordion ,
Eager Loading : Download the employees for a department when you download the departments
Lazy Load : Download the employees for a department when the header of an accordion pane , i.e Department is clicked.

Eager Loading :

DataServiceQuery<Department> deptQueryWithEmployees = context.Departments.Expand("Employees") as DataServiceQuery<Department>;
deptQueryWithEmployees.QueryAndBind(acDepartments);

Since the query part itself isnt interesting in the context of this blog post , I’ve abstracted away the querying into an extension method ( QueryAndBind ) and will be available as part of the download.

Here , as you can see , we are eager loading the Employees for the departments .
I feel that this is wasteful if you have a large number of departments as this not only increases the amount of data on the wire , but it also means that all the data that comes down the wire will be useful .

For example, if you have about 15 departments and a user may click on 5 or less departments , then downloading employees for all the 15 departments seems inefficient.

Xaml for Eager Loading

<layoutToolkit:Accordion x:Name="acDepartments" Width="400">
    <layoutToolkit:Accordion.HeaderTemplate >
        <DataTemplate>
            <TextBlock Text="{Binding Path=DepartMentName}"></TextBlock>
        </DataTemplate>
    </layoutToolkit:Accordion.HeaderTemplate>
    <layoutToolkit:Accordion.ContentTemplate>
        <DataTemplate>
            <ListBox ItemsSource="{Binding Employees}" DisplayMemberPath="EmployeeName">
            </ListBox>
        </DataTemplate>
    </layoutToolkit:Accordion.ContentTemplate>
</layoutToolkit:Accordion>

Lazy Loading :
In this case , we will only bind the Headers and  will bind the Employees only if the header is clicked for that department. In the Silverlight Accordion control , the event SelectionChanged is fired when the header of an Accordion Pane is clicked.
By listening to this event , we can find out which department was clicked and load the Employees for that department using BeginLoadProperty .

public DelayLoad() {
           InitializeComponent();
           context = new TreeViewDataProvider(new Uri("TreeViewDataService.svc", UriKind.RelativeOrAbsolute));
           LoadDepartments();
}
private void LoadDepartments(){
    ((DataServiceQuery<Department>)context.Departments).QueryAndBind(acDepartments);
}
We will subscribe to the SelectionChanged event of the Accordion and add “LoadEmployeesForDepartment” as the event handler.
private void LoadEmployeesForDepartment(object sender, SelectionChangedEventArgs e)
        {
            //The sender is the control that raised the event
            Accordion acControl = sender as Accordion;
            //Get the Selected Department
            Department selectedDepartment = acControl.SelectedItem as Department;
            if (
                //If the Selected object is department
                selectedDepartment != null 
                && (
                // If the Employees collection is null or empty
                selectedDepartment.Employees == null || selectedDepartment.Employees.Count == 0)
                )
            {
                //Call load property , which updates the Employees collection of this instance 
                //and the UI automatically updates itself, since Department type implements INotifyPropertyChanged
                context.LoadPropertyAndCall<Employee>(selectedDepartment, "Employees",
                    null);
            }

        }

XAML for Delay Load :

<layoutToolkit:Accordion x:Name="acDepartments" SelectionChanged="LoadEmployeesForDepartment">
    <layoutToolkit:Accordion.HeaderTemplate >
        <DataTemplate>
            <TextBlock Text="{Binding Path=DepartMentName}"></TextBlock>
        </DataTemplate>
    </layoutToolkit:Accordion.HeaderTemplate>
    <layoutToolkit:Accordion.ContentTemplate>
        <DataTemplate>
            <ListBox ItemsSource="{Binding Employees}" DisplayMemberPath="EmployeeName">
            </ListBox>
        </DataTemplate>
    </layoutToolkit:Accordion.ContentTemplate>
</layoutToolkit:Accordion>

Download the sample Silverlight project here :

Running the sample app

  1. Set SLToolkitWithAstoriaWeb as the Start-up project.
  2. Set SLToolkitWithAstoriaTestPage.html as the start-up page.
  3. To run the EagerLoading sample , just hit F5
  4. To run the DelayLoad sample , follow a-c and add the Query string ?delayLoad to the address bar in the browser that comes up.

As an extension to the last blog post dealing with Set based filter operations in our client library ,
we will introduce support for the specifying method calls in the filter expression.

What does this achieve ?
Currently , the IsIn operator only supports an equality comparision.
With support for Method Calls , you can now select entities in a set which when passed to a method , evaluate true. ex: You can generate Uris such as this :
  1. /northwind.svc/Customers?$filter = substringof('London',City) or substringof('Berlin',City) or substringof('Prague',City)
  2. /northwind.svc/Customers?$filter = startswith('London',City) or startswith('Berlin',City) or startswith('Prague',City)
  3. /northwind.svc/Customers?$filter = endswith('London',City) or endswith('Berlin',City) or endswith('Prague',City)

Fortunately , not a lot of code change is required to get this support.

We will change the first parameter of the extension method from

Expression<Func<TEntity, object>> propertyExpression

to

Expression<Func<TEntity, TValue, bool>> comparisionInvokeExpression

which means that where we were initially sending an expression that selects a property of the entity , we now send the Extension method a delegate that accepts the entity and the value being compared against it and returns a boolean value after comparison using a method.

example :

Expression<Func<T, object>> propertyExpression means
customer => customer.City
Expression<Func<TEntity, TValue, bool>> comparisionInvokeExpression means
(cust, cityName) => cust.City.ToLower().StartsWith(cityName)

The second change is in the location where we build the comparision expression for values in the set.
we change the line which does the comparision using Expression.Equal with a method call to the comparision expression passed in .
We will change  :

//Build a comparision expression which equats the Id of the ENtity with this value in the IDs list
// ex : e.Id == 1
Expression comparison = Expression.Equal(left, Expression.Constant(id));
to :
//The Left Hand Side of the Filter Expression
MethodCallExpression comaprisionMethod = comparisionInvokeExpression.Body as MethodCallExpression;
//Build a comparision expression which calls the method that does the comparision for us
//ex : c=> c.City.Contains(id)
Expression comparison = Expression.Call(
                        comaprisionMethod.Object,
                        comaprisionMethod.Method,
                        Expression.Constant(id) );

The complete code sample is here :

I'll be joining Shayne Burgess and Mike Flasko at Tech Ed in LA .

If you have question/feedback about project Astoria , please drop by the Data Development Technical Learning Center booth at Tech Ed.

Here's the times at which I'll be available at the TLC booth.

 

Tuesday, May 12, 2009

Area 

Station 

9:30 AM - 12:30 PM 

Developer Tools, Languages and Frameworks

TLC/BLUE/DTL: Microsoft Data Development 

Wednesday, May 13, 2009

Area 

Station 

12:15 PM - 3:15 PM 

Developer Tools, Languages and Frameworks 

TLC/BLUE/DTL: Microsoft Data Development 

Thursday, May 14, 2009

Area 

Station 

8:00 AM - 11:00 AM

Developer Tools, Languages and Frameworks 

TLC/BLUE/DTL: Microsoft Data Development 

 

Telerik has a range of controls that work with ADO.NET Data Services as the data source . Take a look at them here :

ADO.NET Data Services with Telerik Controls

Kevin Babcock has a great post over at Telerik where he talks about using ADO.NET Data Services with Telerik Reporting suite .

I wanted to address one small point in the blog post which I felt can be improved upon.

“You might be curious why I chose to iterate through the list of categories in the report parameter value, calling the web service for each one and appending the results to a collection.
The reason is that, due to the limitations of ADO.NET Data Services, you can’t use methods like Contains to filter data in your LINQ queries.“

Yes , this is absolutely correct.
We don't support the “Contains” operator to select a primitive property of the Entity Type from a given range of values.
The client linq implementation doesn't support Contains on Navigation properties is because we don't have a URI Query operator  that corresponds to the "Contains" function to select a value from a set. But you can semantically achieve the same effect by “OR”ing a couple of “EQUALS” expressions.

ex:

If A={0,1,2,3}  , then A.Contains(B) is equivalent to ( B == A[0] OR B ==A[1] OR B == A[2])

I wrote about achieving this effect here :  Set Based Operations in Ado.net Data Services

Now, in this sample , we are filtering an Entity Set (Products) based on the value of a primitive property ( CategoryID ) of a Navigation Property (Categories).
Now , since this is the Northwind model Schema, Products are related to categories in a 1..M association and Categories to Products in a 1..M association.

What this means is that the above query can be expressed as : 

Now , this is still not as optimal as it can be , but we reduced the number of round trips as we download only relevant categories and their associated Products.
To make this even easier , we use the IsIn<T> extension method I wrote from Set Based Operations in Ado.net Data Services.

So , there you have it , we reduced the number of network calls and also the lines of code to achieve this filtering.

On a side note , Kevin has left Telerik and now blogs at : http://www.myviewstate.net/blog/

All the best for your future endeavours Kevin !!

More Posts Next page »
 
Page view tracker