Share via


Defining Service Operations

[This documentation is for preview only, and is subject to change in later releases. Blank topics are included as placeholders.]

You can define the operations in a service using MfSvcUtil-generated code for the service class.

The Dpws.Device.Device.HostedServices collection is a collection of all the services hosted by the device. Each service is derived from the class Dpws.Device.Services.DpwsHostedService.

Call the Add method in your Main method to simultaneously instantiate your services and add them to the HostedServices collection, as shown here. Any number of hosted services can be added. Services should be added before the device stack is started.

// Add hosted service to the device (in Main).
SampleService sampleService = new SampleService();
Device.HostedServices.Add(sampleService);

Service classes must be derived from the DpwsHostedService base class, which is used to define the service’s transport address, unique identifier, namespace, and type. A service provides one or more operations or actions, which are listed in the service class’s ServiceOperations collection. Operations are methods of the service class, not classes of their own. As shown in the following code, the service’s constructor should add the operations to the service’s ServiceOperations collection in much the same way that services are instantiated and added to the HostedServices collection. The SampleService class also needs methods for the two defined operations, OneWay and TwoWayRequest.

Example

class SampleService : DpwsHostedService
{
    public SampleService()
    {
        // Add ServiceNamespace.
        ServiceNamespace = new WsXmlNamespace("smpl",
            "https://schemas.example.org/SampleService");

        // Set ServiceID and ServiceTypeName.
        ServiceID = 
            "urn:uuid:3cb0d1ba-cc3a-46ce-b416-212ac2419b90";
        ServiceTypeName = "SampleService";

        // Add additional namespaces if needed, for example:
        // Namespaces.Add("someprefix", "https://some/Namespace");

        // Add service operations.
        ServiceOperations.Add(new WsdHostedServiceOperation(
            "smpl",
            "https://schemas.example.org/SampleService", 
            "OneWay"));
        ServiceOperations.Add(new WsdHostedServiceOperation(
            "smpl",
            "https://schemas.example.org/SampleService", 
            "TwoWayRequest"));
    }

    // Method for the first defined operation.
    public byte[] OneWayRequest(WsWsaHeader header, 
                                WsXmlDocument envelope)
    {
        ...
    }

    // Method for the second defined operation.
    public byte[] TwoWayRequest(WsWsaHeader header, 
                                WsXmlDocument envelope)
    {
        ...
    }

Methods used for operations receive two parameters: a Ws.Services.WsaAddressing.WsWsaHeader object containing header information validated by the DPWS stack, and a Ws.Services.Xml.WsXmlDocument object containing the entire SOAP request as an XML tree. The operation implementation must use methods of WsXmlDocument (for example, SelectSingleNode) to extract any values from the content of the message needed to perform the desired operation, and must return a byte array containing the SOAP response message for the request. The response is typically built using the original request header object, information provided by the method implementation, and a System.Ext.XML.XMLWriter object. (The System.Ext.Xml namespace is not a part of the base .NET Micro Framework, but is provided in MFDpwsExtensions.dll.)

The following code shows how parameters can be extracted from the SOAP message, for an operation that adds two integers.

public byte[] TwoWayRequest(WsWsaHeader header, 
                            WsXmlDocument envelope)
{
    WsXmlNode tempNode;
    WsFault fault = new WsFault();

    if ((tempNode = 
         envelope.SelectSingleNode("Body/TwoWayRequest/X", false)) 
        == null)
        return fault.RaiseFault(
                header, 
                WsExceptionFaultType.XmlException,
                "Body/TwoWay X value is missing.");
    int X = Convert.ToInt32(tempNode.Value);

    if ((tempNode =
         envelope.SelectSingleNode("Body/TwoWayRequest/Y", false)) 
        == null)
        return fault.RaiseFault(
                header, 
                WsExceptionFaultType.XmlException,
                "Body/TwoWay Y value is missing.");
    int Y = Convert.ToInt32(tempNode.Value);

    return TwoWayResponse(header, X+Y);
}

The response to a Web Services message is another message. It is often good practice to create a separate method that generates the response and call it from the method that handles the original request, particularly if either procedure is involved, or if similar responses are needed for more than one request. For example, the TwoWayRequest method (defined as part of the SampleService class partially shown above) might call a TwoWayResponse method to generate its response. Since the response method is called by the request handler and never by the DPWS stack, the request method is not limited to passing a header and a SOAP request to the response method, but can pass any values needed to construct the response.

The following code shows an example of how the XML might be built in the TwoWayResponse method that is called from the example TwoWayRequest method.

public byte[] TwoWayResponse(WsWsaHeader header, int sum)
{
    MemoryStream soapStream = new MemoryStream();
    XmlWriter xmlWriter = XmlWriter.Create(soapStream);

    // Write processing instructions and root element
    xmlWriter.WriteProcessingInstruction("xml",
        "version='1.0' encoding='UTF-8'");
    xmlWriter.WriteStartElement("soap", "Envelope",
        "https://www.w3.org/2003/05/soap-envelope");

    // Write namespaces
    xmlWriter.WriteAttributeString("xmlns", "wsdp", null,
        Device.Namespaces.GetNamespace("wsdp"));
    xmlWriter.WriteAttributeString("xmlns", "wsd", null,
        Device.Namespaces.GetNamespace("wsd"));
    xmlWriter.WriteAttributeString("xmlns", "wsa", null,
        Device.Namespaces.GetNamespace("wsa"));
    xmlWriter.WriteAttributeString("xmlns", "sim", null,
        TypeNamespaces.GetNamespace("sim");


    // Write header
    xmlWriter.WriteStartElement("soap", "Header", null);
    xmlWriter.WriteStartElement("wsa", "To", null);
    xmlWriter.WriteString(header.From);
    xmlWriter.WriteEndElement();
    xmlWriter.WriteStartElement("wsa", "Action", null);
    xmlWriter.WriteString(
        "https://schemas.example.org/SimpleService/TwoWayResponse");
    xmlWriter.WriteEndElement();
    xmlWriter.WriteStartElement("wsa", "RelatesTo", null);
    xmlWriter.WriteString(header.MessageID);
    xmlWriter.WriteEndElement(); // End RelatesTo
    xmlWriter.WriteStartElement("wsa", "MessageID", null);
    xmlWriter.WriteString("urn:uuid:" + Device.GetUuid());
    xmlWriter.WriteEndElement(); // End MessageID
    xmlWriter.WriteEndElement(); // End Header

    // write body
    xmlWriter.WriteStartElement("soap", "Body", null);
    xmlWriter.WriteStartElement("sim", "TwoWayResponse", null);
    xmlWriter.WriteStartElement("sim", "Sum", null);
    xmlWriter.WriteString(sum.ToString());
    xmlWriter.WriteEndElement(); // End Sum
    xmlWriter.WriteEndElement(); // End TwoWayResponse
    xmlWriter.WriteEndElement(); // End Body

    xmlWriter.WriteEndElement();

    // Create return buffer and close writer
    xmlWriter.Flush();
    byte[] soapBuffer = soapStream.ToArray();
    xmlWriter.Close();

    return soapBuffer;
}