Welcome to MSDN Blogs Sign in | Join | Help

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 !!

As I mentioned in my last blog post , here are some samples of how to map your entity properties to Atom/custom markup in the atom:entry element.
You can apply Friendly Feed mappings on the EDM entity types by adding attributes to the CSDL of the Entity Data Model .
We will focus on the kinds of mappings and how to achieve them .

Pre-requisites

1. To edit the CSDL , you will need to open the EDM model in Xml view .To do this , right-click the EDM model (.EDMX file ) in Visual Studio
      and select “Open with”->”Xml Editor” .
2. Add a reference to this namespace in the <edmx:ConceptualModels> node  of the CSDL section in the EDMX file :
    ex: xmlns:m2="http://schemas.microsoft.com/ado/2008/11/dataservices/metadata"

1) Mapping to ATOM elements in the atom:entry payload : 
The EntityPropertyMapping (EPM) attribute has two constructors , one which binds the property to an Atom element in the feed ,
and another which binds the property to a custom element . We shall discuss the former in this section.

For ATOM Mappings , the EPM markup has the following attributes .

  1. m2:EpmSourcePath: The m2:EpmSourcePath is used when
                                        a) The Property you are mapping exists in a base type and not on the current type .
                                        b) The property you are mapping exists in a complex type and not on the current type .
  2. m2:EpmTargetPath : The atom:entry element to which this property has to be mapped to
  3. m2:EpmContentKind: The content-type of the mapped  atom:entry element
  4. m2:EpmKeepContent : set this to false if you want the entity’s property value to turn up only in the mapped atom:entry element and not in the <contents> section.

Lets proceed  , using the same BlogPost  type that we discussed last time .
This is the EDM Markup for the type :

<EntityType Name="BlogPost">
  <Key>
    <PropertyRef Name="BlogPostID" />
  </Key>
  <Property Name="Lat" Type="Edm.Double" Nullable="false"/>
  <Property Name="Long" Type="Edm.Double" Nullable="false"/>
  <Property Name="Published" Type="Edm.DateTime" Nullable="false" />
  <Property Name="BlogPostID" Type="Edm.Int32" Nullable="false" />
  <Property Name="Title" Type="Edm.String" Nullable="true"/>
  <Property Name="Body" Type="Edm.String" Nullable="true" />
  <Property Name="Author" Type="Edm.String" Nullable="true"/>
  <Property Name="PostURI" Type="Edm.String" Nullable="true" />
  <Property Name="ContentSummary" Type="Edm.String" Nullable="true" />
  <Property Name="IconUri" Type="Edm.String" Nullable="true"/>
</EntityType> 

1. Map the “Title” property  of the BlogPost Entity type to the entry:title element

When decorating EDM  types , the markup specifying the mapping goes on the property you are mapping ,
ex:

<Property Name="Title" Type="Edm.String" Nullable="true"
  m2:EpmAtom="true"
  m2:EpmTargetPath="EpmSyndicationTitle"
  m2:EpmContentKind="EpmPlaintext"
  m2:EpmKeepContent="true" />

2. Map the “Author” property to entry:author element 

This is what the markup would look like :

<Property Name="Author" Type="Edm.String" Nullable="true"
           m2:EpmAtom="true"
           m2:EpmTargetPath="EpmSyndicationAuthorName"
           m2:EpmContentKind="EpmPlaintext"
           m2:EpmKeepContent="true" />

As described in  my previous blog post , you can map an Entity’s properties to the following atom:entry elements in the payload :

atom:entry Element m2:EpmTargetPath
entry:author/email EpmSyndicationAuthorEmail
entry:author/name EpmSyndicationAuthorName
entry:author/uri EpmSyndicationAuthorUri
entry:published EpmSyndicationPublished
entry:rights EpmSyndicationRights
entry:summary EpmSyndicationRights
entry:title EpmSyndicationTitle

Content-Kind m2:EpmContentKind
Plaintext EpmPlaintext
Html EpmHtml
Xhtml EpmXHtml
Default if not specified. EpmPlainText

2) Mapping to non-ATOM/custom  elements in the atom:entry payload : 

For non-ATOM/custom Mappings , the EPM markup requires the following attributes.

  1. m2:EpmSourcePath   : The property of the Entity Type whose value should be mapped
  2. m2:EpmTargetPath    : The xml path markup which describes the path to the custom markup this property should be mapped to .
  3. m2:EpmNsPrefix        : The xml prefix for the custom element/attribute that this property is mapped to.
  4. m2:EpmNsUri             : The xml namespace to which the custom element/attribute that this property is mapped should be under.
  5. m2:EpmKeepContent : set this to false if you want the entity’s property value to turn up only in the mapped atom:entry element and not in the <contents> section.

