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
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:
and the System.Data.Services.Client.dll framework assembly:
References should look like the following and the Copy Local flag for the powerGateServer.SDK.dll reference should be set to False.
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 itemsAddItem(Item)
to create a new item and make sure no duplicates existDeleteItem(Item)
to remove an itemUpdateItem(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.
10. Optional: Set the powerGateServer.exe as Start-Application
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!
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.
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:
Select project name and target framework version:
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