Accessing DSS Services through DSSP

Glossary Item Box

DSS User Guide: Accessing DSS Services through a Web Browser

DSSP: DSSP Specification

See Also Microsoft Robotics Developer Studio Send feedback on this topic

Accessing DSS Services through DSSP

Decentralized Software Services (DSS) uses HTTP and Decentralized Software Services Protocol (DSSP) as the foundation for interacting with services. DSSP is a lightweight SOAP-based protocol that provides support for manipulation of structured state and for an event model driven by changes to the structured state. DSSP is used for manipulating and subscribing to services and compliments HTTP in providing a simple, state-driven application model. By enabling services to be accessed both as regular HTTP resources or as DSSP services, it is possible to extend the HTTP model with support for structured data manipulation, event notification, and partner management. Because HTTP and DSSP have inherently different protocol characteristics, DSSP is complementary to HTTP and not intended as a replacement.

Responding to Create Requests

The create operation is used to create a new instance of a service and is normally only supported by the constructor service. See DSS System Services.  While it is possible to write additional constructor services, most scenarios are typically better covered by writing services on top of the existing constructor service. The manifest loader service is an example of a service that uses the constructor service to create new instances of services listed in a manifest. See DSS System Services and DSS Service Manifests.

As part of the service creation process, the programmer can provide the service with information about its partners including the initial state partner which can be used to initialize the service with a known state. See Service Tutorials Overview for examples.

Responding to Drop Requests

The drop operation is used to shut down a service. When a service accepts a dropP request it can no longer be reached by other services. If a service does not have any particular shutdown logic it can use the DefaultDropHandler which removes the service from the directory service and shuts down the service instance. This handler is automatically registered so a service implementation does not need to provide anything explicit in order to enable the default behavior.

Services that do have special shutdown logic can provide their own drop handler which augments the basic shutdown logic as follows:

[ServiceHandler(ServiceHandlerBehavior.Teardown)]
public virtual IEnumerator<ITask> DropHandler(DsspDefaultDrop drop)
{
    // Perform service specific shutdown logic including shutting
    // down dependent service instances
    
    // Perform default shutdown logic
    base.DefaultDropHandler(drop);

    // Shutdown complete
    yield break;
}

This handler will get picked up automatically and registered when calling DsspServiceBase.Start().

Bb466253.hs-note(en-us,MSDN.10).gif Service instances may share a Concurrency and Coordination Runtime (CCR) dispatcher so issuing a drop on a service does not guarantee that Common Language Runtime threads are removed. This means that if your service started some CCR logic that periodically does something, that will continue after the drop operation has completed.

Responding to Lookup Requests

The lookup operation provides information about a service including what contract, or contracts, the service is implementing and what partners this particular service instance has. All services must support the lookup operation so it is always present on the service operations port. 

The DSS runtime already has all relevant information about a service instance to be able to respond to a lookup request automatically so the DefaultLookuphandler is typically sufficient to handle lookup requests. While the default behavior can be overridden by explicitly registering a lookup handler, this is not recommended under normal circumstances.

Responding to State Retrieval Requests

DSSP defines two operations for service state retrieval: get and query. While the two operations are similar, the query request contains a service-specific, structured query against the service state whereas a get request is an service-independent request for the entire service state.

Because the get request is a request for the entire state and the request type is pre-defined by DSSP, there can be at most one get handler. However, there may well be multiple queries against the state of a service that may warrant multiple query handlers supporting different query types.

Bb466253.hs-tip(en-us,MSDN.10).gif As both get and query requests are defined by DSSP as not having any side-effects. Get and query handlers should be marked as ServiceHandlerBehavior.Concurrent using the ServiceHandler attribute so that the infrastructure knows that these handlers can run concurrently.

Responding to Get Requests

The DSSP get operation has a pre-defined get request type but a service-specific get response containing a representation of the state of the service. A very common get handler looks like this:

[ServiceHandler(ServiceHandlerBehavior.Concurrent)]
public virtual IEnumerator<ITask> GetHandler(Get get)
{
    get.ResponsePort.Post(_state);
    yield break;
}

Responding to Query Requests

A query operation is a query over the service state meaning that the state included in a query response is a subset of the entire state of a service available in a get response. A service can have any number of query handlers supporting different query request types. A typical query handler looks like the following:

[ServiceHandler(ServiceHandlerBehavior.Concurrent)]
public virtual IEnumerator<ITask> QueryHandler(Query query)
{
    // Create filtered view of service state using the parameters provided in the query
    
    query.ResponsePort.Post(_filteredState);
    yield break;
}

DSSP does not limit the way in which queries can be expressed leaving it up to the service to determine the most appropriate way for querying its state. Common examples include name-value-based queries, or by the service defining specific query types that generate views over the service state.

Responding to Subscribe Requests