The Xml Path syntax for custom mappings.

this syntax is very logical and looks like the following .
Lets say that you wanted to map a property to a custom element in markup that looks like this :

<mycustomRoot xmlns=”http://www.mycustomFormat.org>
  <customElement>property value goes here</customElement>
</mycustomRoot>
for this example ,
m2:EpmTargetPath  would be “mycustomRoot/customElement”
m2:EpmNsPrefix        would be an empty string as this markup has no custom prefix.
m2:EpmNsUri  would be “http://www.mycustomFormat.org
m2:EpmKeepContent is subjective to whether you want to keep the property value in the <content> section or not.

and now , lets say that you wanted to map a property to a custom attribute of an element in markup that looks like this :

<me:mycustomRoot xmlns:me="http://www.georss.org.georss">
  <me:customElement customAttribute="property value goes here"></me:customElement>
</me:mycustomRoot>

for this example ,
m2:EpmTargetPath  would be “mycustomRoot/customElement/@customAttribute
m2:EpmNsPrefix        would be “me”.
m2:EpmNsUri  would be “http://www.mycustomFormat.org”
m2:EpmKeepContent is subjective to whether you want to keep the property value in the <content> section or not.

A note , the complexity of your custom markup has a direct effect on the performance costs  for Serialization/De-Serialization of the entity type .
with this example , lets map the lat & long properties to geoRss markup ,which looks like this :

<geo:lat xmlns:geo="http://www.georss.org/georss">47.684</geo:lat>
<geo:long xmlns:geo="http://www.georss.org/georss">-122.122</geo:long>

Final type definition looks like this :

<EntityType Name="BlogPost">
  <Key>
    <PropertyRef Name="BlogPostID" />
  </Key>
  <!-- map the Lat property to the <geo:lat> element  -->
  <Property Name="Lat" Type="Edm.Double" Nullable="false"
            m2:EpmAtom="false"
            m2:EpmTargetPath="lat"
            m2:EpmNsUri="http://www.georss.org/georss"
            m2:EpmNsPrefix="geo"
            m2:EpmKeepContent="true" />
  <!-- map the Long property to the <geo:long> element  -->
  <Property Name="Long" Type="Edm.Double" Nullable="false"
            m2:EpmAtom="false"
            m2:EpmTargetPath="long"
            m2:EpmNsUri="http://www.georss.org/georss"
            m2:EpmNsPrefix="geo"
            m2:EpmKeepContent="true" />
  <!-- Map the “Title” property  of the BlogPost Entity type to the entry:title element -->
  <Property Name="Title" Type="Edm.String" Nullable="true"
  m2:EpmAtom="true"
  m2:EpmTargetPath="EpmSyndicationTitle"
  m2:EpmContentKind="EpmPlaintext"
  m2:EpmKeepContent="true" />
  <Property Name="Body" Type="Edm.String" Nullable="true" />
  <!-- Map the “Author” property to entry:author element  -->
  <Property Name="Author" Type="Edm.String" Nullable="true"
            m2:EpmAtom="true"
            m2:EpmTargetPath="EpmSyndicationAuthorName"
            m2:EpmContentKind="EpmPlaintext"
            m2:EpmKeepContent="true" />
  <Property Name="BlogPostID" Type="Edm.Int32" Nullable="false" />
  <Property Name="Published" Type="Edm.DateTime" Nullable="false" />
  <Property Name="PostURI" Type="Edm.String" Nullable="true" />
  <Property Name="ContentSummary" Type="Edm.String" Nullable="true" />
  <Property Name="IconUri" Type="Edm.String" Nullable="true"/>
</EntityType>

Special cases

I . Complex type properties

[I’ll leave the type definitions as CLR types so that its easier to visualize the relations.]

Consider the following model ,

public class Address
    {
        public long DoorNumber { get; set; }
        public string Street { get; set; }
        public int ZipCode { get; set; }
    }
    [DataServiceKey("CustomerID")]
    public class Customer
    {
        public int CustomerID { get; set; }
        public Address myAddress { get; set; }
    }


and lets say that you wanted to map the property Street of the complex type Address when accessed through the
entity type “Customer”  to the atom:title element ,

this can be achieved via setting the EpmSourcePath property to “Street”  .
In this case , the Epm markup would look like this :

