Category Archives: Data Access

Custom Operations and hiding entities in Astoria

I learned a harsh lesson about Visual Studio and saving code snippets in the toolbox yesterday. Knowing that I am not great at coding Entity SQL on the fly, I stuck my code for custom operations in an Astoria Web data service into the VS2008 toolbox. I had two instances of VS open when I did this, so when I closed the instance where I had created the snippets, the instance that was still open is the one that saved the state and they were lost. Note to self: always have a text file with all snippets available when demoing. Oddly, I never used to trust the snippets and only used text files.  I guess I need to get back to a level of cautious (though not rampant) mistrust.

I did surprise myself this morning when I rewrote these from memory and only made one mistake… inserting an “@” where I didn’t need to. I’d call that an A-. It wasn’t a typo, though and it did take a few minute to discover the error which is something I don’t like doing during a conference session, so I just skipped the pain.  (Still only a C+ in my book 🙁 ).

So here, in place of that particular demo, is a post on how to write operations in data services.

The default service provides for all of the capabilities of drilling into, traversing and querying your entities as laid out in this post and in more detail in the Using Astoria document that comes with the downloads and is also on the Astoria site. (Start at http://astoria.mslivelabs.com to find all resources.)

However you can customize your service by providing explicit query operations and also blocking specific query operations. Don’t forget that you can also build views and sprocs into your model. Views are surfaced as EntitySets so they will be no different than other entities (though read-only) in your web service. Stored Procs are a little different. I have to explore how both of those are currently surfaced in Astoria, but would like to wait until we have bits that are not just prototype.

To create a custom operation you need to use the WebGet attribute. Here’s an operation that finds all customers based on the first name of the contact. (I’m using the AW LT database, and am just lazily querying for something that is a direct property of the customer table.)

<WebGet()> _
Public Shared Function CustbyContact(ByVal aw As AdventureWorksLTEntities, ByVal firstname As String) As ObjectQuery(Of Customer)
  If String.IsNullOrEmpty(firstname) Then
  ‘don’t expect to see this nice error if you are testing
  ‘your services in a browser
    Throw New ArgumentNullException(“firstname”, _
     “You must provide a name to search on”)
  End If

  Try
    Return aw.Customer.Where(“it.firstname=@fname”, New ObjectParameter(“fname”, firstname))
  Catch ex As ArgumentException
  ‘this is an opportunity to catch problems with your Entity SQL query when debugging
    Throw ex
  End Try
  End Function

Note that I’m using Entity SQL in this query. While the query

http://localhost:50000/WebDataService1.svc/CustbyContact?firstname=Linda

will work if I had used LINQ to Entities for the query, I found that further operators or options such as this example where I additionally sort the response data

http://localhost:50000/WebDataService1.svc/CustbyContact?firstname=Linda&$orderby=CompanyName

do not work unless I have used Entity SQL.

While I have used a WebGet attribute to add additional queries to my service, you can use OnSendEntity and OnReceiveEntity to trap calls to the web service.

This custom operation in my data service prevents any one from querying directly for SalesOrderHeader entities using http://localhost:50000/WebDataService1.svc/SalesOrderHeader.

<OnSendEntity(“SalesOrderHeader”)> _
Public Shared Function RequestOrders(ByVal aw As AdventureWorksLTEntities, ByVal order As SalesOrderHeader) As Boolean
   Return False
End Function

I can still get at SalesOrderHeaders, for example by requesting customers with the expand option for SalesOrderHeader entities.

The using astoria doc details the key components for creating a method that traps requests and also one that traps POST, PUT and DELETE operations.

Entity Framework object graphs and viewstate

I’ve been playing with using EF object in code-behind of aspx web pages.

The first issue to hit is postbacks.

Entity Objects are Binary Serializable so they can be stored in ViewState.

Like many other objects, you need to put your entities into viewstate (I’ll deal with session and application caching in another post). Happily entities can be binary serialized so that happens for free when you add an entity object to ViewState. So you can persist the entities, but you cannot persist the ObjectContext, which is where all of the state information for the objects lives. Frankly, the objectcontext is very expensive and you wouldn’t want that in viewstate anyway.

The outcome of this is that even if you store the objects in viewstate, and pull them back out to attach to a new ObjectContext when you need them again, you will lose any state for the objects.

One saving grace is that objects stored in viewstate get updated automagically during postback. In other words, if I create a cust object and store it in viewstate, then make a change to the cust object, then postback and pull the object back out of viewstate, it will have the newer property values. Viewstate is synced up to the object.

That means we can be sure to have a current version of the object (or list of objects) hanging around as we muck with the page.

Binary Serialization keeps the entire graph in tact

The next piece of the puzzle is that if you have an obect graph (i.e. order with order details or cust with orders with orderdetails) that all gets persisted during binary serialization. That’s a big difference from xml serialization. The big reason is that XML serialization doesn’t know what to do with the relationships, which are also first class objets. The relationships “contain” all of the related data. So binary serialization can handle this. When you get the object graph out of viewstate, it’s got everything in it that it had when it went in.

Updating related data in an object that is in viewstate

This doesn’t act the way you might expect so listen up.

Say I have a  cust object that has orders in it. i have saved the cust object into viewstate. If I edit a property of cust, say FirstName, that’s easy:

cust.FirstName=”Julie”

Viewstate syncs up that change just before the postback.

But what if I want to change something in one of the orders.

You need to do this directly in the cust object, not be extracting the order and changing it.

Here’s what I mean.

My first instinct is to do this:

myOrdtoEdit=(From ord in custs.Orders where ord.OrderID=123 Select ord).First()
myOrdtoedit.ShippedDate=”7/1/2007″

On postback, that new ShippedData is not there.

But if I make the change this way:

cust.Orders.Where(Function(o) o.OrderID = currOrderid).First.ShippedDate=”7/1/2007″

The change is synched up. Good to be aware of.

What about concurrency? What if I need to remember original values?

I think the real solution is going to be is to have original values cached in another layer. But for the sake of working out the concepts, let’s say you are doing everything in code behind. Here’s how I’m solving this problem.

When I first get the values, I want to store them in viewstate, too. But if I do that, and I want to take advantage of the synching viewstate (I think I remember seeing that there is a page directive to turn that off, but don’t hold me to it), then the original objects will get overwritten.

So what I have done was explicitly serialize the original objects and store the resulting memory stream into viewstate. When it’s time to do an update, I deserialize that stream and voila, I have a set of original objects that I can use to compare my current objects to.

I have a post here on how to do an update when you have the original object and current objects available over here.

One object or more? How do I persist multiple objects?

Note that I have wavered between talking about persisting a single object and multiple objects. If you are dealing with a query that returned a collection of objects, then you don’t persist the query. Instead, convert the query to a list with .ToList and you will end up with List<Customer> / List(Of Customer) and that’s what you can put into viewstate. This is also what you would serialize, the list of customer objects.

When do I work with the objects again?

I have done various tests using databinding (gridviews, textboxes) or just manually getting and setting text properties.

Once you post back, the datasource is gone on a bound control anyway. I just work with the text values that are in the control. When I want to update an object, then I will get the object(s) from viewstate and modify them. Other than that, the only time I need them again is when it’s time to do an update back to the data store.

Resources for LINQ talk at San Diego .NET

Last week I did something that may have seemed  a little silly to some, but was a great deal of fun. I left my house at 7am, drove to the airport, flew all the way across the country (from the northeast corner of the U.S. to the southwest corner) to San Diego to give a 2 hour presentaiton to the San Diego Dot Net user group on behalf of INETA.

The silly part was that I spent about 15 hours on 4 different planes to give a 2 hour talk. But I loved doing it!

Frankly, 15 hours on planes gives me more productive work time than I have when I’m working in my home office. Probably a good 10 extra hours! No phone, no email, no distractions. I’m stuck on a plane with my laptop and hopefully a movie that I have no interest in seeing and I can just work work work! Well, the movie on the way out was good and it even made me cry (darn I hate that). On the way back it was Fantastic Four – no interest whatsoever.

The other great part about this trip was that I got to spend some great quality time with a friend as well as  an hour by the ocean on Wednesday morning before heading to the airport to return home.

And of course, I got to do one of my most favorite things – present at a user group  on a topic that I find fascinating. My talk was about LINQ. Originally I had hoped to “practice” a talk on ASP.NET Databinding with LINQ that I’ll be doing in November at DevConnections.  I had added some introductory LINQ information to the beginning of the talk as Brian Loesgen, the group leader, told me in advance that they haven’t had a LINQ talk yet.

At the start of the meeting, I asked for a show of hands on who had used LINQ already – only two people. So I ended up focusing on the intro part and just showing some of the databinding quickly at the end. The intro stuff includes the always fascinating language enhancements that enable LINQ and then a quick tour of all of the LINQ “flavors” – objects, datasets, xml, entities and of course, LINQ to SQL. That is a lot of fun to go over.

I made the executive decision to try to write some C# code on the fly, which never goes well – especially at bed time. If you consider the time zone difference I started the talk at 10pm. But I aim to entertain, and I certainly didn’t disappoint much to a bit of embarrassment on my part. Semi-colons are not an issue. I remembered square brackets rather than parens. But this time it was the spacing that got me. VB just takes care of so many little syntax problems you might forget. C# is 100% unforgiving.

Getting past that, I had a blast and managed somehow to wrap up just about on time even though I could have gone on and on for hours more.

Throughout the course of the talk, I mentioned some great articles and resources and wanted to put them all in one place so here they are:

101 LINQ Queries for C#

101 LINQ Queries for VB

Great LINQ overview article by Don Box and Anders Hejlsberg

Lambda Epxressoins article for VB coders

VB Deep Dive articles by Bill McCarthy in Visual studio Magazine – There seems to be no list of all the columns, you have to go look in each issue in the archives. Here is Bill’s blog.

The LINQ Project: consolidated starting point for MSDN materials

LINQ best practices for VB (webcast)

Books I mentioned:

Already published Introducing Microsoft LINQ from MS Press

Coming soon LINQ in Action

Blogs I mentioned:

Roger Jennings

Jim Wooley

LINQ in Action blog

Mike Taulty

Scott Guthrie’s LINQ to SQL post series

XML Serializing Entity Framework entities with their children for SOA

Another challenge in working with tiered solutions (notably web services) that require xml serialization of entity objects is that the xml serializer does not serialize the entire graph. It only gets the main object and drops all of the relations. This is not because Entity Framework is trying to be mean, just related to how XML serialization works. In fact, the binary serialization gets the entire graph. But in the web services scenarios, we need XML.

So how to go about passing the full graph from client to server and back or server to server? I had a few ideas of how to approach this but was given a suggestion by Danny Simmons that would help me create something that would be more aligned with what their thinking on this is.

This solution uses a facade pattern. It is possible because the individual objects are serializable and a generic List is serializable. Conceptually, I take all of the objects in the graph that may start out, for example as:

-Customer
  – Orders

and create Lists of each set of objects then combine those lists into another object. After this is created, the above would look like this

-List(Of Customer)   –> would only contain one
-List(Of Orders)

Deserializing would mean pulling the customer out of the first list, then iterating through the list of orders and adding each order to that customer.

It gets a little more complicated when dealing with deeper graphs.

-Customer
  – Order
     – OrderDetails
  – Order
     -orderDetails

now we need to serialize a bit more carefully

-List(Of Customer)
-List(Of OrderwithDetails)

The OrderswithDetails would be another object that looks like this

-List(Of Order)
-List(Of OrderDetails)

The OrderwithDetails class that implements the facade will need these features:

  1. A property to contain List(Of Order)
  2. A property to contain List(Of OrderDetails)
    1. if we are going deeper then this property should be List(Of OrderDetailswithChildren)
  3. Instantiation code needs to take in the original object and construct the lists
  4. A method that knows how to deserialize the object and return the real object, not the lists of it’s parts
  5. If this is going to be used in a wcf service, the class needs to be marked as a DataContract and the properties should be marked as DataMembers.

Here is what a simple class for serializing/deserializing the orders with their orderDetails (without considering any possible children of orderDetails right now). This is my first pass at this class and therefore it is not generic code that will work with any complex object. However, it does work out the basic logic (and it does work!).

<Serializable()> _
<DataContract()> _
Public Class SalesOrderwithDetailsGraph
Dim _order As List(Of SalesOrderHeader)
Dim _orderdetails As List(Of SalesOrderDetail)

Public Sub New()
‘required for serialization
End Sub

Public Sub New(ByVal salesOrderGraph As SalesOrderHeader)
 _order = New List(Of SalesOrderHeader)
 _order.Add(salesOrderGraph)
 If salesOrderGraph.EntityState <> EntityState.Detached Then
    ‘if I’m just creating the order for the first time and am attached to the context,
    ‘this assumes that I didn’t Include salesorderHeaders in my query – big assumption, but
    ‘it is just for my proof of concept. If it’s detached, then I am already working with a 
    ‘full object and can’t load anyway – that requires a context and a connection
   
salesOrderGraph.SalesOrderDetail.Load()
 End If
 _orderdetails = New List(Of SalesOrderDetail)(salesOrderGraph.SalesOrderDetail)
End Sub

<DataMember()> _
Public Property Order() As List(Of SalesOrderHeader)
 Get
  Return _order
 End Get
 Set(ByVal value As List(Of SalesOrderHeader))
  _order = value
 End Set
End Property

<DataMember()> _
Public Property OrderDetails() As List(Of SalesOrderDetail)
 Get
  Return _orderdetails
 End Get
 Set(ByVal value As List(Of SalesOrderDetail))
  _orderdetails = value
 End Set
End Property

Public Function GetOrderFromGraph() As SalesOrderHeader
 ‘this is to Deserialize
  Dim ord As SalesOrderHeader
 ‘there will only be one header in the object
 ord = _order(0)
 For Each sod As SalesOrderDetail In _orderdetails
  ord.SalesOrderDetail.Add(sod)
 Next
 Return ord
End Function

End Class

Now, if i have a simple scenario where I have a client that requests an order from a web service, mucks with that order, then sends it back to the service for an update, the client can start by retrieving a SalesOrderGraph, deserializing it back to a SalesOrder, then when it’s done, create a SalesOrderGraph from the existing SalesOrder and pass it back up to the Service.

There’s one big missing piece here and I blogged about that yesterday. When the order gets back to the service for an update, if you plan to update through the objectContext, then you will need to manually set the state to modified. You can do this with or without original data (depending on whether or not you care about concurrency). See my blog post about Disconnected Entities.

Lastly, I have actually gone the next step with the above serializer so that i can get a Customer with Orders and OrderDetails. It means bulding a CustomerGraph just as I built the Order Graph, but the children of the Customer will be SalesOrderwithDetailGraph objects, rather than just SalesOrderHeaders. Then you get a recursive thing happening where the customer knows how to work with it’s orders, and each order know how to work with it’s details.

But this post is long enough already, eh?

More on Disconnected Entity Framework

One of the biggest challenges with Entity Framework for updates is that if you want to move objects across tiers, you lose the object’s state. All of the state and change tracking information is maintained by the object context. While entity objects are serializable (xml and binary) and can be transported across tiers, object context is not.

 

Therefore, if you have objects being managed  by an ObjectContext in one tier, then move them to another tier and attach them to a new ObjectContext, you will have the current data, but nothing else and the object will be seen as “unchanged”.

 

If you want to use the ObjectContext’s SaveChanges method to do your db updates (I am using the term “update” generically to refer to updates, inserts and deletes, aka “the CUD in CRUD”), nothing will get sent to the server since it’s all seen as unchanged.

 

There are a few ways we have seen to get around this., but they have all boiled down to this:

 

Solution #1 Ignore concurrency and perform an inefficient update

 

Buried in replies by team members in the ADO.NET Orcas forums there is a  conceptual solution that leverages the EntityState object (combined with EF’s MetaDataWorkSpace or reflection) to mark the object as modified and then iterate through ALL of the properties in your object and change their state to “modified”. Now SaveChanges will push all of the current data up to the server.

 

What I like about this solution:
It’s reusable code that will work with any entity which you throw at it.

 

What I don’t like about this solution:

1) What is hugely unsatisfying to me is that this is a pure “last data in wins” scenario. While this is probably all that many solutions require, it means that there is no interest in handling any possible conflicts for data that may have changed on the server in between the user’s fetch and subsequent save.

