Static (Described) Service Brokers

A Static Service Broker is used when the underlying Schema of the provider does not change frequently. Think of a Static Broker as something that describes the Service Objects (as opposed to dynamically discovering Service Objects by querying some underlying schema), because it always knows what the Provider's schema looks like.

Here is an example: suppose you have a class library in your organization that exposes Time Zone information. This TimeZone object has properties like Name, UTCOffset and Abbreviation and methods like Read TimeZone and List TimeZones. We don’t expect that the definition or Schema of the TimeZone object will ever change. Now imagine that we wanted to create a Service Broker that exposes this custom TimeZone object so that we can create SmartObjects for TimeZones. Since the Schema of our TimeZone object never changes, we can create a static Service Broker which describes the TimeZone as a Service Object. Essentially, the description of the Service Object is hard-coded into the Service Broker code.

Sample Project
You can download a sample Static Service Broker project from here: K2Documentation.Samples.Extensions.StaticServiceBroker (on GitHub). The sample project is provided for demonstration purposes only. It is not supported by K2 product support and is not intended to be used as-is in production environments.
In your own organization, you may already have .NET classes with well-defined and static Schemas that expose business objects. The Static Service Broker approach can be used to expose existing .NET classes as Service Objects. All you need to do is to decorate the existing class, properties and methods with Attributes and implement the ServiceAssemblyBase class methods

Implementing Static Service Brokers

Here are the basic steps to implement a Static Service Broker:

1. Create .NET class library (or edit existing class)

Custom Brokers are standard .NET Class libraries (.dlls). You can create a Service Broker in C# or VB.NET. If you have an existing class that you want to expose as a Service Broker, you can edit the code in your class and add the necessary decorations or alternatively reference your assembly in a new class project. If you are referencing a custom assembly, remember that you will need to copy the references assembly to the K2 server along with the Service Broker .dll file.

2. Add Reference to SourceCode.SmartObjects.Services.ServiceSDK.dll

Add a reference to the .NET library SourceCode.SmartObjects.Services.ServiceSDK.dll which is located by default in %PROGRAMFILES%\K2\Bin. This file is available on the K2 server and in a machine where the K2 design tools are installed. When deploying your project you don’t need to copy this assembly to the K2 server, since it already exists on the K2 server.

After adding the reference, import the SourceCode namespaces that you will need to use in your project:

using SourceCode.SmartObjects.Services.ServiceSDK;
using SourceCode.SmartObjects.Services.ServiceSDK.Objects;
using Attributes = SourceCode.SmartObjects.Services.ServiceSDK.Attributes;
using SourceCode.SmartObjects.Services.ServiceSDK.Types;

3. Inherit the base class: SourceCode.SmartObjects.Services.ServiceSDK.ServiceAssemblyBase

Next inherit the base class SourceCode.SmartObjects.Services.ServiceSDK.ServiceAssemblyBase in your project. We recommend creating a separate .cs class for the base class to separate the Broker code implementation from the class you will expose as a ServiceObject.

class CustomStaticServiceBrokerClass : ServiceAssemblyBase

When you inherit this base class in your class, you will override two methods for your service broker: GetConfigurationand DescribeSchema.

Importing required namespaces and inheriting from the base class:

4. Define Configuration values in the GetConfiguration method

The next step is to add any configuration settings to your broker, if you need to store configuration settings per Service Instance. You do this by overriding and implementing the base class' GetConfigSection() method. For each configuration setting in your Service Broker, add it to the Service Configuration items like this:

public override string GetConfigSection() {
 //In this example, we are adding two configuration values, one required and one optional, and one with a default value
 this.Service.ServiceConfiguration.Add("RequiredConfigurationValue", true, "RequiredValueDefaultValue");
 this.Service.ServiceConfiguration.Add("OptionalConfigurationValue", false, string.Empty);
 //return the configuration as XML
 return base.GetConfigSection();
}

Implementing configuration settings:

At runtime, you can expose the Service Instance's configuration settings by declaring a property of type ServiceConfiguration in your class. K2 will automatically pass the service instance configuration settings into this property at runtime. You can read the configuration values like this:

string configSettingValue = this.Service.ServiceConfiguration["ConfigSettingName"].ToString();

Obtaining Service Instance configuration settings at runtime:

5. Describe your objects in Service Object terms

Next, you need to define the Service Objects in your Broker. Since this is a Static or Described schema broker, you will achieve this by adding Attribute descriptors to the Classes, Properties and Methods in your class file.

Class = Service Object

If necessary, create a public .NET Class for each Service Object in your new Broker. Decorate the classes that you want to expose as Service Objects with the [Attributes.ServiceObject] attribute.

[Attributes.ServiceObject("ServiceObjectSystemName", "Service Object Display Name", "Service Object Description")]
public class CustomClass {}

Decorating a class as a Service Object:

Make sure to implement a public constructor for your class, otherwise K2 will not be able to instantiate your class and you may get null reference exceptions at runtime when executing the SmartObject method.
Class Properties = Service Object Properties

If necessary, create public properties for each property of the Service Object. Decorate the public properties that you want to define as Service Object properties with the [Attributes.Property] Attribute. As part of the attribute, you will need to specify what Service Object Type the Property will be, .e.g Text, YesNo, DateTime and so on.

//private member
private string _property1;

//public property, decorated with attributes to expose it as a Service OBject Property
[Attributes.Property("Property1", SoType.Text, "Property 1 (Display Name)", "Property 1 (Description)")]
public string Property1 {
 get {
  return _property1;
 }
 set {
  _property1 = value;
 }
}

Decorating Properties as Service Object Properties:

Class Methods = Service Object Methods

Create public methods for your Service Objects that will accept collections of input Properties, return Properties and the Service Object. Decorate the methods you want to expose with the [Attributes.Method] Attribute.

[Attributes.Method("MethodSystemName", MethodType.List, "Method Display Name", "Method Description",
 new string[] {
  "list of Required input properties for the method"
 },
 new string[] {
  "list of the Input Properties the method accepts"
 },
 new string[] {
  "list of properties that the method returns"
 })]
public void CustomMethod(Property[] inputs, Property[] returns, ServiceObject serviceObject) {
 //do work to execute the method and create custom class objects
}

Decorating methods as Service Object Methods:

The method is where you will write the code that interacts with the provider and populates the Service Object properties. Remember to return an instance or collection of the Service Object class at the end of the method.

To define static parameters for the method, decorate it similar to the following example, which adds the File parameter.

Example of static parameter for a static service object method:

To retrieve any input properties or parameters passed in by the user, you can just query the Property of the class. K2 will automatically populate the class properties with the values entered by the user when they execute the method.

Reading the input properties and parameters passed in by the user:

6. Implement the DescribeSchema() method

Next you will need to override and implement the DescribeSchema() method in the ServiceAssemblyBase base class. This method is called when you register or refresh a Service Instance, and it is used to list the available Service Objects for a Service Broker. Note that you will manually register or refresh a Service Instance to call this method. K2 does not "poll" or otherwise automatically update the list of Service Objects in a Service Broker.

Since this is a described schema Broker, all you need to do in the DescribeSchema() method is add each of your classes that you have decorated with the [Attributes.ServiceObject] attribute in Step 5

public override void DescribeSchema() {
 //TODO: Since this is a static broker, you would add static service objects using attribute decoration.
 //The recommended approach is to create separate classes for each of your static service objects
 //in the sample implementation, we iterate over each of the classes in the assembly and if they are decorated with the
 //ServiceObjectAttribute, we add them as service objects.
 //if you prefer, you can manually add Service Objects like this instead:
 //serviceBroker.Service.ServiceObjects.Add(new ServiceObject(typeof(StaticServiceObject1)));

 Type[] types = this.GetType().Assembly.GetTypes();

 foreach(Type t in types) {
  if (t.IsClass) {
   if (t.GetCustomAttributes(typeof(SourceCode.SmartObjects.Services.ServiceSDK.Attributes.ServiceObjectAttribute), false).Length > 0) {
    this.Service.ServiceObjects.Create(new SourceCode.SmartObjects.Services.ServiceSDK.Objects.ServiceObject(t));
   }
  }
 }
 return base.DescribeSchema();
}

Implementing the DescribeSchema() method:

7. No need to implement the Execute() method

For a Described/Attributed Service Object, it is not necessary to implement the Execute() method. K2 will automatically execute the appropriate Service Object method based on the inputs passed in when the Service Object is executed.