<EntityType Name="Customer">
  <!-- Map the Street property of the Address complex type to the entry:title element -->
  <Property Name="myAddress" Type="MyModelNamespace.Address"
            me:EpmSourcePath="Street"
            m2:EpmAtom="true"
            m2:EpmTargetPath="EpmSyndicationTitle"
            m2:EpmContentKind="EpmPlaintext"
            m2:EpmKeepContent="true"/>
  <!-- other properties removed for brevity-->
</EntityType>

II Mapping properties declared  on base type

Consider this data model :

[DataServiceKey("CustomerID")]
public class Customer
{
        public int CustomerID { get; set; }
        public Address myAddress { get; set; }
        public string BaseTypeField { get; set; }
}

public class DerivedCustomer : Customer
{
  public string DerivedTypeField { get; set; }
}
and you want to map a property declared on the Base type “Customer” on the derived type “DerivedCustomer”
The EPM Markup would look like this :
<!-- Map the "BaseTypeField" property of the base type "Customer" to the entry:title element -->
<EntityType Name="DerivedCustomer" BaseType="MyModelNamespace.Customer"
            m2:EpmAtom="true"
            me:EpmSourcePath="BaseTypeField"
            m2:EpmTargetPath="EpmSyndicationAuthorName"
            m2:EpmContentKind="EpmPlaintext"
            m2:EpmKeepContent="true">
  <!-- other properties removed for brevity-->
</EntityType>

Considerations for location  of EPM markup in EDM Schema

Use the following guidelines to decide where in the EDM Schema you should add the attribute for either ATOM or custom Mappings,

Where is property defined ? Where do I apply the EPM attribute? SourcePath
Simple property on the Entity Type
ex:
“Title” property of “BlogPost” type above
<Property> node in the <Entitytype> markup Not required
Simple property on entity’s base type <EntityType> node Base type property name
Complex Property on the Entity Type Complex Types cannot be mapped directly N/A
Simple property defined on complex type which is a property on an Entity Type <Property> node in the <EntityType> Complex type’s simple property name

Hope you enjoyed this post about applying Friendly Feeds mappings to EDMdata models.
The second part of this post will discuss more special cases in EDM Models and troubleshooting failing mappings
and also a sample project for EDM Friendly Feeds Mappings.

As part  of the v1.5 install, we also shipped a Silverlight 2.0 SDK library that is capable of talking to a v1.5 Astoria Service.

Did you know that you could use the Silverlight 2.0 client library we shipped as part of our v1.5 CTP1 release in Silverlight 3.0 applications?

From a Silverlight SDK library point of view ,to use Mike Flasko’s words, ”we are nothing but user code”.
We have no dependencies on the Runtime that have changed in SL 3.0 , yet.
So , you can use the Silverlight 2.0 SDK library that we shipped in v1.5 CTP1 , by
replacing the reference to “System.Data.Services.Client.dll” with “Microsoft.Data.Services.Client.dll”

In your Silverlight project ,

1. If you already have a reference to “System.Data.Services.Client.dll” in your SIlverlight application , remove it .

2. If you have the v1.5 CTP1 installed , the Silverlight client binaries are stored in the following location ,
%ProgramFiles%\ADO.NET Data Services V1.5 CTP1\sl_bin

3. Bring up the “Add Reference” window by right clicking the “References” node for the Silverlight 3.0 Project in Visual Studio.

4. Use the “Browse” tab of the “Add Reference” window to browse to this location to add a reference to “Microsoft.Data.Services.Client.dll”.

5. Rebuild and run the app .

What about Code-gen ,
Can I point the Silverlight 3.0 application at a v1.5 CTP1 service and get all the binding & Friendly Feeds mappings generated in the Client types?

No , there is no integration for v1.5 codegeneration tools in Visual Studio for Sl 3.0 Projects .
You will have to use the DataSvcUtil.exe tool from the following directory manually to generate the types with binding information for SL 3.0 projects .

Location for DataSvcUtil.exe : %ProgramFiles%\ADO.NET Data Services V1.5 CTP1\bin

From a runtime perspective , is there any functionality in the v1.5 SL 2.0 library that is not present when the dll is inside a xap built with SL 3.0 tools ?

No , none , everything should just work . If something doesn’t work , please leave a comment on this post or write to me at PhaniRaj At Microsoft Dot Com.

What about Silverlight 3 Out-Of-Browser applications ?

The Astoria Silverlight client library doesn’t yet work with Out of the Browser Silverlight applications.