2) Every property is flagged for update. Every property value is sent to SQL Server and every property value is updated in the database. Icch.

 

Solution #2 Write object update code for every single entity class

Another workaround I came up with was to extend the entity class so that it knows how to update itself. This assumes we have kept the original data hanging around somewhere. For each class, I created a method that takes in the current entity and the original entity, then I have some code that explicitly updates fields that I care about updating. Here’s part of that, where I’m dealing with updates, but not deletes and inserts.

 

 

This works – the original order now has the current values updated to the new values and the state is impacted correctly for the properties and the entity itself. Then I can use SaveChanges or other functionality that I’ve exposed in my model such as stored procedures to get the data to the server. The key here is that I can leverage the framework for my DML.

 

But this solution stinks because I have to write the same method over and over again for every single class.

 

Solution that I want and finally figured out: Update only relevant properties and have the option to deal with concurrency on a granular level

Mike  Taulty actually pulled this off in this blog post, however I explicitly chose to hold off on reading Mike’s post. 🙂 I didn’t want to be influenced by his methods. What’s interesting is that in the end, we came up with very similar solutions, even though I went down many many paths before I found success! (I’m sure it took me about 10 times as long as it took Mike though.) Some evidence of my doggedness is in Dave Burke’s post about what an un-fun girl I was on Saturday night at code camp.

 

