Creating a Plugin

This page provides a Visual Studio Template for a demo plugin and a Step by step guide on how to create a basic powerGateServer plugin from scratch

Step by step Guide

1. Create a new Solution in VisualStudio

Choose a new project of type Class Library (.net Framwork):

../../_images/step1_select_project_type.png

Choose the name of the plugin and the target .net framework version (minimum v4.8):

../../_images/step1_select_name_and_target_framework.png

The new project should have the following settings:

  • Output Type: Class Library

  • Target .Net framework: 4.8

  • Platform Target: Any CPU

2. Add required assembly references

Adding references to the assemblies contain the relevant interfaces, base classes and attributes to create WebServices and Entities.
Add a reference to the powerGateServer.SDK.dll assembly from the powerGateServer installation directory:

../../_images/step2_powerGateServerSdkReference.png

and the System.Data.Services.Client.dll framework assembly:

../../_images/step2_systemDataServicesClient_Reference.png

References should look like the following and the Copy Local flag for the powerGateServer.SDK.dll reference should be set to False.

../../_images/step2_references.png
3. Creating a WebService

To get started with the plugin, create a new class derived from powerGateServer.SDK.WebService.
Add the WebServiceData attribute and specify the Bundle and Service name. (Bundle names should start with “PGS/”)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
using powerGateServer.SDK;

namespace powerGateDemoPlugin {

	[WebServiceData("PGS/coolOrange", "Demo")]
	public class DemoErpSystem : WebService
	{
		public DemoErpSystem()
		{
		
		}
	}
}

The WebService can later be accessed via this Url: http://localhost:8080/PGS/coolOrange/Demo/$metadata.

4. Creating an Entity

Before the ServiceMethod can be implemented, an Entity class is required for the ServiceMethod to work with.
Create a new class with the desired properties having public getter and setter methods. The class needs to be marked with a DataServiceEntity attribute to be recognized as an Entity.
Additionally it needs to be marked with a DataServiceKey attributes which defines one or multiple Properties to be used as Keys to uniquely identify the entity(Number is used in the following example). The System.Data.Services.Client reference is required for the attributes.

Supported Types

All primitive types are supported. System.Object is NOT supported.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
using System.Data.Services.Common;

namespace powerGateDemoPlugin
{
    [DataServiceKey("Number")]
    [DataServiceEntity]
    public class Item
    {
        public string Number { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string UnitOfMeasure { get; set; }
        public decimal Weight { get; set; }
        public string Material { get; set; }
        public decimal Price { get; set; }
        public int Stock { get; set; }
        public bool MakeBuy { get; set; }
        public string Supplier { get; set; }
    }
}

Media Link Entry

To make streamable entities (MLE) see here.

5. Create a ServiceMethod

Create a new class derived from ServiceMethod<> and specify the entity type as the generic parameter (Item in the following example).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System.Collections.Generic;
using powerGateServer.SDK;

namespace powerGateDemoPlugin
{
    public class Items : ServiceMethod<Item>
    {
        public override IEnumerable<Item> Query(IExpression<Item> expression)
        {
            throw new System.NotImplementedException();
        }

        public override void Update(Item entity)
        {
            throw new System.NotImplementedException();
        }

        public override void Create(Item entity)
        {
           throw new System.NotImplementedException();
        }

        public override void Delete(Item entity)
        {
            throw new System.NotImplementedException();
        }
    }
}

The ServiceMethod can later be accessed via: http://localhost:8080/PGS/coolOrange/Demo/Items.

Media Link Entry

To extend the ServiceMethod for a streamable entity (MLE) see here.

6. Register a ServiceMethod

The ServiceMethod has to be registered in the WebService.
This is done by passing it to the AddMethod method in the WebService’s constructor.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
using powerGateServer.SDK;

namespace powerGateDemoPlugin
{
	[WebServiceData("PGS/coolOrange", "Demo")]
	public class DemoErpSystem : WebService
	{
		public DemoErpSystem()
		{
			AddMethod(new Items());
		}
	}
}
7. Provide ERP data

For most plugins it makes sense to create a class to provide centralized access to the ERP system API or data source the plugin consumes.
To make sure only one instance of this class exists a singleton pattern is used in this example. (constructor is declared private and a static GetInstance() method is provided)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
namespace powerGateDemoPlugin
{
	public class ErpSystem
	{
		private static ErpSystem _instance;
		
		private ErpSystem()
		{
		}
		
		public static ErpSystem GetInstance()
		{
			return _instance == null ? _instance = new ErpSystem() : _instance;
		}
	}
}

For this demo plugin the data will only be stored temporarily in a List (data is lost when powerGateServer is restarted!).
To keep the implementation in the ServiceMethod simple the same CRUD operations are provided by this class:

  • GetItems() to retrieve all items

  • AddItem(Item) to create a new item and make sure no duplicates exist

  • DeleteItem(Item) to remove an item