Imagine this , you just downloaded the Astoria V1.5 CTP1 and are happily chugging along and decide to make a Silverlight Project
that uses the latest Silverlight client library to make some cool app.
You open an existing Silverlight app  /create a new Silverlight app ,
and generate the client types by running “Add Service Reference” from Visual Studio.
and write some code in the app and hit F5 to run the app .
Now , Instead of seeing the poetic beauty that is a Silverlight app built with Astoria , you see this :

M_D_S_C_Unhandled_Exception

The Exception message is :

System.IO.FileNotFoundException occurred
  Message="Could not load file or assembly 'Microsoft.Data.Services.Client, Version=2.0.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies.
           The system cannot find the file specified."
  StackTrace:
       at SilverlightProject1.Page..ctor()
       at SilverlightProject1.App.Application_Startup(Object sender, StartupEventArgs e)
  InnerException:

 What just happened ?

When the tools which generate the client code for an Astoria Service for Silverlight applications ran , they added a reference to the new client dll,
Microsoft.Data.Services.Client.dll with “Copy Local” set to false.

M_D_S_C_Silverlight_Reference

If your code looks like this,
public Page(){
InitializeComponent();
nwServiceReference.BlogServiceProvider prov =
                new SilverlightProject1.nwServiceReference.BlogServiceProvider(new Uri("http://ServiceEndPoint"));
}

When the JIT compiler compiles your Page() constructor method, it scans the method, sees that it references a type named BlogServiceProvider , and attempts to load Microsoft.Data.Services.Client.dll so that the reference can be resolved.
Now , Since we set Copy Local to false , the Client DLL is not copied into the XAP file ,and the Silverlight CLR cannot find the file , it throws the above exception.
We can verify by opening the xap file in winrar or some other archiving utility.
Xap_No_CLient_Library

Resolution :

In your Silverlight project, for the reference to “'Microsoft.Data.Services.Client.dll” ,  Set “Copy Local” to “True” and rebuild your Silverlight XAP.

What about “Update Service Reference”?
Same issue , follow same resolution.

When will this be fixed?
We are tracking this issue and will release a fix in a future release of ADO.NET Data Services v1.5

As I mentioned in my last blog post , here are some samples of how to map your entity properties to Atom/custom markup in the atom:entry element.

You can apply Friendly Feed mappings on the CLR entity types by decorating the Entity classes with the EntityPropertyMappingAttribute type.
We will focus on the kinds of mappings and how to achieve them .

1) Mapping to ATOM elements in the atom:entry payload : 

The EntityPropertyMapping (EPM) attribute has two constructors , one which binds the property to an Atom element in the feed ,
and another which binds the property to a custom element . We shall discuss the former in this section.

For ATOM Mappings , the EPM Attribute constructor takes the following parameters.

  1. propertyName : The property of the Entity Type whose value should be mapped
  2. targetSyndicationItem : The atom:entry element to which this property has to be mapped to
  3. targetTextContentKind : The content-type of the mapped  atom:entry element
  4. keepInContent : set this to false if you want the entity’s property value to turn up only in the mapped atom:entry element and not in the <contents> section.

Lets proceed  , using the same BlogPost  type that we discussed last time .

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; }
}

1. Map the “Title” property  of the BlogPost Entity type to the entry:title element
2. Map the “Author” property to entry:author element 

This is what the code would look like :

[EntityPropertyMapping(
       "Title",/*Source property path , the property of the Entity type to be mapped*/
       SyndicationItemProperty.Title,/* Syndication item to which the Source Property is mapped*/
       SyndicationTextContentKind.Plaintext,/* Syndication content kind for the syndication item this property is bound to */
       true/* If  false the property value is only placed at the mapped location & removed from the <content> section of the atom:entry*/
       )]
[EntityPropertyMapping("Author", SyndicationItemProperty.AuthorName, SyndicationTextContentKind.Plaintext, true)]
public class BlogPost

As described in  my previous blog post , you can map an Entity’s properties to the following atom:entry elements in the payload :

atom:entry Element TargetSyndicationItem
entry:author/email SyndicationItemProperty.AuthorEmail
entry:author/name SyndicationItemProperty.AuthorName
entry:author/uri SyndicationItemProperty.AuthorUri
entry:published SyndicationItemProperty.Published
entry:rights SyndicationItemProperty.Rights
entry:summary SyndicationItemProperty.Summary
entry:title SyndicationItemProperty.Title

 

2) Mapping to non-ATOM/custom  elements in the atom:entry payload : 

