Generated code - WCF RIA Services support

LLBLGen Pro Runtime Framework supports the WCF RIA Services shipped by Microsoft for .NET 4.0. To learn more about WCF RIA Services, visit the MSDN website for WCF RIA Services. This section describes in brief how to use the generated code in a WCF RIA Services application and how to create your own WCF RIA Services domain service so it can be used in a Silverlight application. WCF RIA Services works for both Adapter and SelfServicing.

Getting started

First make sure you have the WCF RIA Services required components installed on your system. To do so, visit the MSDN website for WCF RIA Services. After you've generated code using the LLBLGen Pro designer for the LLBLGen Pro runtime framework (be sure to choose '.NET 4.0' as target platform!), you have to create a WCF RIA Service application in Visual Studio.net 2010. To do so, create a 'SilverlightApplication' in VS.NET 2010 and check the checkbox  to enable WCF RIA Services. Instead of adding a ‘Domainservice’ class (which will add entity framework specific code), you will implement the DomainService class manually, by sub-classing the LLBLGenProDomainService(2) class located in the SD.LLBLGen.Pro.RiaSupportClasses assembly found in the folder <LLBLGen Pro Installation Folder>\Frameworks\LLBLGen Pro\RuntimeLibraries\DotNET40 folder. How to create your own DomainService class is described in the next sub-section.

The created web.config  file  in the web project doesn’t contain the setup of a service, this has to be done manually but is fairly straight forward: follow the section ‘Walkthrough: Creating a RIA Services Class Library’, step 8'. This walkthrough is for using the Entity Framework with WCF RIA Services, however the only difference is that for the Entity Framework a default domain service is generated which in general has to be refactored a lot anyway.

Creating the DomainService class

