Domain Services

[WCF RIA Services Version 1 Service Pack 2 is compatible with either .NET framework 4 or .NET Framework 4.5, and with either Silverlight 4 or Silverlight 5.]

Domain services are Windows Communication Foundation (WCF) services that encapsulate the business logic of a WCF RIA Services application. A domain service exposes a set of related operations in the form of a service layer. When you define a domain service, you specify the data operations that are permitted through the domain service.

When designing a domain service, you should think of the domain service as a set of related tasks that you expect users to perform in your application. Typically, such tasks involve a small group of closely-related entities. For example, in an expense reporting application, you might expose entities for expense reports, line items, and details. You might, then, place entities for accounts and payments in a separate domain service.

Domain Services and their Data Sources

The DomainService class is the base class for all classes that serve as domain services. To create a domain service that binds to a custom data object, you create a class that derives directly from DomainService. But if you have a domain service either binds an ADO.NET Entity model or that exposes a LINK to a SQL database, there are special abstract classes the derive from DomainService that you use instead.

  • To create a domain service that binds to an ADO.NET Entity model, you create a class that derives from LinqToEntitiesDomainService<TContext>. RIA Services provides the LinqToEntitiesDomainService<TContext> class.

  • If you want to create a domain services that exposes LINQ to SQL classes in your application, you create a class that derives from LinqToSqlDomainService. This class is provided in the RIA Services Toolkit. If you want to create a domain services that exposes LINQ to SQL classes in your application using this class, you must download the RIA Services Toolkit.

When you use the Add New Domain Service Class dialog box to create a domain service, the type of domain service that is created is based on the entities you expose.

A domain service class must be marked with the EnableClientAccessAttribute attribute to make the service available to the client project. The EnableClientAccessAttribute attribute is automatically applied to a domain service when you select the Enable client access check box in the Add New Domain Service Class dialog box. When the EnableClientAccessAttribute attribute is applied to a domain service, RIA Services generates the corresponding classes for the client project. For example, when you apply the EnableClientAccessAttribute attribute to a domain service named HRService that exposes an entity named Employee, RIA Services generates a domain context named HRContext in the client project and a client-version of the Employee entity.

WCF and Domain Services

As a Windows Communication Foundation (WCF) service, the domain service builds upon WCF concepts. The domain service preserves the following:

  • Standard usage of WCF services

  • Existing WCF programming models constructs, such as operation contracts, operation behaviors, and service behaviors

  • Standard WCF customization capabilities, such as binding configuration, behavior configuration, and management infrastructure

The domain context communicates with the RIA Services domain service by using the WCF ChannelFactory to create a channel and passing to it a service contract that was generated from the domain service.

By default, only the binary endpoint is enabled for domain services. To use the binary endpoint no additional configuration is needed. If you want to use another endpoint (such as OData, JSON, SOAP, or a custom host) you must register an endpoint factory in the Web.config file as shown below:

<configSections>
  <sectionGroup name="system.serviceModel">
    <section name="domainServices" type="System.ServiceModel.DomainServices.Hosting.DomainServicesSection, System.ServiceModel.DomainServices.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" allowDefinition="MachineToApplication" requirePermission="false" />
  </sectionGroup>
</configSections>

<system.serviceModel>
  <domainServices>
    <endpoints>
      <add name="json" type="Microsoft.ServiceModel.DomainService.Hosting.JsonEndpointFactory, Microsoft.ServiceModel.DomainService.Hosting" />
    </endpoints>
  </domainServices>
<system.serviceModel>

The System.ServiceModel.DomainServices.Hosting namespace contains the endpoints that are supported in RIA Services. The Microsoft.ServiceModel.DomainServices.Hosting namespace contains the endpoints that are supported with the RIA Services Toolkit, such as the JsonEndpointFactory shown in the previous example. To create a custom endpoint, you must create a class that derives from the DomainServiceEndpointFactory class, and override the CreateEndpoints(DomainServiceDescription, DomainServiceHost) method.

Data Operations

You add methods to a domain service that perform the data operation you want to expose. For example, you can add methods that perform the following operations:

  • Query

  • Update

  • Insert

  • Delete

You can also add more complicated operations such as:

  • Invoke: to implement operations that need to be executed without tracking or deferred execution. This method is used only with non-entity data, and used only when query, update, insert, or delete operations cannot be used instead.

  • Named Update: to implement custom operations that do not fall into simple modification operations.

When you expose a domain service, an EntitySet object is generated in the domain context with properties that indicate which operations (insert, update, or delete) are permitted from the client. You execute data modifications by modifying the entity collection and then calling the SubmitChanges method.

In almost all scenarios, you should use query operations instead of invoke operations to load data. Query methods return either a single Entity object, an IQueryable<Entity> object, or an IEnumerable<Entity> object. Query methods are an integral part of the data pattern supported by DomainService on the middle-tier and by DomainContext on the client. The RIA Services framework generates entities in the client project for only those entities that are returned from query methods in a DomainService.