For non-ATOM/custom Mappings , the EPM Attribute constructor takes the following parameters.

  1. propertyName : The property of the Entity Type whose value should be mapped
  2. targetName  (Target Path)   : The xml path markup which describes the path to the custom markup this property should be mapped to .
  3. targetNamespacePrefix: The xml prefix for the custom element/attribute that this property is mapped to.
  4. targetNamespaceUri: The xml namespace to which the custom element/attribute that this property is mapped should be under.
  5. keepInContent : set this to false if you want the entity’s property value to turn up only in the mapped atom:entry element and not in the <contents> section.

The Xml Path syntax for custom mappings.

this syntax is very logical and looks like the following .
Lets say that you wanted to map a property to a custom element in markup that looks like this :

<mycustomRoot xmlns=”http://www.mycustomFormat.org>
  <customElement>property value goes here</customElement>
</mycustomRoot>
for this example ,
targetName  would be “mycustomRoot/customElement”
targetNamespacePrefix would be an empty string as this markup has no custom prefix.
targetNamespaceUri would be “http://www.mycustomFormat.org
keepInContent  is subjective to whether you want to keep the property value in the <content> section or not.

and now , lets say that you wanted to map a property to a custom attribute of an element in markup that looks like this :

<mycustomRoot xmlns:me="http://www.georss.org.georss">
  <me:customElement customAttribute="property value goes here"></me:customElement>
</mycustomRoot>

for this example ,
targetName  would be “mycustomRoot/customElement/@customAttribute
targetNamespacePrefix would be “me”.
targetNamespaceUri would be “http://www.mycustomFormat.org”
keepInContent  is subjective to whether you want to keep the property value in the <content> section or not.

A note , the complexity of your custom markup has a direct effect on the performance costs  for Serialization/De-Serialization of the entity type .

with this ,example , lets map the lat & long properties to geoRss markup ,which looks like this :

<geo:lat xmlns:geo="http://www.georss.org/georss">47.684</geo:lat>
<geo:long xmlns:geo="http://www.georss.org/georss">-122.122</geo:long>

Final type definition looks like this :

   [EntityPropertyMapping(
        "Title",/*Source property path , the property of the Entity type to be mapped*/
        SyndicationItemProperty.Title,/* Syndication item to which the Source Property is mapped*/
        SyndicationTextContentKind.Plaintext,/* Syndication content kind for the syndication item this property is bound to */
        true/* If  false the property value is only placed at the mapped location & removed from the <content> section of the atom:entry*/
        )]
    [EntityPropertyMapping("Author", SyndicationItemProperty.AuthorName, SyndicationTextContentKind.Plaintext, true)]
    [EntityPropertyMapping("Lat",/*Source property path , the property of the Entity type to be mapped*/
        "lat",/*The xml path markup which describes the path to the custom markup this property should be mapped to . */
        "geo",/*The xml prefix for the custom element/attribute that this property is mapped to. */
        "http://www.georss.org/georss", /*The xml namespace to which the custom element/attribute that this property is mapped should be under*/
        true /*set this to false if you want the entity’s property value to turn up only in the mapped atom:entry element and not in the <contents> section. */
        )]
    [EntityPropertyMapping("Long", "long", "geo", "http://www.georss.org/georss", true)]
    public class BlogPost
    {
        public double Lat { get; set; }
        public double Long { get; set; }
        public DateTime Published { 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;   }
        public string IconUri {get;set;}
    }

Special cases

I . Complex type properties


Consider the following model ,

public class Address
    {
        public long DoorNumber { get; set; }
        public string Street { get; set; }
        public int ZipCode { get; set; }
    }
    [DataServiceKey("CustomerID")]
    public class Customer
    {
        public int CustomerID { get; set; }
        public Address myAddress { get; set; }
    }


and lets say that you wanted to map the property Street of the complex type Address when accessed through the
entity type “Customer”  to the atom:title element ,

this can be achieved via setting the propertyName property to an appropriate path .
because propertyName not just takes the property name , it also accepts a path to the property’s location. 
 
in this case , the propertyName would be : “myAddress/Street”  , and the Epm attribute would look like this :

[DataServiceKey("CustomerID")]
[EntityPropertyMapping(
        "myAddress/Street",
        SyndicationItemProperty.Title,
        SyndicationTextContentKind.Plaintext,
        true
        )]
public class Customer
{
   public int CustomerID { get; set; }
   public Address myAddress { get; set; }
}

II Mapping properties declared  on base type

Consider this data model :

[DataServiceKey("CustomerID")]
public class Customer
{
        public int CustomerID { get; set; }
        public Address myAddress { get; set; }
        public string BaseTypeField { get; set; }
}

