Your SlideShare is downloading. ×
RIA services exposing & consuming queries
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×
Saving this for later? Get the SlideShare app to save on your phone or tablet. Read anywhere, anytime – even offline.
Text the download link to your phone
Standard text messaging rates apply

RIA services exposing & consuming queries

3,966
views

Published on

Slides from week 8 of the Inland Empire .NET User's Group Silverlight 4 class

Slides from week 8 of the Inland Empire .NET User's Group Silverlight 4 class

Published in: Technology

0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
3,966
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
29
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide
  • Once the query methods are created in the domain service, let’s see what happens at build time.The build process extension provided by the framework goes through the assemblies in the server project and looks at each service derived class to check whether the EnableClientAccess attribute is present. If so it creates a matching domain context in the Silverlight application for each domain service it finds on the server. The domain context has the same namespace as its server counterpart.Then the tooling looks at each publically exposed query methods in the domain service and it creates a matching query factory method in the domain context on the client.Each query operation that is exposed is examined for the entity type that it returns. As we mentioned before, entity types are concrete classes that have one or more properties annotated with a key attribute and these classes may be generated automatically by the data layer depending what you choose to use.The tooling creates an entity client proxy type for each entity type exposed on the server.The client type has the same namespace and class name as the server entity and exposes the same public members.Code generation provides the client=side proxy with data binding capability through the INotifyPropertyChanged interface and validation capability through INotifyDataErrorInfo. We’ll look at validation in two weeks.Custom attributes that are applied server-side are reflected on the client provided that the appropriate assemblies are made available to the client.Server-side metadata is merged with the entity type and so it is reflected directly in the client-side entity proxies.
  • Probably the most important class generated for us by the build process is the typed domain context. The domain context is the chief orchestrator on the client.Among its generated members we find a series of constructors that allow us to pass various pieces of information to the class such as WCF service uri information, or a domain client instance which is a client side base class that is used to communicate with the server using a specific communication channelThe domain context also contains a set of query factory methods which return query proxies that match the server-side query operations that we’ve defined on the server.Also generated for us is a set of properties that give us access to client-side entity proxies.We also have an entity container factory method which creates an entity container instance
  • Let’s examine how the querying mechanism actually works.When we need to retrieve data from the server what we do is make an asynchronous call from the client using one of the load methods that are exposed by the domain context base class.First we get an instance of the generated typed domain context class.Next we grab one of the client-side proxy queries through one of the query factory methods generated for in the domain context class. That proxy class represents one of the server-side queries we want to invoke.The actual type of that query is EntityQuery. The EntityQuery class encapsulates information about the server query we want to call. We can extend that query through Linq composition right here on the client before sending the query back to the server.Once we get a hold of the query proxy, we pass it to one of the load methods provided by the domain context class which will then send the query data across the network through the client-side infrastructure and then through the WCF infrastructure.When the load call is made, the load method immediately returns an instance of the LoadOperation class. The load operation object represents an ongoing asynchronous load operation.After the call returns, we can access the results of the query asynchronously through load operation entities property. In Silverlight we can bind to that property using a datagrid for example.Now asynchronous is the key word here. It is important to remember that, so lets take a closer look at how that works.
  • There are actually 5 overloads of the load method that can be called. All of them take an EntityQuery parameter which represents the query method invocation.Two of them allow us to pass a completion callback and two allow us to specify how we want the results of the query to update the client-side cache through the LoadBehavior parameter.The overloads that allow a callback are very useful for dealing with the asynchronous nature of the load call. We specify a callback method that the load operation will call whenever it returns.There are at least two ways to specify a callback:One is to pass a delegate or lambda expression as a parameter to the load method. We also pass custom state information to the UserState parameter or you can pass null if none is required.Another way to specify callback is the handle to load operation completed event. Note that you can use an anonymous method or lambda expression for this.All these overloads return a LoadOperation Object, so lets zoom in on that object for a second
  • The load operation exposes an Entities and an AllEntities property which we use to retrieve the loaded data. Through the Entities property we can access the top level entities in the return results set, as well as nested entities within those top level ones. Note that when we use this property, the nested entities get loaded on demand from the client-side entity container provided of course that the object tree has previously been loaded from the server. The AllEntities property on the other hand, gives us access to all the entities in the hierarchy in a flat manner.Load operation also has an EntityQuery property which stores the entity query instance that was passed by the load method, and remember that EntityQuery encapsulates the server-side query that we are invoking,Also the result count returned by the server can be retrieved by the load operation TotalEntityCount property.Load operation ultimately derives from OperationBase, which is the base class for all operation types in the framework including submit and invoke operations which we’ll see next week.OperationBase implements INotifyPropertyChanged so it knows how to raise notifications when the operations complete status is updated and that’s what enables us to bind data to a data grid to the load operation object even before the load call has completed.OperationBase also provides operation canceling and error handling capabilities.
  • Once the asynchronous load call returns from the server, the properties of the load operation instance returned by the load method are populated, but there is another important thing that occurs when the server call returns.The domain context passes the data retrieved by the load call to the entity container for caching on the client.You may recall from last week that Ria services architecture defines a stateful client. State is largely maintained through the entity container in collaboration with the domain context and the entity sets.Entity sets are IEnumerable collections of entities in which the entity container caches the results of the instances. This means we can continue to access the loaded data even after the load call is exited and we do that through a bunch of public properties exposed by the domain context that give us access to the entity sets.Each of these properies actually returns a list of entities stored in the client cache which is the entity container.The entity container manages the list and tracks changes in them.Entity sets contain entity instances. Remember the tooling has generated in the domain context some entity proxy classes based on the domain entities returned by the domain service operation.Each of these client-side type are derived from the entity base type which has change tracking, validation, data binding, and updating capabilities.Both entity and entity set implement INotifyPropertyChanged, so just like the load operation object we can bind to our entities even before the data has finished loading from he server and then the UI gets notified when the operation is complete.
  • Let’s take a look at the query proxy that is returned by the query factory method that gets generated by the tooling at build time. Remember, these query proxies are the ones we passed the Load method to invoke the corresponding server side operation.There type is EntityQuery<T>. Now before passing an entity query to the load method, we can actually extend it on the client. We mentioned that the EntityQuery class encapsulates information about the server-side query to invoke. That includes the query name and parameter information. EntityQuery also exposes a query property that can store an Iqueryable client-side query that we apply before invoking load.The entity query class has the capability of taking a client-side Linq query, store it and ultimately send that query across the network through the call stack so that it can be applied on the server.EntityQuery actually acts like an Iqueryable object on the client, and this capability is provided to it by the EntityQueryable extension class. Its extension methods allow us to apply a few specific Linq operators such as … and all this on the client.What this means is that we can filter and shape our query before it is passed on to he server.When the server call is made, along with the server-side name and parameters, the client-side Iqueryable is serialized and transmitted on the wire. The query sent to the DAL then combines both the server part and the client part of our request.This is a powerful part of Ria services as it allows us to shape the data, if we wish to, as close to the client as possible. Even though we can shape the data on the client, execution takes place on the server so we avoid the common pattern of having to haul back heavy loads of data only to discard large amounts of that data through pure client-side filtering.This is an important aspect of the framework as it provides the base capabilities for things such as the domain data source control.As we’ll see later in this course, using the domain data source control we can filter, sort, group and page data in a very simple and powerful way, and these features are enabled by this end-to-end query design that is part of the Ria services framework.
  • Ria services allows us to retrieve object trees containing related entities in our queries. This simplifies classic scenarios such as master-detail scenarios and in general allows us to retrieve related objects together with the root object.There are actually several types of relationships that are facilitated by the framework including more complex ones such as composition relationships that exist between an order and its line items, and inheritance items. We are going to limit the talk to a basic association relationship that exist between two entity types.To enable the client to retrieve related entity types we need to take a couple of steps.First we need to annotate the server side entity types with the include attribute. If the entity types are generated automatically in our project, for example if we use EF or L2S as our data layer, we can do the attribute annotation in a metadata class that is associated with the root type instead of directly in the root type definition.The second thing we need to do is to explicitly include the related entities with the root entities and the results of our query operation in the service. Typically we do this using the Linq operator. As a result, the query operation will return an object tree that contains related entities along with the query and root entities.Once we build the project, the object tree becomes available on the client. The client’s entity proxy now has new properties that return the related entities that were specified on the server and these properties are annotated with the association attribute on the client that allows us to traverse the tree and access related properties client side.
  • Now that we’ve looked at how to create and send queries from our Silverlight client to our domain service, let’s take a quick look at what happens behind the scenes.There are actually a slew of classes that participate in the query call on both sides of the network. On the client side, the domain context is agnostic of the communication stack. It uses a sub-class of domain client to set up the actual asynchronous call through the WCF pipeline. By default, it is the Web Domain Client that is used which knows how to create a WCF client channel using a channel factory and a service contract that was copied to the domain context at build time.On the server side an http module intercepts the query call from the client and dynamically creates an in-memory svc file.The in-memory svc file is based on the service contract that is shared with the client.In a previous step, the contract was generated by our domain service by a domain service host which changed the query operation return type from the one we specified in the domain service to a QueryResult<T> that contains additional information besides the result of the query.The domain service host also hosts the service and by default a binary encoded REST type endpoint is exposed
  • Transcript

    • 1. Week 7 – WCF RIA Services Overview
      Jim LaVine
      jim.lavine @gmail.com
    • 2. Remaining Schedule
      1-8 Exposing and consuming querying services
      1/15 Updating data
      1/22 Business Logic and validation
    • 3. Agenda
      Domain query rules
      The DomainContext Class
      Asynchronous loading
      Client-side data caching
      Shaping data in the client
      Retrieving object hierarchies
      A peak under the hood
    • 4. Design-time workflow
      Server project
      Client project
      Domain Service
      CRUD
      Domain Service
      Domain Context
      Load
      2
      Invoke
      Custom
      logic
      Build
      Entity Container
      Data model
      Metadata
      Entity
      Metadata
      Entity proxy type
      3
      Metadata
      Entity
      Metadata
      Entity proxy type
      Metadata
      Entity
      Metadata
      Entity proxy type
      1
      DAL
      Bindable
      UI Views
      L2S
      EF
      REST/SOAP
      POCO
      4
    • 5. Domain query operation rules
      IEnumerable
      IQueryable
      <T>
          [EnableClientAccess()]    public class ChinookDomainService : LinqToEntitiesDomainService<ChinookEntities>    {                public  IEnumerable<Invoice> GetInvoiceByCustomer(int customerId)        {    return ObjectContext.Invoices.Where(c => c.CustomerId == customerId); }        public Customer GetCustomerById(int customerId)        {    return ObjectContext.Customers.Where(c => c.CustomerId == customerId); }    }
      public
      Supported
      types
      Entity
               public  IEnumerable<Customers> GetCustomersByJoinData(DateTimemindate, DateTimemaxdate)        {    
      return ObjectContext.Customers.Where(c => c.JoinDate >= mindate && c.JoinDate <= maxdate); 
      }
      No
      Overloads
    • 6.          public class  Customers        {    
      [Key]
      public int CustomerId { get; set; } 
      public string FName{ get; set; } 
      . . .
      }
      Domain query operation rules
      Identity
    • 7. Convention vs. configuration
      Query operation explicit marking : QueryAttribute
      Signature match : returns IQueryable<T>, IEnumerable<T>, T
      QueryAttribute parameters
      IsComposable
      ResultLimit
      HasSideEffects
               [Query]
      public Iqueryable<Customers>  GetCustomersByState (BillingStatestate)  { . . . }
      public Iqueryable<Customers>  GetCustomersByState (BillingStatestate)  { . . . }
      [Query (IsComposable=false)]
      public SalesPerson GrabTopSalesperson (intyear)  { . . . }
    • 8. Demo
      Defining domain queries
    • 9. Code generation
      l
      Server assemblies
      Silverlight Client
      Silverlight client
      Namespace
      DomainContext types
      Query factory methods
      DomainService types
      [EnableClientAccess]
      Public methods
      Namespace
      Class name
      Public props
      Entity type
      Entity type
      Entity type
      Entity proxy
      Entity proxy
      Entity proxy
      InotifyPropertyChanged
      Validation
      Metadata
      Custom Attribute
      Metadata class
      Custom Attribute
    • 10. The typed DomainContext class
      Constructors
      Query proxy methods
      Entity proxy properties
      Entity container factory
    • 11. Demo
      Examining generated classes
    • 12. Asynchronous loading
      ChinookDomainContext ctx = newChinookDomainContext();
      varquery = ctx.GetInvoicesByCustomer (1) ;
      LoadOperation<Invoice>op = ctx.Load(query);
      EntityQuery
      <Invoice>
      CustomerGrid.ItemsSource = op.Entities
      LoadOperation
      <Invoice>
      IEnumerable<Invoice>
    • 13. The Load method
      Load method overloads
      Load(EntityQuery<TEntity>)
      Load(EntityQuery<TEntity>, LoadBehavior, Callback, UserState)
      Load(EntityQuery<TEntity>, Callback, UserState)
      Load(EntityQuery<TEntity>, ThrowOnError)
      Load(EntityQuery<TEntity>, LoadBehavior, ThrowOnError)
      LoadOperation<Invoice> op = ctx.Load<Invoice>(query,
      lo => { /* Check for errors, bind to UI, do work */},
      null);
      ctx.Load<Invoice>(query).Completed += newEventHandler(LoadComplete);
      voidLoadComplete(object sender, EventArgs e)
      {/* Check for errors, bind to UI, do work */ }
    • 14. LoadOperation
      Load Operation:
      OperationBase:
      • INotifyPropertyChanged
      • 18. IsComplete, Completed, event
      • 19. Cancel(), CanCancel, IsCanceled
      • 20. Error, HasError
    • Demo
      Loading data
    • 21. Caching query results
      EntitySet
      property
      Load()
      Entity
      Container
      Domain
      Context
      Query
      Results
      Send
      query
      Query
      Results
      Entity
      Set
      Entity
      Set
      Entity
      Set
      Domain
      Service
      INotifyProperty
      Changed
      Change tracking
      Validation
      Data binding
      Updating
      Entity
      Entity
      Entity
    • 22. Demo
      Binding to cached data
    • 23. Load options
      Changes (local)
      Changes (remote)
      Load()
      LoadBehavior:
      -KeepCurrent
      -MergeIntoCurrent
      -RefreshCurrent
      Entity Container
      Entity
      Set
      ?
    • 24. Demo
      Using LoadBehavior
    • 25. Client side data shaping
      EntityQueryable
      (extension)
      QueryName
      Parameters
      Query
      IsComposable
      EntityQuery<T>
      e.g. GetProductsQuery()
      LINQ operators
      (Where, Skip,Take, OrderBy)
      LINQ operators
      (Where, Skip,Take, OrderBy)
      Client
      Server
      Server query +
      Client-side query
      combined
      Domain
      Service
    • 26. Demo
      Filtering data
    • 27. Retrieving object hierarchies
      Server
      Client
      Server-side
      Entity type
      Domain Service
      IQuerable<foo> GetFoos()
      Entity
      Container
      [IncludeAttribute]
      Include
      foo1
      foo1
      [Association]
      new props
      Metadata
      Class
    • 28. Demo
      Returning related data
    • 29. A look behind the scenes
      Domain
      Context
      Domain
      Service
      BeginQuery()
      Domain
      Service
      HostFactory
      Web
      Domain Client
      Domain
      ServiceHost
      Operation Description
      QueryResult<T>
      WCF Channel Factory
      WCF Service
      Contract
      REST/binary endpoint
      WCF Service
      Contract
      Virtual.SVC file
      <%@ServiceHost Service=“XYZService Factory=“System.Web.Ria.
      DomainServiceHostFactory”%>
      WCF Client Channel
      DomainService
      HttpModule
    • 30. Summary
      Integrated Infrastructure
      Signature-based conventions
      Metadata-specific object heirarchies
      Simplified asynchronous calls
      Client-side data caching
      Integrateing data shaping
      REST-based default configuration