  • UpdateItem(Item) to replace an item with a different version

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;
using System.Collections.Generic;
using System.Linq;

namespace powerGateDemoPlugin
{
	public class ErpSystem
	{
		private static ErpSystem _instance;
		
		private readonly List<Item> _items = new List<Item>();
		
		private ErpSystem()
		{
		}
		
		public static ErpSystem GetInstance()
		{
			return _instance == null ? _instance = new ErpSystem() : _instance;
		}
		
		public IEnumerable<Item> GetItems()
		{
			return _items;
		}
		
		public void AddItem(Item item)
		{
			if (_items.Any(i => i.Number == item.Number))
				throw new Exception("Item already exists");
			_items.Add(item);
		}
		
		public void DeleteItem(Item item)
		{
			var existingItem = _items.FirstOrDefault(i => i.Number == item.Number);
			if (existingItem != null) 
				_items.Remove(existingItem);
		}
		
		public void UpdateItem(Item item)
		{
			DeleteItem(item);
			AddItem(item);
		}
	}
}
8. Implement Service Method

Implementations of the CRUD methods in the ServiceMethod can now use the ErpSystem class to access and modify data.
For plugins working with actual ERP system it might be necessary to evaluate the expression in the Query method as it might not be possible or feasible to return all entities.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using powerGateServer.SDK;
using System.Collections.Generic;

namespace powerGateDemoPlugin
{
    public class Items : ServiceMethod<Item>
    {
        readonly ErpSystem _erpSystem = ErpSystem.GetInstance();
        public override IEnumerable<Item> Query(IExpression<Item> expression)
        {
            return _erpSystem.GetItems();
        }

        public override void Update(Item entity)
        {
            _erpSystem.UpdateItem(entity);
        }

        public override void Create(Item entity)
        {
           _erpSystem.AddItem(entity);
        }

        public override void Delete(Item entity)
        {
            _erpSystem.DeleteItem(entity);
        }
    }
}

Exception handling
The CRUD methods in the SerivceMethod can throw Exceptions.
For example:

 9
10
11
12
public override IEnumerable<Item> Query(IExpression<Item> expression)
{
	throw new InvalidDataException("Something is wrong");
}

The thrown exception is automatically converted into a valid error response of type Internal Server Error with status code 500.
The above exception would show up in a browser like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
  "error": {
    "code": "",
    "message": {
      "lang": "de-DE",
      "value": "Internal Server Error! Something is wrong"
    },
    "innererror": {
      "message": "Something is wrong",
      "type": "System.IO.InvalidDataException",
      "stacktrace": "   at powerGateDemoPlugin.Items.Query(IExpression`1 expression) in <pathToProject>\\powerGateDemoPlugin\\ItemsService.cs:line 11\r\n   at powerGateServer.Core.WcfFramework.Internal.QueryProviderSdkAdapter`1.Execute(Expression expression)"
    }
  }
}

Response

The error.message contains the message from the thrown Exception.
The error.innererror contains the originally thrown exception including details like the stacktrace and type.

9. Create the plugin folder

Create a new folder with the name of your Plugin in the powerGateServer Plugin Directory (usually C:\ProgramData\coolOrange\powerGateServer\Plugins).
Within that directory create a addin file e.g.: powerGateDemoPlugin.addin . The content of the JSON file contains the path to the assembly.
In this example we set the addin-path to bin\Debug\powerGateDemoPlugin assembly is.

../../_images/step9_create_plugin_folder.png
10. Optional: Set the powerGateServer.exe as Start-Application

Set the powerGateServer.exe as Start-Application in your project.
These may requires administrative privileges. Therefore you should start VisualStudio via “Run as administrator”.

../../_images/step10_start_pgs_when_debugging.png
11. Launch the powerGateServer

Note

Make sure VisualStudio was launched with enough permissions to launch the WebService!

Press F5 to start the powerGateServer with Console.
The WebService should now be up and running with the Plugin!

../../_images/step11_powergateserverconsole.png


Testing that Service loaded
To test that the service was loaded open the metadata url (e.g. http://localhost:8080/PGS/coolOrange/Demo/$metadata) in a web browser.

../../_images/step11_metadata.png

Visual Studio Template

The Visual Studio Template creates a basic Plugin by following the steps above.

Visual Studio Project Template
Download:
C# Template

The template is installed with the product but can also be installed manually by copying the zip file to the VisualStudio Templates directory %userprofile%\documents\Visual Studio <Version>\Templates\ProjectTemplates\coolOrange.

Start VisualStudio and create a new project by using the powerGateServer Plugin project template:

../../_images/template_create_new_project.png

Select project name and target framework version:

../../_images/template_configure_new_project.png

The project will build the plugin to the Plugins directory, with the same name as the project.
The project is configured to launch powerGateServer in a Console when clicking the Start button or pressing F5. (Requires Visual Studio to be started with elevated permissions)

Therefore your own WebService should be up and running on following Url now:
http://localhost:8080/PGS/coolOrange/Demo/$metadata