Updating for efficiency and concurrency

 

So here’s what I came up with as part of a larger solution of using entity framework in an ASP.NET website, surviving post backs, keeping the original values around and being able to use SaveChanges and also for using entities across tiers (eg web services).

 

I use reflection and the Entity Framework MetaDataWorkspace to accomplish this.

 

I’ll write another post about how I’m keeping the original values and surviving the postbacks on the ASP.NET site.

 

#1 important rule that has been discovered by everyone who is trying to solve this problem in Entity Framework and in LINQ to SQL, use a datetime field in your entity. This can be a field that is already in your database table or a special property exposed only by the conceptual model (or an extension to the entity’s class). If it’s in the database, you’re original data is fine, but you need to be sure to update that field any time you make mods to the properties of the entities. If you create a special property in the EDM, then you’ll also need to set the date when you first retrieve data from the data store.

 

Below, I am starting with a collection of original objects and a collection of current objects in hand. The collections are generic lists as in List<CustomerEntity>.

 

Step 1: Get a list of only those objects that have been altered since the data was first retrieved as well as objects to be inserted and objects to be deleted.

 

LINQ to the rescue!

 

In my example, origCustList is the List(Of Customer) with the original objects. custList is the List(Of Customer) with the new objects.

 

Inserts and deletes are not so complicated.

 