The subscribe operation allows other services to subscribe to state changes. See section Responding to State Changes Requests. Subscriptions are widely used in DSS services to enable subscribers to track state changes. Service implementing support for subscriptions can use the subscription manager service for managing their subscriptions rather than doing it themselves. See DSS System Services. The following is an example of a typical subscribe handler using a subscription manager service previously set up as a partner service. For a full scenario demonstrating the subscribe operation, see Service Tutorial 4 (C#) - Supporting Subscriptions.

[ServiceHandler(ServiceHandlerBehavior.Concurrent)]
public IEnumerator<iTask> SubscribeHandler(Subscribe subscribe)
{
    yield return Arbiter.Choice(SubscribeHelper(_submgrPort, subscribe.Body, subscribe.ResponsePort),
        delegate(SuccessResult success)
        {
            // Send notification (or notifications) using <strong>DsspServiceBase.SendNotification()</strong>
            // allowing the newly subscribed party to catch up to the current state of this service.            
            // In this example we use Replace to catch up the newly subscribed party.
            base.SendNotification<Replace>(_submgrPort, subscribe.Body.Subscriber, _state);
        },
        delegate(Exception failure)
        {
            LogError(null, "Unable to subscribe", failure);
        }
    );
    yield break;
}

Responding to State Changes Requests

The following cover DSSP operations that change the state of a service. State changes can result in the service state being inserted, updated, or deleted and causes event notifications to be generated as a result.

Bb466253.hs-tip(en-us,MSDN.10).gif As state changes by the very nature have side-effects. The operations described in this section should be marked as ServiceHandlerBehavior.Exclusive using the ServiceHandler attribute so that the infrastructure knows that these handlers must run exclusive to all other handlers registered as part of the same interleave context. See CCR Coordination Primitives.

Responding to Insert Requests

The insert operation is used to add new state to the service. Below is a typical insert operation handler that performs the following sequence of instructions:

  • Checks whether the data is valid or generates a OperationFailed fault message.
  • Checks the data for any uniqueness constraints, and if not met then generates a DefaultInsertResponse fault message.
  • Adds data included in insert request to service state.
  • Sends an insert event notification using the Subscription Manager service previously created.
  • Sends a DefaultInsertResponseType.Instance message.
[ServiceHandler(ServiceHandlerBehavior.Exclusive)]
public virtual IEnumerator<ITask> InsertHandler(Insert insert)
{
    // Validate insert data
    if ( /* data is not valid */ )
    {
        insert.ResponsePort.Post(
            Fault.FromCodeSubcodeReason(
                FaultCodes.Sender,
                DsspFaultCodes.OperationFailed));
        yield break;
    }    

    // Check uniqueness of data
    if ( /* uniqueness constraint not met */)
    {
        insert.ResponsePort.Post(
            Fault.FromCodeSubcodeReason(
                FaultCodes.Sender,
                DsspFaultCodes.DuplicateEntry));
        yield break;
    }

    // Add data included in insert request to service state

    // Send notification
    base.SendNotification(_submgrPort, insert);

    // Send response
    insert.ResponsePort.Post(DefaultInsertResponseType.Instance);
    yield break;
}

Responding to Update Requests

The update operation is used to update the current service state with new data included in the request. The typical update handler looks very similar to the insert handler above but with a change from insert to update message types. For example:

[ServiceHandler(ServiceHandlerBehavior.Exclusive)]
public virtual IEnumerator<iTask> UpdateHandler(update update)
{
    // Validate update data
    if (false)
    {
        update.ResponsePort.Post(
            Fault.FromCodeSubcodeReason(
                FaultCodes.Sender,
                DsspFaultCodes.OperationFailed));
        yield break;
    }

    // Check existence of data
    if (false)
    {
        update.ResponsePort.Post(
            Fault.FromCodeSubcodeReason(
                FaultCodes.Sender,
                DsspFaultCodes.UnknownEntry));
        yield break;
    }

    // Update service state with data included in update request

    // Send notification
    base.SendNotification(_submgrPort, update);

    // Send response
    update.ResponsePort.Post(DefaultUpdateResponseType.Instance);
    yield break;
}

Responding to Upsert Requests

The upsert operation is used to either update part of the current service state if the data is already present or insert the data included in the request state as a new state. Logically the upsert operation merges the insert and update semantics but with the benefit that the entire state change can be done as a single operation. The typical upsert handler follows the same pattern as indicated for insert and update above.

Responding to Delete Requests

The delete operation is used to delete an existing state. The typical handler for delete operations also follow the same pattern as already laid out above in terms of steps that it goes through.

Responding to Replace Requests

The replace operation can be used to replace the entire service state regardless of the existing service state. An example of a typical replace handler is shown below where the event notification is managed by the subscription manager service.

[ServiceHandler(ServiceHandlerBehavior.Exclusive)]
public IEnumerator<iTask> ReplaceHandler(Replace replace)
{
    // Assign new state received in request to service state
    _state = replace.Body;
    
    // Send REPLACE event notification
    base.SendNotification(_submgrPort, replace);
    
    // Send response to the request
    replace.ResponsePort.Post(DefaultReplaceResponseType.Instance);
    yield break;
}

Responding to Submit Requests

The submit operation can be used to represent semantics that is not possible or practical to represent as state changes. The submit operation is explicitly defined to allow computations that do not change the state of a service and as a result do not generate any event notifications.

See Also 

DSS User Guide: Accessing DSS Services through a Web Browser

DSSP: DSSP Specification

 

 

© 2012 Microsoft Corporation. All Rights Reserved.