public class DerivedCustomer : Customer
{
  public string DerivedTypeField { get; set; }
}
and you want to map a property declared on the Base type “Customer” on the derived type “DerivedCustomer”
The type declaration would look like this :
[EntityPropertyMapping("BaseTypeField", SyndicationItemProperty.Title, SyndicationTextContentKind.Plaintext, true)]
public class DerivedCustomer : Customer {
   public string DerivedTypeField { get; set; }
}
In other words , when specifying the propertyName , property paths always make simple properties look like they are declared
on the type which has annotations , mapping inherited properties is no different from mapping properties declared on the same type.

Considerations for location  of EPM Attribute

Use the following guidelines to decide where in the entity model you should add the attribute for either ATOM or custom Mappings,

Where is property defined ? Where do I apply the EPM attribute?
Simple property on the Entity Type
ex:
“Title” property of “BlogPost” type above
Entity Type
Simple property on entity’s base type Derived Entity Type or Base Entity Type
Complex Property on the Entity Type Complex Types cannot be mapped directly See , 3
Simple property defined on complex type which is a property on an Entity Type Entity Type

Hope you enjoyed this post about applying Friendly Feeds mappings to CLR data models.
The next blog post will discuss how to apply the same mappings to EDM models.

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”.
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

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.

Did you know you could execute batch queries using the Data Services client library ?

The API is ExecuteBatch for Synchronous access and Begin/End ExecuteBatch for asynchronous scenarios.

1) Batching a set of URI Queries .

The ExecuteBatch API accepts an array of DataServiceRequest objects.
Consider this example , you want to batch queries to be sent to the “Products” and “Categories” entity sets of a northwind service.

2) Batching Linq Queries

If you want to use strongly types Linq queries instead of string based URI queries , you can use the linq support to generate the linq query

3) How do I Identify the response if I make duplicate requests with the same ElementType ?

Consider this situation , You make 2 requests both of type DataServiceRequest<Products>  , how do you identify
which response is for which request ?

One of the scenarios  I can think of , is that the entity set contains multiple types related via inheritance .

ex: Customers entity set contains instances of types HappyCustomers and HappierCustomers inheriting from Customers.

The QueryOperationResponse type contains a Query property which returns the DataServiceRequest that this response corresponds to .

You can pass along the requests you made in the batch as a state to the callback and then compare the Query property of the QueryOperationResponse
to match the response to the request.

ex:

I buckled under peer pressure .Here are the pics from the  2nd Annual Astoria Ski Day .

Explanations will come soon .

If you have a facebook account , here are the same pictures ,tagged.

Astoria Ski Day V2

I’ve seen this question quite often on the Astoria forums and wanted to write something down so that our users can gain from the discussions that go on in our forums.
We will discuss how one deals with entities ( tables / records / resources ) that participate in an inheritance hierarchy.
We shall take the following Data Model to discuss some key scenarios involving the Client Library.

//Base Class
[DataServiceKey("PersonID")]
public class Person {
        public int PersonID { get; set; }
        public string Name { get; set; }
    }

//Derived Class
public class Employee : Person {
        public int EmployeeID { get; set; }
}

And you expose an IQueryable<Person> from your data source,

public class InheritedProvider {
        static List<Person> _people;
        private static void Initialize()  {
            _people = new List<Person>(){
                new Person  {
                    PersonID =1,
                    Name="Phani"
                },
                new Employee {
                    PersonID =2,
                    EmployeeID =3,
                    Name ="Raj"
                }
            };
        }
        public IQueryable<Person> People {
            get {
                if (_people == null)
                    Initialize();
                return _people.AsQueryable<Person>();
            }
        }
    }

Browsing to the /People endpoint of the service gives you :


<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<feed …Namespace Declarations… >
  <title type="text">People</title>
  <id>http://localhost:13975/Inheritance.svc/People</id>
  <updated>2008-12-23T20:56:47Z</updated>
  <link rel="self" title="People" href="People" />
  <entry>
  <id>http://localhost:13975/Inheritance.svc/People(1)</id>
  <title type="text" />
  <updated>2008-12-23T20:56:47Z</updated>
  <author>
  <name />
  </author>
  <link rel="edit" title="Person" href="People(1)" />  

<category term="Repro.Person" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 

<content type="application/xml">
  <m:properties>
  <d:PersonID m:type="Edm.Int32">1</d:PersonID>
  <d:Name>Phani</d:Name>
  </m:properties>
  </content>
  </entry>
  <entry>
  <id>http://localhost:13975/Inheritance.svc/People(2)</id>
  <title type="text" />
  <updated>2008-12-23T20:56:47Z</updated>
  <author>
  <name />
  </author>
  <link rel="edit" title="Person" href="People(2)" /> 