For inserts, I only need to query the current customers for those with no ID.

 

Dim inserts = custlist.Where(Function(c) (c.CustomerID=0))

 

Now I only need to add the new customers to my ObjectContext.

 

For Each insCust In inserts
   myObjContext.AddToCustomer(insCust)
Next

 

I cheated by using AddToCustomer for the inserts. For a more generic solution, just use the AddObject method instead.

 

 

For deletes I query the original customers and find any that don’t have a match in the new customers.

 

Dim deletes = From oc In origCustList _
 
Where Not 
custlist.Any(Function(c) (c.CustomerID=oc.CustomerID))

 

Next you need to attach, then delete these objects from the ObjectContext. These steps for delete may not seem intuitive. The object needs to be known by the ObjectContext (therefore you attach it) and then deleting it from the ObjectContext marks it as a record to be deleted when we SaveChanges back to the database.

 

For Each delCust In deletes
   myObjContext.Attach(delCust)
   myObjContext.DeleteObject(delCust)
Next

 

Now come the updated cystomers. Here’s where it gets fun!

 

I’m using LINQ to join on customerid and grab objects that have a newer dateModified value. This is where the date property pays off. Otherwise, I’d have to check every property of every object to see if anything changed.

 

Dim updates = From oc In origCustList Join cc In custlist _
On
oc.CustomerID Equals cc.CustomerID _
Where oc.ModifiedDate <> cc.ModifiedDate _
Select oc, cc

 