Invoke operations provide an out-of-band mechanism for returning non-entity data and executing operations with side-effects. For more information about side-effects, see the HasSideEffects property. Invoke operations are usually not appropriate for query methods. Even when an invoke operation returns an entity, the entity is generated for the client project only if it is returned by a query method.

Conventions

When you add methods to perform these operations, the method must match the expected signature for that operation. In addition to matching the signature, the method must include a name prefix that matches the naming convention for that data operation. If the name of the method does not start with the expected prefix, you must apply the corresponding attribute for that operation. The attribute is optional if the name of the operation matches the naming convention. Using the naming convention provides a more consistent experience for developers.

You cannot overload methods that are domain operations. You must specify a unique name for each method that can be called from the client project. All methods that represent domain service operations must be public. The methods must use serializable types for parameters and return types.

You can prevent a method from being exposed by adding the IgnoreAttribute attribute to the method.

The data operation signatures are provided in the following tables.

Query

A query method must return a single instance of an entity, or an IEnumerable<T> or IQueryable<T> where T is a valid entity type. Because overloaded methods are not allowed, you must provide a unique name for each method that takes different input parameters (for example GetEmployees() and GetEmployeesByLastName(string lastname).

The following table lists the expected signature values for a query operation.

Return value

IEnumerable<T>, IQueryable<T>, or entity

Parameters

Any number of parameters

Name Prefix

Any name

Attribute

[Query] (C#)

-or-

<Query()> (Visual Basic)

For more information, see QueryAttribute.

Example

public IQueryable<Product> GetProducts() (C#)

-or-

Public Function GetProducts() As IQueryable(Of Product) (Visual Basic)

Update

The following table lists the expected signature values for an update operation.

Return value

None

Parameters

Entity

Name Prefix

Update, Change, or Modify

Attribute

[Update] (C#)

-or-

<Update()> (Visual Basic)

For more information, see UpdateAttribute.

Example

public void UpdateProduct(Product product) (C#)

-or-

Public Sub UpdateProduct(ByVal product As Product) (Visual Basic)

Insert

The following table lists the expected signature values for an insert operation.

Return value

None

Parameters

Entity

Name Prefix

Insert, Add, or Create

Attribute

[Insert] (C#)

-or-

<Insert()> (Visual Basic)

For more information, see InsertAttribute.

Example

public void InsertProduct(Product product) (C#)

-or-

Public Sub InsertProduct(ByVal product As Product) (Visual Basic)

Delete

The following table lists the expected signature values for a delete operation.

Return value

None

Parameters

Entity

Name Prefix

Delete or Remove

Attribute

[Delete] (C#)

-or-

<Delete()> (Visual Basic)

For more information, see DeleteAttribute.

Example

public void DeleteProduct(Product product) (C#)

-or-

Public Sub DeleteProduct(ByVal product As Product) (Visual Basic)

Invoke

Invoke operations provide an out-of-band mechanism for returning non-entity data and executing operations with side-effects. For more information about side-effects, see the HasSideEffects property. Invoke operations are usually not appropriate for query methods.

The following table lists the expected signature values for an invoke operation.

Return value

Any

Parameters

Any number of parameters

Name Prefix

Any

Attribute

[Invoke] (C#)

-or-

<Invoke> (Visual Basic)

For more information, see InvokeAttribute.

Example

[Invoke]

public decimal GetCompetitorsPrice(Product product) (C#)

-or-

<Invoke> _

Public GetCompetitorsPrice(ByVal product As Product) As Decimal (Visual Basic)

Named Update

The following table lists the expected signature values for a named update operation.

Return value

None

Parameters

Entity

Any number of other parameters

Name Prefix

Any name other than one starting with the prefixes for Insert, Update, or Delete

Attribute

[Update(UsingCustomMethod=true] (C#)

-or-

<Update(UsingCustomMethod:=True)> (Visual Basic)

For more information, see UpdateAttribute.

Example

[Update(UsingCustomMethod=true]

public void DiscountProduct(Product product, int percentage) (C#)

-or-

<Update(UsingCustomMethod:=True)> _

Public Sub DiscountProduct(ByVal product As Product, ByVal percentage As Integer) (Visual Basic)

Adding Application Logic to a Domain Service

After defining the exposed data operation, you can add the required application logic to the domain service class. The code generated by the wizard is intended to only help you start writing the application logic. You can add the logic directly into the operation methods or you add it to methods that are called from the operation methods. You can add parameters to existing methods, customize the implementation of methods, or add new methods to provide the functionality required by your application. For more information about implementing business logic, see How to: Add Business Logic to the Domain Service.

When implementing a domain service, you must carefully consider the security risks of exposing data through a service. For more information about security, see Building Secure Applications with WCF RIA Services.

See Also

Concepts

DomainContext and Operations

Building Secure Applications with WCF RIA Services