<category term="Repro.Employee" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />

  <content type="application/xml">
  <m:properties>
  <d:PersonID m:type="Edm.Int32">2</d:PersonID>
  <d:Name>Raj</d:Name>
  <d:EmployeeID m:type="Edm.Int32">3</d:EmployeeID>
  </m:properties>
  </content>
  </entry>
  </feed>

As you can see , the <Category> element of an <entry> element represents the Entity Type that this <entry> represents.

How does this help one with working with against an Entity Set using Inheritance ?

Consider the following snippet of Client Code :

DataServiceContext dsc = new DataServiceContext(new Uri("URI_TO_DATASERVICE"));
Employee newEmployee = new Employee() {Name = "Peter Qian"};
dsc.AddObject("People", newEmployee);
dsc.SaveChanges();
Can you guess what is wrong with this ?

Yep, since the client library sees that you are trying to insert a Person Entity , we put the Entity Type as “Person”
in the payload , i.e , the above operation results in the payload :
<entry xmlns:d=http://schemas.microsoft.com/ado/2007/08/dataservices 
xmlns:m=http://schemas.microsoft.com/ado/2007/08/dataservices/metadata
xmlns="http://www.w3.org/2005/Atom"> <updated>2008-12-23T21:23:38.5935141Z</updated> <content type="application/xml"> <m:properties> <d:EmployeeID m:type="Edm.Int32">0</d:EmployeeID> <d:Name>Peter Qian</d:Name> <d:PersonID m:type="Edm.Int32">0</d:PersonID> </m:properties> </content> </entry>

And this causes the Server to respond with :

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<error xmlns="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
  <code></code>
  <message xml:lang="en-US">Error processing request stream. 
    Type information must be specified for types that take part in inheritance.</message>
</error>

This error is because , as you can see in the request payload , the <category> element which specifies the Entity Type is missing form the Request Payload.
Since the Client library doesn’t resolve the Names/Types of the Entities for you , it provides you hooks to customize the name/type resolution
so that the right entity type is specified in the payloads.

Why can’t the Client library do this automatically ?

Main reason , Since we allow POCO , the type hierarchy of entities on the client can be different compared to the server.

In your client code , set the ResolveName and ResolveType Properties on the  DataServiceContext instance to
override the default type resolution behavior.

ex :

DataServiceContext dsc = new DataServiceContext(new Uri("URI_TO_DATASERVICE"));
dsc.ResolveName = delegate(Type entityType) {
     return entityType.FullName.Replace("<ClientNamespace>", "<ServerNamespace>");
};
dsc.ResolveType = delegate(string entitySetName) {
      return Type.GetType(entitySetName);
};
Employee newEmployee = new Employee() {Name = "Peter Qian"};
dsc.AddObject("People", newEmployee);
dsc.SaveChanges();
Since we provide the right Entity Type Name in the ResolveName property , the right Entity Type
is placed in the payload.
<entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices"            
       xmlns:m=http://schemas.microsoft.com/ado/2007/08/dataservices/metadata
xmlns="http://www.w3.org/2005/Atom"> <category scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" term="ServerNamespace.Employee" /> <updated>2008-12-23T21:52:44.8021175Z</updated> <content type="application/xml"> <m:properties> <d:EmployeeID m:type="Edm.Int32">0</d:EmployeeID> <d:Name>Peter Qian</d:Name> <d:PersonID m:type="Edm.Int32">0</d:PersonID> </m:properties> </content> </entry>

Hope this helps .

I probably brought this onto myself by taking all my vacation time in November to go back home for a month long visit.

Now that its December , almost 80% of the team is on vacation and I am in office. Its not just my team , most of my floor
in building 35 is on vacation. I hardly see anyone in the hallways nowadays , the silence feels unusual.
Most of the people with whom I used to discuss any new ideas are on vacation , and not having anyone around
to bounce my ideas off of feels weird . Although , the silence lets me get a lot done though , no distractions.

Thanks to the unusual ( in Redmond terms) snow, the campus shuttles are shut down for these snowed-in days .
That means my walk to work for  a distance of mere 3 mile feels like 10 miles as I have to walk real slow
to prevent slipping on the ice and falling . And not to mention that it gets dark by 4 PM in the evening .

So I go to work in the dark and go home in the dark, but only have an eight hour day.
Guess I can check off one of the items in the list of You Might be from the Pacific Northwest if You….

This is how evenings look when I step out in the evenings to go home .
DSCN0333

Pretty awesome , isn’t it !