Now I have a pair of related objects for each modified customer.

 

In order to emulate a scenario where the objects have been tracked by the ObjectContext from the start, I need to attach the original objects to this new ObjectContext and then make any necessary changes to the objects. I iterate through the collection of object pairs and pass them off to a custom method, updateEntityProperty.


For Each c In updates
  myObjContext.Attach(c.oc)
  updateEntityProperties(aw, c.oc, c.cc)
Next

 

Here is where the cool stuff happens!

 

I want to preface this by saying that I tried using the ObjectStateEntry to pull this off, but it didn’t give me quite enough capabilities as I needed for this solution. The class allows you to change the state of the entity to Modified and to change the state of the individual properties to modified, but I also needed to change the values of the properties, which I couldn’t acheive with the state manager (which makes perfect sense – values are not state). [Update – apparently what I needed was in there; I just couldn’t find it and after trying for some time, chose to move on to reflection.] So instead I am using reflection to help me modify the values programmatically. When I do this, the state changes automatically.

 

Although I didn’t get to use ObjectStateEntry, I am leveraging the MetaDataWorkspace which is also part of the Entity Framework.

 

Private Sub updateEntityProperties(ByRef context As AdventureWorksModel.AWModel.Entities, ByRef origcust As Customer, ByRef newcust As Customer)


