Client Code Generation
[ This document was written for WCF Services Version 1 Service Pack 2 and might not be up to date Please see Release Notes or Changelog for a list of changes since WCF RIA Services ]
When you link a Silverlight project and a middle-tier project using Open Ria Services, Open Ria Services generates client proxy classes for the client application based on entities and operations you have exposed in the middle tier. Because Open Ria Services generates these classes, you do not need to duplicate any application logic from the middle tier to the presentation tier. Any changes you make to the middle tier code are synchronized with the presentation tier code when you rebuild the client project. When you add a Open Ria Services link to a solution, an explicit build dependency is added to the solution that forces the server project to build before generating code for client project.
The generated code resides in a folder named Generated_Code in the client project. To see this folder, you must select Show All Files in the Solution Explorer window for the client project. You should not directly modify the classes in the Generated_Code folder because they will be overwritten when the client project is rebuilt. However, you can open the generated file to see the code that is available to the client project.
The algorithm that generates client code follows these basic rules:
- 1.Analyze all assemblies either built or referenced by the middle tier project for domain service classes, entity classes, or shared code.
- 2.For each domain service that is annotated with the EnableClientAccessAttribute attribute, generate a class that derives from the DomainContext class.
- 3.For each query method, named update method (an update method with the UsingCustomMethod property set to true), or invoke operation in the domain service class, generate a method in the domain context class.
- 4.For each entity class that is exposed by a domain service, generate an entity proxy class. An entity class is exposed when it is returned by a query method.
- 5.Copy code marked for sharing to the client project.
The following image shows the client code that is generated for a middle tier project.
Client Code Generation
One class that derives from DomainContext is generated for each domain service class according to the following rules:
- 1.The domain context class is generated with same namespace as the domain service.
- 2.The domain context class contains three constructors:
- 1.A default constructor that embeds the URI necessary to communicate with the domain service over http using a WebDomainClient\ class.
- 2.A constructor that permits the client to specify an alternate URI.
- 3.A constructor that permits the client to provide a custom DomainClient implementation (typically used for unit testing or redirection to a custom transport layer).
- 3.For each query method in the domain service class, generate an EntityQuery\ method that can be used in the client project to load entities.
- 4.For each invoke operation, generate a corresponding InvokeOperation method that can be used to invoke that operation asynchronously.
- 5.For each method marked the Update(UsingCustomMethod=true) attribute, generate methods to invoke it and to determine whether it has been invoked.
- 6.Public methods in the domain service that perform inserts, updates, or deletes cause the generated EntityContainer in the domain context to be constructed with an EntitySetOperations flag that indicates which of operations are permitted on the client.
The following rules are applied when generating the entity proxy class:
- 1.The proxy class is generated with the same name and namespace as the entity class in the middle tier.
- 2.The root entity type derives from the Entity class. Derived entity types derive from the corresponding base types exposed by the middle-tier.
- 3.Every public property that contains a supported type and is not marked with the ExcludeAttribute attribute in the entity class is generated in the proxy class, unless that property already exists in the client project. For more information, see the “Avoiding Duplicated Members” section later in this topic. Object is not a supported type.
- 4.Each property setters will contain code that performs validation and notifies clients that the property is changing and has changed.
- 5.Metadata attributes are combined with the entity class in the generated code. No metadata class will exist on the client.
- 6.If possible, custom attributes are propagated to the proxy class. For a description of the conditions that must exist for the custom attribute to exist in the client project, see the following “Custom Attributes” section.
Only one CustomValidationAttribute is propagated to the member if the same type and validation method are specified in more than instance of the CustomValidationAttribute for that member.
Custom attributes are propagated to the proxy class if adding the custom attribute does not cause a compilation error in the client project. For the custom attribute to be propagated, the following conditions must exist:
- 1.The custom attribute type must be available on the client project.
- 2.Any types specified in the custom attribute declaration must be available on the client project.
- 3.The custom attribute type must expose public setters for all of its properties, or expose a constructor that allows for setting properties that do not have public setters.
If a required custom attribute is not propagated to the client, you may need to add an assembly reference in the client project. Add a reference to any assembly that is needed for the custom attribute to compile in the client project. You can also share a custom attribute between the tiers by defining it in a shared file.
When you share code files between the middle tier and the presentation tier, the code is copied without any changes to the client project. You specify a file for sharing by naming it with the pattern *.shared.cs or *.shared.vb. The directory structure from the middle-tier project containing the shared files is replicated under the Generated_Code folder.
When you add a custom type in a shared code file and then return that type from an invoke operation, the generated method in the domain context will not return the custom type. Instead, the method in the domain context will return a type that is part of the framework. For example, when you create a custom type named MyCustomDictionary that implements IDictionary\ and specify that type as the return value for a domain operation, the method generated in the domain context will not return MyCustomDictionary. Instead, it will return a Dictionary\ object.
When generating an entity proxy class, it is possible that the same type and member have already been defined in the client project by using partial types. You may have defined the member in shared code or in code that only exists in the client project. Open Ria Services checks the existing members before generating the proxy class. Any member that is already defined will not be generated in the proxy class.