In the 'SilverlightApplication' solution created from the template in VS.NET 2010, there's a project with the .Web suffix. This is the service project. Add a new class to this project and give it a name. This is your service class. Derive this class from either LLBLGenProDomainService (If you're using SelfServicing) or LLBLGenProDomainService2 (if you're using Adapter). The .Web project needs references to:

Make sure you add a namespace import / using statement at the top of the domain class file which specifies SD.LLBLGen.Pro.RiaSupportClasses.

Your domain service class has to have a mandatory attribute: EnableClientAccess(). When this attribute is placed on your domain service class, the WCF RIA Services runtime will generate code for the Silverlight part of your application when you compile your project.

You can now add methods to the domain service class which return entities or accept entities to process them. Use the following naming scheme for your methods so WCF RIA services can pick them up:

Insert
“Insert”, “Add”, “Create” prefixes    
Method signature : void InsertX(T entity), where T is an entity Type, e.g. void InsertCustomer(CustomerEntity entity)

Update
“Update”, “Change”, “Modify” prefixes
Method signature : void UpdateX(T current), where T is an entity Type

Delete
“Delete”, “Remove” prefixes
Method signature : void DeleteX(T entity), where T is an entity Type

Query / Select
Method signature returning a single value, IEnumerable<T> or IQueryable<T> where T is an entity Type, and taking zero or more parameters

You should use LLBLGen Pro entity types here and shouldn't worry about whether Silverlight supports them or not: the conversion is done by WCF RIA Services.

Control your WCF RIA Services code through attributes.

WCF RIA Services is actually a code generator under the hood: it generates intermediate classes from the service exposed methods / types and re-uses them in the silverlight application. This process is controllable through attributes applied to entity definitions, fields and navigators. The SD.LLBLGen.Pro.RiaSupportClasses code picks up those attributes and controls with those attributes which meta-data is supplied to the WCF RIA Services system.

You can add attribute definitions in the designer very easily, at the project level or at the entity / field / navigator level. Please see in the LLBLGen Pro designer documentation the section 'Functionality Reference -> Attribute Definition Macro Definitions' to get started.

The SD.LLBLGen.Pro.RiaSupportClasses already add Key, StringLength etc. attributes so you don’t have to add those to the entity classes. The only attributes you might want to add in the designer are:

note Note:

Fields which don't have the RoundtripOriginal attribute set will show up as 'changed' when you update an entity in your domain service class. This is OK, as the update will result in an update query, however it could be you have logic in place which acts on fields which are marked as 'changed' (their IsChanged flag is set to true): this logic will see the fields as 'changed' even though the original value wasn't changed at all. To avoid this, add RoundtripOriginal to the fields you need the original value for in roundtrips.


SelfServicing and the IncludeAttribute

When using SelfServicing, be aware that any navigator exposed with the IncludeAttribute will be lazy loaded by the WCF RIA Services, through its serialization mechanism. To prevent this, use prefetch paths to fetch the related entities in the query so lazy loading won’t trigger the fetch. If you are familiar with writing templates, you can also switch off lazy loading by generating partial classes for all entities and override OnInitialized and setting the _alreadyFetchednavigatorname member to true. Do this in a <[ForEach RelatedEntity]> loop in your template, similar to the one in the entityInclude.template.

Fields mapped onto a related field

Fields mapped onto related fields are supported, but only read-only. This is because the forf isn’t referring to the related entity, but is seen as a field of the containing entity. Changing it therefore won’t change the related entity.

Inheritance

Entities in an inheritance hierarchy are supported however you have to decorate the root of an inheritance hierarchy with System.Runtime.Serialization.KnownType attributes. It isn’t done automatically because it’s unclear at the point when the info is requested by the code generator of Ria services, which types are exposed by the service.

Only the root of the inheritance hierarchy which is exposed through the created DomainService has to have the KnownType attributes, and only for the subtypes which are to be known on the client. Subtypes don’t need KnownType attributes. You can specify these attributes in the designer at the entity level, in the entity editor, Code Generation Info tab. An example, added as attribute to the Employee entity which is the supertype of Manager:
System.Runtime.Serialization.KnownType($typeof(ManagerEntity))

Implementing your DomainService class

As briefly mentioned above, your DomainService class has to derive from the proper LLBLGenProDomainService class: LLBLGenProDomainService for SelfServicing and LLBLGenProDomainService2 for Adapter. Both have an abstract method which has to be implemented in the domainservice class, and which is used to produce a new instance for the transaction provider for Adapter or Selfservicing. For Adapter this is CreateDataAccessAdapter() which has to produce a new instance for the DataAccessAdapter class. For SelfServicing this is CreateTransaction which has to return a new instance of the Transaction class. Furthermore, you have to add the EnableClientAccess() attribute to your DomainService class.

Implementing CRUD methods

The following sections describe how to implement the crud methods on the service.

Retrieving/selecting data
As described above, the select methods can return an IQueryable<T> or an IEnumerable<T>. You can use any select method you want inside the method, like you’d normally would. If you’re returning an IQueryable<T> however, you have to use Linq. Example:

public IQueryable<CustomerEntity> GetCustomers()
{
        return new LinqMetaData(CreateDataAccessAdapter()).Customer;
}


Inserting Data
Inserting an entity is simply done by calling the base class method InsertEntity(entity). The InsertEntityName method (e.g. InsertCustomer(CustomerEntity toInsert)) isn’t exposed on the client and not callable directly on the client. Example:

public void InsertCustomer(CustomerEntity toInsert)
{
	this.InsertEntity(toInsert);
}


Deleting Data
Deleting an entity is done by calling the base class method DeleteEntity(entity) The DeleteEntityName method (e.g. DeleteCustomer(CustomerEntity toDelete)) isn’t exposed on the client and not callable directly on the client. Example:

public void DeleteCustomer(CustomerEntity toDelete)
{
	this.DeleteEntity(toDelete);
}


Updating Data
Updating an entity is done by calling the base class method UpdateEntity(entity). The UpdateEntityName method (e.g. UpdateCustomer(CustomerEntity toUpdate)) isn’t exposed on the client and not callable directly on the client. Example:

public void UpdateCustomer(CustomerEntity toUpdate)
{
	this.UpdateEntity(toUpdate);
}
Unit Of Work

All tasks are done in a unit of work, which is committed in the PersistChanges method of the DomainService. Every call to the base class’ methods for Create / Update and Delete will add the passed in entity to the active unit of work. The order in which actions happen is the default action order. If you want to change this, you can override the method CreateUnitOfWork in your domain class and create a UnitOfWork(2) instance with a different action order.

Refetches of saved entities

Due to the nature of WCF RIA Services, the entity that’s saved to the RDBMS on the service has to be re-read. This means that the entity has to be re-fetched. This might be unnecessary in your case. LLBLGen Pro is capable of marking a saved entity as ‘fetched’ after a successful save operation. To do so, set the EntityBase.MarkSavedEntitiesAsFetched (SelfServicing) or EntityBase2.MarkSavedEntitiesAsFetched (Adapter) property to true on the server side, in your domain service class. This is a static property so you have to do this once, and no re-fetches are performed after a save when you set this to true. Do this only if you don’t use default constraints in the database.

Conflict resolution

LLBLGen Pro offers the ability to use a custom concurrency mechanism which will result in ORMConcurrencyExceptions if a concurrency problem occurs. The nature of this system is that the error is per failing entity, not per batch. The idea behind the WCF RIA Services approach, one error will make the whole batch fail, is that due to the single error, you can’t continue saving entities beyond this error: everything has to be saved again.

This results in a somewhat different approach to resolving conflicts. When during PersistChanges on the service an ORMConcurrencyException occurs, it’s always propagated to the client  through OnError.


LLBLGen Pro v3.1 documentation. ©2011 Solutions Design