Dim mdw As Data.Metadata.Edm.MetadataWorkspace = context.MetadataWorkspace

‘do an explicit declaration of Edm.EntityType, otherwise custtype becomes an edmtype
‘which doesn’t expose
properties that I want to grab through reflection!

Dim
custtype As Edm.EntityType = _
mdw.GetType(GetType(Customer).Name, “AWModel”, Edm.DataSpace.CSpace)

For
Each p In newcust.GetType.GetProperties ‘<- that’s Reflection at work
   Dim newprop = p.GetValue(newcust, Nothing)
   If newprop Is Nothing Then
     If p.GetValue(origcust, Nothing) IsNot Nothing Then
       p.SetValue(origcust, newprop, Nothing)
     End If
   Else
     If
Not newprop.Equals(p.GetValue(origcust, Nothing)) Then
      ‘if we are here, then the value in new cust is different from the original
      ‘SKIP THIS FOR NOW IF IT’S A PROPERTY COLLECTION –

      ‘TO DO: build in recursive behavior to update property collections as well
      ‘simplest test to see if it’s a property collection or not: straight values are a System
       If newprop.GetType.Namespace = “System” Then
          p.SetValue(origcust, newprop, Nothing)
       End If
     End If
   End If
Next

End Sub

 

So, this is not quite perfect yet, but it does the job and I’m really happy that I got the concept worked out. I need to do a few more things to make this work generically and I also need to add in recursive mods to this. For example, the Customer has a property collection of addresses. In the above code, I am ignoring them, but I need to make this solution so that if it hits a property collection (this is where I’m testing for a System type – if it’s not system type then it’s a  property collection that is exposing child records) that it calls the same UpdateEntityProperties on that entity as well. SaveChanges will take care of all of the related records that are in the ObjectContext.

 

While this isn’t a cut & paste solution like Mike’s, i hope that the explanations help you to understand how and why this works. There are quite a lot of lessons that I learned during this exercise.

 