Oh and before I forget , Happy Holidays Readers !!

This post is inspired by this forum thread :Data services client -- exception on saveChanges

Problem Statement


I have added some custom proeprties to the Entity Types Generated by DataSvcUtil.exe /Add Service Reference / Hand Coded ,
these properties do not exist on the server and should not be sent to the server .
When I try to save an object of a Type which has custom client-Side only properties to the Data Service using AddObject and SaveChanges,
I get the following error :

Error processing request stream. The property name '{PropertyName}' specified for type '{TypeName} is not valid

This error is basically from the server telling the client library that its sending a payload which does not seem to match the definition
of the Entity Type on the server.

We can solve this problem by customizing the Payload that the client generates when it sends the entity to the server.
The DataServiceContext exposes an event called WritingEntity that is fired right before we send the payload over the wire.

Its argumentlist contains ReadingWritingEntityEventArgs which gives you access to the Entity Instance being Serialized ( e.Entity ) 
and the ATOM Payload (e.Data ) we are about to send to the Server.

Removing a property from the ATOM Payload that is being sent to the server.
void dataContext_WritingEntity(object sender, ReadingWritingEntityEventArgs e) {

    // e.Data gives you the XElement for the Serialization of the Entity 
    //Using XLinq  , you can  add/Remove properties to the element Payload  
    XName xnEntityProperties = XName.Get("properties", e.Data.GetNamespaceOfPrefix("m").NamespaceName);
    XElement xePayload = e.Data.Descendants().Where<XElement>(xe => xe.Name == xnEntityProperties).First<XElement>();
   //The XName of the property we are going to remove from the payload
    XName xnProperty = XName.Get(“{PropertyName}”, e.Data.GetNamespaceOfPrefix("d").NamespaceName);

    //Get the Property of the entity  you don't want sent to the server
    XElement xeRemoveThisProperty = xePayload.Descendants().Where<XElement>(xe => xe.Name == xnProperty).First<XElement>();
    //Remove this property from the Payload sent to the server 
     xeRemoveThisProperty.Remove();

     }
}

Generalizing this further , we want to make it easier to customize the serialization of multiple entity types without having to write
multiple copies of the WritingEntity event handler.
We will add an attribute that specfies that a certain CLR property should not be serialized in the ATOM Payload when the client library
sends the entity to the server.

    /// <summary>
    /// Properties marked with this Attribute are not serialized in the payload when sent to the server
    /// </summary>
    [AttributeUsage(AttributeTargets.Property)]
    public class DoNotSerializeAttribute : Attribute
    {
    }

Now , we change the WritingEntity Event handler to remove any property  that has this attribute on it .

        void DataServiceContextEx_WritingEntity(object sender, ReadingWritingEntityEventArgs e)
        {
            // e.Data gives you the XElement for the Serialization of the Entity 
            //Using XLinq  , you can  add/Remove properties to the element Payload  
            XName xnEntityProperties = XName.Get("properties", e.Data.GetNamespaceOfPrefix("m").NamespaceName);
            XElement xePayload = null;
            foreach (PropertyInfo property in e.Entity.GetType().GetProperties())
            {
                object[] doNotSerializeAttributes = property.GetCustomAttributes(typeof(DoNotSerializeAttribute), false);
                if (doNotSerializeAttributes.Length > 0)
                {
                    if (xePayload == null)
                    {
                        xePayload = e.Data.Descendants().Where<XElement>(xe => xe.Name == xnEntityProperties).First<XElement>();
                    }
                    //The XName of the property we are going to remove from the payload
                    XName xnProperty = XName.Get(property.Name, e.Data.GetNamespaceOfPrefix("d").NamespaceName);
                    //Get the Property of the entity  you don't want sent to the server
                    XElement xeRemoveThisProperty = xePayload.Descendants().Where<XElement>(xe => xe.Name == xnProperty).First<XElement>();
                    //Remove this property from the Payload sent to the server 
                    xeRemoveThisProperty.Remove();
                }
            }
        }

We can encapsulate this functionality into its own class and any DataServiceContext type that inherits from this class should be able to
inherit this functionality too .
Complete Source Code :

Using this in your applications :

Create a partial class with the same name as shown above and include it in your application to get this behavior.

Attribute your types with the DoNotSerializeAttribute  attribute so that this property is not serialized.

 public class TestType
    {
        public int ID { get; set; }
        /// <summary>
        /// This Property is client-only , should not be sent to the server
        /// </summary>
        [DoNotSerialize]
        public string ClientOnlyProperty { get; set; }
    }
More Posts Next page »
 
Page view tracker