I have two more patterns that I have worked out which I want to write about. The first is dealing with the state when working in an ASP.NET application (postbacks trash the objectcontext, too) and the other is doing xml serialization on the entire object graph. Danny Simmons gave me a hint for how to approach the graph problem, and I was able to work it out from there.

Trying to see what Astoria messages look like in the pipe

I don’t like not knowing how something works, so I just had to dig further into how Astoria services see requests for queries versus Updates, Deletes and Inserts.

In my previous post, I dug into the assembly with reflector and could see that a PUT was used for updates, DELETE for deletes and POST for inserts.

I turned tracing on for the Astoria service and pushed the trace info to a log file. You can see how to do that at the end of this post.

Looking at the messages, you can see the METHOD and the query operators but not the main call. 🙁

For example if I made a call to service.svc/Customers the message looks like this. I’ve stripped out WebHeader information from the message.

<HttpRequest xmlns=”http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace“>
<
Method>GET</Method>
<
QueryString></QueryString>
</HttpRequest>

I don’t see that I called the Customers “operation”.

If I request service.svc/Customers[52], it’s the same. I don’t see the Customers and I don’t see the ID i’ve passed in.

If I use a query operator as in service.svc/Customers[City eq Seattle], it’s still not exposed. Now I’m getting frustrated. I know I’ll have to dig deeper at some point, or bribe Pablo to show me someday.

But for now here’s a little gratification. If I create my own Service Operation which takes a query string, now there is something to see. My service operation is CustomersbyCity. the call looks like this

service.svc//CustomersByCity?city=London

The message looks like this

<HttpRequest xmlns=”http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace“>
<
Method>GET</Method>
<
QueryString>city=London</QueryString>
</HttpRequest>

When I use my little console app as a client and do some inserting and deleting, I can see the methods coming up the pipe, remember, the Astoria.Client.dll translates the function (insert/update/delete) into a Method.

<HttpRequest xmlns=”http://schemas.microsoft.com/2004/06/ServiceModel/Management/MessageTrace“>
<
Method>DELETE</Method>
<
QueryString></QueryString>
</HttpRequest>

So, only MILDLY interesting to me (because I can’t get in deep enough yet) and probably COMPLETELY uninteresting to most everyone else. But it was fun digging around and also learning how to use some of the WCF tool. Here by the way is how I got to see the messages.

Modify the web.config to “Turn On” tracing and messaging. You can do it manually or with a tool.

    <system.diagnostics>
        <sources>
            <source name=“System.ServiceModel.MessageLogging”>
                <listeners>
                    <add name=“messages”
                    type=“System.Diagnostics.XmlWriterTraceListener”
                    initializeData=“c:\logs\messages.svclog” />
                </listeners>
            </source>
        </sources>
    </system.diagnostics>

    <system.serviceModel>
        <diagnostics>
            
<messageLogging logEntireMessage=“true” logMessagesAtServiceLevel=“true”
               logMessagesAtTransportLevel=“true” />
        </diagnostics>
    </system.serviceModel>

 

You can use the WCF Config tool in Visual Studio 2008 to configure this. Right click on the web.config and choose Edit WCF Configuration. Here are screenshots of the settings that created the above in my web.config.

If you are using the Web Dev server, you need to stop that server so that the trace actually gets written to the file before you can look at it.

Once the file is created, you can look at it using the Service Trace Viewer which you can find in the SDK Tools (available from Start/Program Files/Microsoft Windows SDK for Visual Studio).

Astoria is sick (as in SLICK) when it comes to DML!

I got bored with querying Astoria in the browser and and wanted to see how to use it in an application, so I opened up the sample console app that comes with the bits and started poking around and was astonished at what I saw.

You can create an new WebDataContext based on the Astoria data service.

WebDataContext is like an ObjectContext. Here’s what it exposes:

namespace Microsoft.Astoria.Client
{
public class WebDataContext : IDisposable
{
public WebDataContext(string uri);

public string BaseUri { get; }
public ICredentials Credentials { get; set; }

public void Add(object obj, string entitySet);
public void Attach(object obj, string entityKey, ObjectState state);
public WebDataQuery<T> CreateQuery<T>(string queryString);
public WebDataQuery<T> CreateQuery<T>(string queryString, QueryOption queryOptions);
public void Delete(object obj);
public string[] GetEntitySets();
public void MarkModified(object obj);
public void SaveChanges();
}
}

So, you can create a WebDataContext

WebDataContext ctx = new WebDataContext(“http://localhost:50000/northwind.svc”);

then query it

Category beverages =
ctx.CreateQuery<
Category>(“/Categories[CategoryName eq ‘Beverages’]”
)
.FirstOrDefault();

add a new object to the ObjectContext

Category newcategory = new Category();
newcategory.CategoryName =
“Sample”
;
ctx.Add(newcategory,
“Categories”);

And then (this is the part that is sick and I want to rip open the covers and see how they are pulling this off!), call SaveChanges on the context!

ctx.SaveChanges();

Of course, you can update and delete, too.

So, I wanted to see what’s going on here. It’s REALLY important to understand that we’re looking at prototype bits. THe production code that they are working on now will be different, though the concepts and use will be relative to what we can play with today.

You can’t get any hints by adding ?WSDL to the end of the uri. Rembmer withi a default asotira service, there are no operations. It’s all based on interpreting the URI. So I opened up Reflector and pointed to the key assembly.

SaveChanges calls a method called SendHttpEntityUpdate which sends up the object and the key and based on the operation calls a request method. So if you are adding, it sends a POST. If you are deleting, it sends DELETE and if you are modifying it sends PUT. The dll used by the service checks which method you pushed up (there’s an enum for ReceiveEntityOperations) and processes the incoming data accordingly.

Neat!

So of course there will be the usual million concerns about this. There are definitely credentials built into these operations and all kinds of ways to limit what is available thorugh the web service.  And there’s so much I don’t know yet, so don’t judge solely on what you are seeing here.

If you don’t have a .NET Astoria client, you can just construct the POST, PUT and DELETE URIs. I can’t say how to do that quite yet though. 😉 (Not that it’s a secret. I just don’t know how yet.)

But it’s still darned cool. Nice job folks (and don’t forget Alex who was key in getting Astoria going before he left Microsoft! )

More fun with Astoria – random queries in the browser

I find it helpful to use the browser to visualize immediate cause and effect of queries to an Astoria web data service. THere’s so much more that you can do when you are really using this in applications, though.

In the documentation there’s a list of query operators:

  • callback (specific to JSON for AJAX calls)
  • expand – pull related data using EDM associations
  • format – define format of the response (eg xml, json, rdf)
  • keyset- only return the entityKeys
  • orderby (you know what this is)
  • skip (same as in LINQ)
  • top

The doc explains each of these in more detail.

Here for example, I can get a specific customer and all of their sales order headers. (Make sure you have MultipleActiveResultSets=true in your connection string in order to do this. That allows the db to return more than one result on the same connection string .. a feature added in that we first acquired with .NET 2.0 and SS2005.)

I can drill even further to return the SalesOrderDetail data form the SalesOrderHeader using this URI:

http://localhost:55976/WebDataService1.svc/Customer[6]?$expand=SalesOrderHeader.SalesOrderDetail

Here’s an example of using skip

Looking at the non-xml formats is tough in Internet Explorer, at least with JSON as IE doesn’t know how to display the response. There are a few ways around this.

1) (bit of a hack :-))

Add this into the appSettings seciton of web.config

  <add key=”EnableAstoriaJSONP” value=”true”/>

and then browse your service in Firefox, Firefox will ask you waht you want to view the response in, choose notepad and you can see the json response. Read the caveats about JSONP in the Astoria documentation.

2) Use the helper tool which is an HTML page here [ http://astoria.sandbox.live.com/tools/raw.htm ]. You can’t use this online (I know ’cause I tried in my impatience!). You need to download it and add it into your project. It will then properly parse and display results.

So all this is just about querying, the “R” (read) in CRUD. Wait till you see the C, U & D. Watch for another post.