SmartConnector Dev Guide
SmartConnector Dev Guide
Developers Guide
Buildings Labs
SmartConnector Developers Guide
1 Support.................................................................................................................................................. 5
2 Revision History .................................................................................................................................... 5
3 Overview ............................................................................................................................................... 6
3.1 Scope ............................................................................................................................................. 6
3.2 What is SmartConnector? ............................................................................................................. 6
3.2.1 Processor ............................................................................................................................... 7
3.2.2 Processor Configuration........................................................................................................ 7
3.2.3 SmartConnector EWS Servers ............................................................................................... 7
3.2.4 REST Endpoints...................................................................................................................... 8
3.2.5 Endpoint Configuration ......................................................................................................... 8
3.2.6 SmartConnector Portal ......................................................................................................... 8
3.2.7 Worker Manager and Workers ............................................................................................. 8
3.2.8 Extension ............................................................................................................................... 8
3.2.9 Persistent Data Store ............................................................................................................ 8
3.2.10 In-Memory Cache.................................................................................................................. 9
3.2.11 Logging .................................................................................................................................. 9
3.2.12 Licensing ................................................................................................................................ 9
4 Common Data Flows ........................................................................................................................... 10
4.1 Retrieving Data from an EWS Server .......................................................................................... 10
4.1.1 EwsClient ............................................................................................................................. 10
4.1.2 AlarmItemReader ................................................................................................................ 10
4.1.3 ValueItemReader ................................................................................................................ 10
4.1.4 HistoryItemReader .............................................................................................................. 10
4.1.5 SubscriptionReader ............................................................................................................. 10
4.2 Providing Data to an EWS Client ................................................................................................. 10
4.2.1 Asynchronous Data Management ...................................................................................... 11
4.2.2 Synchronous Data Management ........................................................................................ 11
4.2.3 Hybrid Data Management................................................................................................... 11
4.3 Providing Data to a Third Party ................................................................................................... 12
4.3.1 Active Third Party ................................................................................................................ 12
Document : Revision Revision date Page
[Link] 6 12/15/2017 Page 1 of 86
SmartConnector Developers Guide
1 Support
Schneider Electric provides branch and channel partners with planning and implementation assistance
from Buildings Labs. To request help, send an email to Product Support specifying the solution name and
the type of assistance you require. Product Support will relay your request to the appropriate support
team.
Most questions can be answered by accessing the SmartConnector Developer Community page located
at [Link]
developer.
2 Revision History
Date Author Revision Changes Made
10/21/2014 MRS 1 Initial release
02/16/2015 MRS 2 Updated for v1.3
09/30/2015 MRS 3 Updated for v2.0
04/11/2016 MRS 4 Updated for v2.1
12/22/2016 MRS 5 Updated for v2.2
12/15/2017 MRS 6 Updated for v2.3
© 2017 Schneider Electric. All Rights Reserved. Schneider Electric, StruxureWare, SmartStruxure
solution, and EcoStruxure are trademarks owned by Schneider Electric Industries SAS or its affiliated
companies. All other trademarks are the property of their respective owners.
3 Overview
3.1 Scope
This document is intended as a guide for developers using SmartConnector – the Windows service
middleware framework developed by Schneider Electric Buildings Labs. This document assumes the
reader has the requisite knowledge of C# or [Link]® and is moderately comfortable developing class
libraries in Visual Studio® .NET.
This document will not cover the details pertaining to installation, configuration, monitoring, and control
of SmartConnector in a runtime environment. That information can be found in SmartConnector
Installation and Configuration Guide. It is assumed that this document has been reviewed and the
topics contained within are fully understood before continuing.
SmartConnector also provides the infrastructure to provision HTTP endpoints. These endpoints can
either serve data to Schneider Electric systems and third-party clients via Schneider Electric’s
EcoStruxure Web Services (EWS) SOAP protocol or generic RESTful services.
3.2.1 Processor
A Processor is custom code that is designed to accomplish a task. While SmartConnector does include
some sample Processor classes for operational validation and demonstration purposes, Processors are
written by others using SmartConnector’s public libraries. These libraries are packaged into a
SmartConnector Extension.
The scope of a Processor can vary from simple to very complicated. Often, several Processors are
required to function cooperatively to accomplish the necessary tasks for a solution.
third party via a custom EWS Server. As with Processors, custom EWS Servers are written by third
parties and packaged into a SmartConnector Extension.
The Worker Manager is responsible for selecting a Processor Configuration, instantiating its defined
Processor and passing it off to an idle Worker for execution. The Worker Manager also listens to input
to start or stop a Processor or EWS Server as required.
3.2.8 Extension
The term “Extension” is used to define any class assembly which contains code which can run in
SmartConnector. Extensions can contain Processors, EWS Server Hosts, RestProviders, and any
combination of these. Extensions are written by SmartConnector Developers to solve an application
problem.
Values data store that Processors can access directly. This data store can be used to save state between
run iterations of the Processor or to enable collaboration between multiple Processors.
3.2.11 Logging
SmartConnector provides an integrated logging framework. Logging levels of Info, Status, Error, Debug,
and Trace are extensively used throughout the SmartConnector runtime and public libraries. The Logger
is also available to Extension authors for adding their own log information to the common log file
output.
3.2.12 Licensing
SmartConnector’s framework is licensed. Commercial and development licenses can be obtained at
[Link].
Additionally, SmartConnector provides all the hooks necessary for developers to license any Extension
component. These Licenses are managed by the developers themselves also using
[Link].
SmartConnector provides the EwsClient class for this purpose. While EWS is not difficult to consume,
SmartConnector has abstracted out common read oriented tasks into higher order helper classes. These
tasks handle some of the idiosyncrasies in EWS, shielding the user from issues such as paging,
subscribing and renewing, and knowing when to call GetAlarmEvents versus GetUpdatedAlarmEvents.
4.1.1 EwsClient
This class provides all methods and proxy data classes needed to consume any EWS 1.1/1.2 server.
4.1.2 AlarmItemReader
This class provides the functionality to retrieve paged data sets of AlarmItem from any EWS 1.1/1.2
server.
4.1.3 ValueItemReader
This class provides the functionality to retrieve paged data sets of ValueItem from any EWS 1.1/1.2
server.
4.1.4 HistoryItemReader
This class provides the functionality to retrieve paged data sets of HistoryRecord from any EWS 1.1/1.2
server.
4.1.5 SubscriptionReader
This class provides the functionality to receive subscription notifications from any EWS 1.1/1.2 server.
All aspects of subscription management are handled for the consumer.
Where the server data originates depends on which technique works best for your solution. Generally,
there are three data management techniques used to manage EWS data: asynchronous data
management, synchronous data management, or a hybrid approach which uses both asynchronous and
synchronous methods. While each technique comes with its own complexities and pros and cons,
asynchronous data management is the easiest method to implement and the more common technique
used.
Regardless of the provisioning approach, the data served is stored in the SmartConnector database and
managed asynchronously to the inbound client calls. This is typically done with one or more custom
Processors which maintain the data using the aforementioned EwsServerDataAdapter class.
Pros:
Cons:
• Served data may be stale between refresh cycles of the update Processor.
Pros:
Cons:
Hybrid solutions are asynchronous solutions where only those method(s) which need to be performed
synchronously are overridden from the base implementation.
Pros:
Cons:
• Served data may be stale between refresh cycles of the update Processor.
• Harder to configure.
• Incrementally more involved to implement.
If only EWS is not supported, there are still options available to you in SmartConnector.
5 Develop an Extension
Regardless of whether you are writing a custom Processor, EWS Server, or REST Provider, you will need
to create at least one SmartConnector Extension to contain it all. A SmartConnector Extension is a
specially annotated .NET assembly which contains all of the pieces for your SmartConnector solution. If
you prefer, you could create multiple Extensions to organize different solution components separately.
Review the Licensing Your Extension section before deciding if one or multiple Extension assembles are
best for your situation.
The best way to describe how to develop an Extension is to actually develop an Extension. The
remainder of this guide will do just that. We will design an Extension and develop the code to
implement it. After the code is developed, we will write some unit tests to verify our Extension works
properly in a development environment. Then we will deploy our Extension to a SmartConnector
runtime, configure it, and verify that it functions as intend. Finally, we will add licensing to our
Extension and update the deployed runtime.
Some of the code steps below may seem obvious for seasoned developers. Have patience as the pace
will quicken as you read on. All screen shots, code syntax, and steps are for C# using Visual Studio 2017.
Other languages and development environments may have slightly different steps.
The following methodology is by no means the only way to develop Extensions, but it is the preferred
methodology used by Buildings Labs.
You can follow along with the sections below or jump right in and review the final source code on
GitHub at [Link] Other samples can also be found
in this repository./
We will pull weather data from the free weather service [Link] You will
need to register as a developer for this site and obtain your own API key.
5.2.1 SetupProcessor
• Create a configurable EWS Server (if one does not exist).
• Verify the EWS Server settings are as intended to prevent against inadvertent change.
• Provision the proper EWS data objects (ContainerItem, ValueItem, HistoryItem etc.) which
will contain forecast and current conditions.
• This Processor should run on an occasional schedule.
5.2.2 UpdateProcessor
• Connect to the EWS Server configured by the SetupProcessor.
• Read a predefined City input from the EWS Server, obtain current conditions and forecast from a
weather service, and update the EWS Server with this data.
• Manage historical weather data.
After you are granted access by Buildings Labs, you will receive an email directly from MyGet. Follow
the instructions contained in that email and then continue on with the steps in this section.
1. Open up the [Link] file in the root of your class library project.
2. Enter useful and descriptive information for:
a. AssemblyDescription
b. AssemblyCompany
c. AssemblyCopyright
d. AssemblyVersion
You will notice Visual Studio complaining (red syntax highlighting) about Processor. If you click CTRL + .
to ask Visual Studio for hints, your environment should like something like Figure 7.
Visual Studio doesn’t yet know the Processor base class. We need to add a reference to one of the
SmartConnector NuGet packages.
5. Select “[Link]”.
6. Click “Install”
Visual Studio will install all dependent packages automatically. At this point, go back to your processor
code and click CTRL + . again. Now Visual Studio is telling you to add a using [Link];
directive. Select that option.
Alas, Visual Studio is now complaining about the SetupProcessor class. Click CTRL + . one more time
and choose “Implement Abstract Class”. Your code should look like Figure 9.
[Link] IsLicensed
By default, SmartConnector assumes that you will be licensing all component parts of your Extension.
This is optional. If you do NOT wish to license your Processor, you do need to add an override for the
IsLicensed property as shown in Figure 10. For now, we will override this in the SetupProcessor.
We’ll come back to this later when we add licensing.
The first way to do this is to provide a default name and description for Processor Configurations based
on this Processor. By annotating our SetupProcessor with the ConfigurationDefaultsAttribute as
shown in Figure 11 we can provide some context on what the class will do.
Let’s take a look at this in practice. Our SetupProcessor requires the following inputs in order to
perform its intended function:
A quick look at these properties and you will notice that we have some properties that are required,
some that are optional and some that are going to contain sensitive information. Can SmartConnector
handle all of that? Have I mentioned that SmartConnector was designed to be highly flexible and
configurable?
Stubbing out these properties in our SetupProcessor class will result in what is shown in Figure 12.
Something seems to be missing though. How does SmartConnector know what we want to be required
and what we want to be optional? How does SmartConnector know that the UserName and Password
properties contain sensitive information? To do that, let’s talk about validation.
[Link] Validation
Because of the configurable nature of SmartConnector, validation of the state of the Processor – loaded
from a Processor Configuration – is critical. In SmartConnector, Processor validation is based on the
.NET Validator class and does both schematic (attribute based) and semantic (interface based)
validation.
You can also author your own custom validation attribute by subclassing the .NET framework’s
ValidationAttribute class and SmartConnector will honor it. SmartConnector provides some of
its own specialized validation attributes in this manner. These are documented in the Appendix.
Knowing this, we can now update our code to require certain values.
In our SetupProcessor we have a condition which could warrant Semantic Validation. It is as common
security best practice to not allow a user name and a password to be the same. We can implement that
as shown in Figure 14.
Note: if you are not familiar with the yield keyword, a good reference can be found here.
[Link].1 DefaultValueAttribute
The DefaultValueAttribute is part of the .NET framework but it’s not a very well understood
attribute. It is enumerated here because SmartConnector fully supports its use during Processor
Configuration creation if any configurable property is decorated with it. When a Processor
Configuration is first created, the default value will be what you, the developer, set. This is true
regardless of whether the property is a string, int, long, decimal, or even an enumeration. These
properties will still be editable, but at least the initial value is controlled by you the developer.
[Link].2 TooltipAttribute
A Processor author can decorate any configurable property with the TooltipAttribute. The contents of
the “tooltip” will be rendered in the SmartConnector Portal when the user clicks on an icon adjacent to
the property label. This can be useful to provide instructions and guidance to Portal users – or basically
tell users what the property does.
[Link].3 EncryptedStringAttribute
Configuration properties derived from items with this attribute will be encrypted when they are written
to the SmartConnector database and decrypted when they are read from the database.
With this information, we can now able to complete our SetupProcessor properties as shown in Figure
15.
[Link] Execute_Subclass
When we implemented the required abstract Processor (see Figure 9), Visual Studio stubbed out the
main entry point for all custom logic. It is here where our actual “work code” will go. Before we
implement our custom logic, let’s take a moment to review some general topics about this method.
[Link].2 Looping
Loops in your Processor code are expected. Well written Processor code must still be responsive to
external input from users, the operating system, or the SmartConnector runtime. To achieve this, the
base class has a CancellationToken property that is managed by the SmartConnector runtime.
Processor code must monitor this if loop constructs of any type are present – even if they are “short”
loops. This can be done in two different ways:
[Link].2.1 IsCancellationRequested
The protected IsCancellationRequested property can be used to determine if a stop is pending. The
method should then terminate as soon as possible after performing any required actions. This is
typically used as shown in Figure 16.
[Link].2.2 CheckCancellationToken()
A somewhat less graceful albeit faster exit can be achieved by calling the protected
CheckCancellationToken method. This approach should only be used if an uncontrolled and
immediate termination of the method is acceptable as it will cause a TaskCancelledException to be
thrown if a stop request is pending. SmartConnector will call the virtual CleanupBeforeCancellation
method prior to throwing the exception if cleanup of any type is required. This is demonstrated in
Figure 17.
If a Processor has not completed in the time configured in the Portal Settings, the SmartConnector
runtime will terminate the thread it is executing on.
For a variety of reasons, it may not always be practical to design a conforming Processor which runs in a
short amount of time. SmartConnector runtime can accommodate this situation. Developers need only
implement the ILongRunningProcess as shown in Figure 18.
[Link].4 Finishing Up
Before we implement our Execute_Subclass override, let’s review the code we have so far. It should
look similar to Figure 19.
From the requirements, we can stub out the functionality we need with comments as shown in Figure
20.
Much like the God Object is an anti-pattern, the “god method” is an anti-pattern as well – and you won’t
see any code like that in these examples. Adding some methods brings us to Figure 21.
Let’s review.
An instance of the EwsServerDataAdapter is what we will be using to bootstrap and configure the
native SmartConnector EWS Server. There is no public constructor for this class. Rather, you need to
use one of the two static methods to acquire an instance. Figure 22 illustrates how we can use that in a
Lazy Loading design pattern to accomplish what we need.
For “Create New” we will just use the native EWS Server implementation. We’ll come back to this after
we have written our custom EWS Server.
Our connected EwsServerDataAdapter property (DataAdapter) can do this for us as shown on line 66 in
Figure 20. Any required start request will occur asynchronously but that’s OK for our purposes.
• Confirm that the server settings are how we want them to be.
The EwsServerDataAdapter has all of the required methods to do this as shown in Figure 23.
In order to accomplish this step, we are going to need to bootstrap ContainerItem, ValueItem, and
HistoryItem instances in our server. While we can and will use the DataAdapter property to do this,
we will need to set the AlternateId (the EWS Id) for each entity. If we think ahead for a moment, we’ll
realize that we are also going to need this information in both the UpdateProcessor and
CustomSetValuesProcessor. There are several ways to do this, but we won’t be using Magic Numbers
here. Rather we will create a ServerHelper static class for this purpose as shown in Figure 24.
Now we can add some helper methods that will actually create/update our EWS Items as shown in
Figure 25.
And finally, we can add the fields a client can use to “set” the location as shown in Figure 26.
On line 228, you can see that we are making the cityName ValueItem not writeable and if there is no
value in the cityName ValueItem, we are setting its state to Uncertain to indicate to consumers that
our code hasn’t yet acknowledged a change to the city ValueItem.
• Add the folders and data points where we will write the current weather conditions.
Following the similar approach from the prior step, and leveraging those helper methods, we can add
placeholders for the current conditions as seen in Figure 27.
• Add the folders and data points where we’ll write the forecast.
We can wrap up our code by returning any issues. Since we’re not accumulating any, we’ll just return an
empty list as shown on line 81 of Figure 21.
Before me move on, we should make sure we cleanup anything that’s IDisposable. Our
EwsServerDataAdapter backing property does implement IDisposable so let’s make sure we dispose
of that properly.
Since Processor is itself IDisposable we only need to override the Dispose method and the runtime
will handle calling it for us at the proper time. Of course we must still call the base implementation
since it also needs to do it’s cleanup. Figure 29 shows one way to handle this cleanly.
Knowing what we know now about attributes. It shouldn’t take us long to stub out these properties as
shown in Figure 31.
Hopefully, you will look at this code and your own particular warning bells will be going off. Three of the
properties we needed in the SetupProcessor we need again here. Furthermore, we’re going to need a
DataAdapter instance just like we did in the SetupProcessor, and some common validation and
cleanup. Perhaps some refactoring of our code is in order.
Then we can add in our lazy loaded DataAdapter. For this we’ll make a minor tweak. Only the
SetupProcessor should actually create the EWS Server. The UpdateProcessor should just exit
gracefully if the server isn’t available (i.e. it’s null). This should look like Figure 33.
Finally we can move our Dispose from Figure 29 here to handle the proper cleanup required.
We can now refactor SetupProcessor and UpdateProcessor to be a subclass of our new base class and
remove the redundant properties. This should look like Figure 34 and Figure 35 respectively.
5.6.3 Execute_Subclass
From the requirements, we can stub out the functionality we need with comments as we did previously
in the SetupProcessor. The results are shown in Figure 36.
Line 36 of Figure 37 is exactly what we did in the SetupProcessor. If there is no server (e.g.
IsConnected == false) we will just report that via a Prompt and exit.
Lines 39-50 of Figure 37, retrieves the EwsValueItem from our DataAdapter instance. If there is no
EwsValueItem, (e.g. currentCity == null) we will just report that via a Prompt and exit.
• Perform Updates
Line 53-56 of Figure 37 calls DoUpdates. If the method fails to perform the updates for currentCity we
want to make sure our EWS data can report that condition (this was a requirement enumerated above).
Before we get to that, let’s write the actual update code.
Since the UpdateProcessor can be configured to update either the current conditions and/or the
forecast, we can write that method as shown in Figure 38. If updating either the current conditions or
forecast fails, we’ll return that to the calling routine.
Drilling into DoUpdateCurrentConditions we can frame out the work we need to do as shown in Figure
39.
First we need to create the web request we will send to the weather service and then execute that
request as shown in Figure 40.
Assembling and executing the HTTP request are done with the helper methods shown in Figure 41.
CreateWeatherRequest uses the SmartConnector QueryBuilder class to establish the HTTP request,
complete with query parameters, to be made as dictated by the weather service API we are using.
RequestWeatherData executes the HTTP request. But how does it know what type to return? For that,
a code generator such as [Link] was used to generate C# POCO classes from sample
JSON responses from the weather API.
Now that we know can make the HTTP request, we can complete the DoUpdateCurrentConditions
method as shown in Figure 42.
When we don’t receive a successful response from the weather service, we’ll exit
DoUpdateCurrentConditions as shown on line 89 of Figure 42. But what are we doing with lines 98 -
112? The weather service we are using doesn’t provide “real time” values. Rather it updates current
conditions periodically. By only updating our current conditions with newer data we wont inadvertently
create “history” when the change of value occurs.
At this point we are almost done. If you recall, we still have that TODO left to clean up (line 55 of Figure
37). Looking at the ModifyValueItemValue calls in Figure 42 and Figure 43 you will notice that we are
passing a value of [Link] into the state parameter. The
EwsServerDataAdapter will set the state along with the updated value. In contrast, when we fail to
receive a response from the web service, we should update all of those same EwsValueItem instances
with a state of [Link].
Since we are probably going to need this again in our custom EWS Server implementation, let’s update
the ServerHelper class with this logic as shown in Figure 44.
We can wrap up our code by returning any issues. Since we’re not accumulating any, we’ll just return an
empty list as shown on line 56 of Figure 45.
This latency can be addressed by setting the State value of the served EwsValueItem to Uncertain. Of
course we already did this in the ServerHelper. We only need to know where to inject that logic.
You will notice Visual Studio complaining (red syntax highlighting) about EwsServiceHost. If you click
CTRL + . to ask Visual Studio for hints, your environment should like something like Figure 46.
Visual Studio is missing a reference to a subclass of EwsServiceHost that it also requires. Allow it to
“Add reference to ‘[Link]’”.
Alas, Visual Studio is still complaining. Click CTRL + . one more time and choose “Implement Abstract
Class”. Your code should look like Figure 47.
Fortunately, most of the code here is boilerplate code that we can easily replace as shown in Figure 48.
Reviewing the code from Figure 48 we see that we opted out of licensing (IsLicensed returns false)
and threw a NotImplentedException in ValidateCustomLicenseFeatures. That’s fine, but we also
added a call to AddServiceEndpoint in ProvisionEndpoint. AddServiceEndpoint and CreateBinding
are WCF methods used to “wire-up” request handlers. The abstract ProvisionEndpoint method is
simply the SmartConnector frameworks way of reminding you that if you are subclassing
EwsServiceHost, you must do this yourself. The type IDataExchange (on line 38) doesn’t actually have
to be used here, but if you do want to extend the interface of the SOAP service, you will need to pass in
an interface type that is at least a subclass of IDataExchange. Remember this is all boilerplate code. In
virtually every custom EWS Serve extension you write, you can copy lines 19-40 as is.
If you’re paying attention, you may realize we still haven’t wired in our custom code. How do we do
that? For that, let’s revisit the constructor in lines 13-16 of Figure 48. The constructor code generated
was Visual Studio’s best guess implementation when we asked it to ““Implement Abstract Class””.
Unfortunately, it didn’t guess correctly. What is needed is for us to supply the type name for a subclass
of MongooseDataExchange. For now, we can re-write the constructor as shown in Figure 49 and we will
create the CustomDataExchange class shortly.
You will notice Visual Studio complaining (red syntax highlighting) about MongooseDataExhange. That’s
because we need to supply a different NuGet reference. Follow the steps outlined above and add a
reference to “[Link]”.
Alas, Visual Studio is still complaining. Click CTRL + . one more time and “Add reference to
‘[Link]’”. Your code should look like Figure 50 .
At first blush, this may look strange to you. We haven’t overridden anything and there are no abstract
methods or properties to implement. That is correct. If we left our code like this, we will have changed
nothing and have the identical functionality as a native SmartConnector EWS Server. Of course that’s
not why we are doing this.
To inject our custom “Set Values” functionality, we need to add an override as shown in Figure 51.
For our SmartConnector Extension solution, we need to provide custom handling for the “SetValues”
method. So we’ll need to add another class for that.
1. Right click the “EwsServer” folder in the Solution Explorer and select Add-Class.
2. Name the class CustomSetValuesProcessor. By convention, you should end the name with
“Processor”.
3. Click Ok.
4. Make the class public.
5. Subclass MongooseSetValuesProcessor.
6. Override the SetValue method.
Remember, the only thing we want to add to the base functionality (i.e. persisting the change to the
database) is to address the latency that will arise between this call and UpdateProcessor acting on the
new city and updating the current conditions and forecast. For that, we can leverage the ServerHelper
method we added earlier. The result will look like Figure 54.
6 Testing an Extension
Test-driven development is the norm in software development best practices these days. As such, this
approach is strongly recommended when developing SmartConnector Extensions. Choosing which unit
testing framework to use, however, is less clear. Whether you choose Visual Studio testing, NUnit, XUnit
or another framework is largely a matter of developer preference and a discussion topic that is beyond
the scope of this document.
For this guide, we will use the NUnit3 testing framework. As an incentive to using NUnit, Buildings Labs
provides a NuGet package to facilitate test writing with NUnit.
Before we can begin writing tests, we will need to complete some housekeeping steps.
Older versions of NUnit provided a Windows application to run tests and examine results. NUnit3 has
replaced this with a console based test runner. While sufficient for build environments, this approach is
not the suitable for running and debugging tests from within the Visual Studio IDE. For that, a free
Visual Studio add-in will be used. To install this add-in follow the following steps.
In order to accomplish this, we will need a functional SmartConnector runtime. Follow the steps
outlined in the SmartConnector Installation and Configuration Guide to install SmartConnector on your
development computer. You must complete the entirety of section 4 in this guide.
Now that we have completed our prerequisites, we can begin to write unit tests for our SmartConnector
Extensions.
5. Choose “Add to Solution” and chose the solution you just created.
6. Supply a “Name” for your Test Assembly.
7. Click “OK”.
1. Right click the “References” icon for your Test Assembly in the Solution Explorer pane and select
“Add Reference”.
2. In the “Reference Manager dialog”, select “Projects” and “Solution”.
3. Check the “[Link]” item listed.
4. Click “OK”.
1. Right click the “References” icon for your Test Assembly in the Solution Explorer pane and select
“Add Reference”.
2. In the “Reference Manager” dialog, select “Browse” from the options on the left.
1. Right click the project icon for your Test Assembly in the Solution Explorer pane and select “Add-
New Item”.
2. Select “General” from the navigation pane on the left.
3. Select “Application Configuration File” from the options on the right (see Figure 58).
4. Click “Add”.
1. Right click the “References” icon for your Test Assembly in the Solution Explorer pane and select
Manage NuGet Packages.
2. Select the “SmartConnector”.
3. Confirm that “Include prerelease” is not checked.
4. Click Browse. You should see something like Figure 8.
5. Select “[Link]”.
6. Click “Install”
1. Right click the project icon for your Test Assembly in the Solution Explorer pane and select “Add-
Class”.
2. Name the class SetupProcessorFixture. By convention, you should end the name with
“Fixture”.
3. Click “OK”.
4. Make the class public.
5. Subclass SmartConnectorTestFixtureBase and IProcessorTestFixture<SetupProcessor>.
You will notice Visual Studio complaining (red syntax highlighting) about the IProcessorTestFixture
interface. Using CTRL + . tells us we are missing a using directive for [Link] and
[Link]. Adding that we can CTRL + . one more time and “Implement Abstract
Class”. Your code should look like Figure 60.
While Visual Studio is good at stubbing out known interfaces, it doesn’t supply everything we need here.
While convention dictates unit test method names should end in “Test” in order to make these methods
callable from the NUnit test runner, we must add the TestAttribute to them (along with a using
[Link] directive); which will bring us to what is shown in Figure 61.
6.3.1 FixtureOneTimeSetup_Base
NUnit provides attributes which can be used to decorate methods so that they run before and after the
actual tests run. These are useful for performing setup type operations required for any and all tests
included in the fixture. Much of what is needed to run a SmartConnector fixture is already handled for
you in the SmartConnectorTestFixtureBase class. Of course, there is one step that is typically needed
that can’t be performed for you in the base class; initialization of the inversion of control container.
Luckily this code is available as a static method from the Service reference itself. We can easily provide
the required code for FixtureOneTimeSetup_Base as shown in Figure 62.
6.3.2 CreateTestableProcessor
Using the IProcessorTestFixture interface as a basis for writing unit tests for your Processor code
focuses on testing three major aspects: Processor Validation, Execution, and canceling a running
Processor. In all of these scenarios an instantiated Processor instance with valid properties is required.
CreateTestableProcessor provides that instance. To be clear, this method is not a test. Rather it is a
support method which the other Test methods will incorporate.
Line 26 invokes an extension method which returns an instance of SetupProcessor with the default
values we set (see Figure 15). Line 29 adds the additional information our tests will need.
Document : Revision Revision date Page
[Link] 6 12/15/2017 Page 58 of 86
SmartConnector Developers Guide
6.3.3 ValidateTest
The ValidateTest is meant to work interactively with CreateTestableProcessor as shown in Figure
64. First, we call CreateTestableProcessor (line 40) and then run the extension method on lines 43-44
to confirm no issues are initially present. Following that, it is up to the test author to manually produce
validation issues and confirm that they are detected. The depth and breadth of this validation
confirmation is really up to the test writer and what is shown here is merely a guideline.
6.3.4 ExecuteTest
ExecuteTest mimics what the SmartConnector runtime does when a Processor Configuration is
commanded to run. In this case an extension method is available as shown in Figure 65.
6.3.5 CancelTest
CancelTest is similar to ExecuteTest except that shortly being invoked an abort is simulated to ensure
that your Processor exits in a timely fashion. As with ExecuteTest, an extension method is also
available for you to call to perform this test (see Figure 65).
Once displayed you can either “Run” or “Debug” a single test, all tests in your fixture, or all tests in your
project. Debugging will allow you to set breakpoints in your code and step through to find any issues in
either your test code or processor code.
For our sample this means that we only need to copy the [Link] file to
the SmartConnector service folder. If your actual Extension Assembly includes references to third party
DLLs, you need to include them as well.
1. Open up a browser and navigate to [Link] (note if you have changed the default
Portal address use that instead).
2. Authenticate with the proper portal credentials you established when you installed
SmartConnector.
3. Click “Configurations-Processor”.
4. Click “Add New”. You should see something like what is shown in Figure 68. If you do NOT see
“[Link]”, examine the log files to determine what the issue is. You
will need to first ensure “Portal” logging is not filtered out.
5. Select “[Link]”
6. Click “Next”
7. Select “[Link]”
8. Click “Next”
9. Click “Finish”
10. Click the “Details” tab on the “Processor Configuration” page.
11. Verify the settings and make any changes from the default.
12. Save any changes.
13. Click “Validate”. If there are any issues, correct them now by repeating steps 11-12 and making
the appropriate changes.
14. Click the “Control” tab.
By default, a new Processor Configuration will not automatically run when the service starts (“Runs on
Start”) nor will it run on a schedule (“Runs on Schedule”). For our purposes, we only need this Processor
Configuration to execute on start.
We can run our Processor Configuration manually now by clicking the “Start” button. To confirm the
Processor executed successfully perform the following.
10. Click the edit icon for the “Api Key” field.
11. Enter your developer API key for [Link] which you obtained into
the “Api Key” input.
12. Edit “Update Current Conditions” to “True”
13. Edit “Update Forecast” to “True”
14. Click “Save”
15. Click “Validate”
To verify that the processor succeeded, navigate to the EWS Server shown in Figure 69. Explore the
“CurrentConditions” and “Forecast” ValueItem children and you should see values as shown in Figure
71 and Figure 72.
1. Open SoapUI
2. Create a new Project.
3. Right click the project folder and select “Add WSDL”. You should see a dialog like Figure 73.
4. In the “WSDL Location” enter the WSDL “Address” of the EWS Server (e.g.
[Link]
5. Click “OK”. You should see the list of supported methods as shown in Figure 74.
15. Click the green play button in the toolbar of the request.
16. The SOAP response from the server will be displayed at the right.
Using the Portal again, we can navigate back to our EWS Server and see that the “City Name” and “City
Code” values have been updated and that the “State” of each is “Uncertain” as shown in Figure 76.
Finally, we can go to the Processor Configurations page one last time and run the “Weather Update
Processor” again. If we then refresh the CityName and CityCode ValueItem we will see that our
mysterious CityCode value was for Paris. A list of all supported city codes is available here:
[Link]
The realities of deploying to a real production environment are no different than what we have just
demonstrated. We probably would want our UpdateProcessor to run on a schedule; perhaps even
different schedules for “Current Conditions” and “Forecast” since the former is more likely to change
more frequently than the later.
SmartConnector licenses are created and managed entirely by you in your personal Tenant at
[Link]. Once generated, the license itself is immutable. Additionally, once a
license is added to the SmartConnector runtime, the data cannot be altered even though it is stored in
the SmartConnector database. Any edits to either the physical file or the database license fields will
render the license unusable.
Licenses can be created with the following restrictions. Multiple restrictions will behave in a logical
“OR” fashion:
• Time based licensing. License will expire at an absolute date in the future.
• Machine based licensing. Licenses can be generated that allow code to run on only a specific
machine.
• Version based licensing. Licenses can be generated that will only allow specific versions of the
extension assembly to execute.
• Licenses can be generated with custom features that are enforced at run time from the
Extension itself. See Custom Licensing for more details.
You will notice some new fields that were not on the ‘new’ page; specifically the “Public Key” field. This
is one half of a public/private key pair that SmartConnectorServer uses to create license files. We will
use this Public Key shortly to update our Extension Assembly.
In order to create an actual License, we’ll first need to create License Template.
1. From the Extension Detail page shown in Figure 77, click “New License Template”
2. Enter a “Name”. Names are public facing and should be short by descriptive (e.g.
“SmartConnector Weather Extension DEMO”).
3. Enter an optional “Description”. Descriptions are for your internal use and can contain any
information deemed pertinent.
4. Assembly Version is optional. If used, the License Template would be associated with a specific
version of your code. Wild carding is supported here. Enter in “1.0.*” which translates major
version 1, minor version 0, revision any.
5. Click “Save”. The page should look like Figure 78.
1. From the License Template Detail page shown in Figure 78, click “New License”
2. Enter a “Name”. Names represent the actual file name which is generated (e.g.
“[Link]”). Use of “.lic” or no extension has not appreciable
value. We use “.lic” here out of convention.
3. Enter an optional “Description”. Descriptions are for your internal use and can contain any
information deemed pertinent.
4. Click “Save”. The page should look like Figure 79.
5. Click the “Download License” button.
There it is. We have created a license. Unfortunately, by not providing an Expires value or requiring a
Thumbprint, anyone with access to the license file we just downloaded would be able to use it. This is
certainly not a practical option for a real world Extension.
Luckily, [Link] supports more intelligent and scalable workflows then the
“Manual license creation” workflow demonstrated here. Please review the FAQ page on that site.
Additional questions can be brought up in the SmartConnector Developer Forum. Also, review Custom
Licensing on how to add and enforce custom licensing into your Extension Assembly.
1. Open up the [Link] file in the root of your class library project. This is the same file we
annotated earlier.
2. Locate the [assembly: AssemblyCulture("")] line.
3. Add a custom assembly attribute on the next row as shown in Figure 80.
4. Paste in the PublicKey value from the [Link] Extension created
earlier.
1. Open WeatherProcessorBase
2. Locate the IsLicensed override.
3. Comment out or delete the override.
4. Rebuild the solution.
After updating your deployed Extension Assembly and restarting the SmartConnector service we can
verify our licensing requirements.
9 Appendix
9.1 Strong-Named Assemblies
All SmartConnector binaries are Strong-Named Assemblies. All Extension assemblies must be compiled
with the NuGet packages corresponding to the version of the SmartConnector runtime to which it will
be deployed. Failure to do this will result in a runtime exception when the SmartConnector framework
attempts to load an assembly.
This requirement is true regardless of whether or not you strongly name your Extension assembly or
whether or not you incorporate licensing requirements into your Extension assembly.
See the Troubleshooting section in the SmartConnector Installation and Configuration Guide for more
details.
[Link] [Link]
This NuGet package contains low level support classes for other packages.
[Link] [Link]
This NuGet package contains helpers for licensing aspects.
[Link] [Link]
This NuGet package contains EWS data constructs which are commonly used when serving EWS or
consuming a EWS endpoint.
[Link] [Link]
This NuGet package contains all classes and data proxy constructs needed to consume any EWS v1.1 or
EWS 1.2 compliant endpoint.
[Link] [Link]
This NuGet package contains a fully customizable MVC style EWS Server implementation.
[Link] [Link]
This NuGet package contains a fully customizable MVC style RESTful implementation based on an EWS
like data model.
[Link] [Link]
This NuGet package contains low level support classes for the SmartConnector Runtime.
[Link] [Link]
This NuGet package contains data classes for creating SmartConnector Processor Configurations.
Document : Revision Revision date Page
[Link] 6 12/15/2017 Page 76 of 86
SmartConnector Developers Guide
[Link] [Link]
This NuGet package contains all classes and data constructs to interactive natively with EcoStruxure
Buildings Operations servers (AS or ES) using the native CSP protocol. License Required.
[Link] [Link]
This NuGet package contains the SmartConnector standard EWS Server implementation. It can be
customized as needed.
[Link] [Link]
This NuGet package contains classes for managing the internal data for a SmartConnector EWS Server.
[Link] [Link]
This NuGet package contains classes which illustrate how to extend and consume SmartConnector EWS
Servers. This package will be reviewed in detail in a later section.
[Link] [Link]
This NuGet package contains the core SmartConnector framework library. When creating custom
Processors, you will always need to include this NuGet package.
[Link] [Link]
This NuGet package contains classes which illustrate how to extend and consume SmartConnector
Processors. This package will be reviewed in detail in a later section.
[Link] [Link]
This NuGet package contains classes, extension methods and other helpers to aid in writing unit tests for
Processors.
9.3.1 ITraversable
Any class decorated as ITraverseable will allow graph traversal by the ObjectExaminer class for deep
analysis. This is specifically used for Validation and to extract configuration information from a
Processor or REST Endpoint. If a reference type property is added to a Processor which will require
exposure via the configuration engine, you need to decorate those classes with this interface so that
child properties will be exposed.
9.3.2 ILongRunningProcess
A Processer should perform its work as efficiently as possible and terminate. This will allow the finite
number of Workers available to be reused as other Processors need to be executed. It is understood
that sometimes a Processor can’t be written in such a manner. For example, if the processor is
communicating with a third party system by opening a socket and “listening” for traffic it may need to
do so for an indefinite amount of time before exiting.
For cases like this, the interface ILongRunningProcess should be used to assure the SmartConnector
Runtime that the Processor has not become unresponsive or stuck in an infinite loop. Failure to do so
may cause the Worker Manager to terminate the Process because it has become unresponsive.
9.3.3 IEndpoint
The IEndpoint defines the properties needed to connect to any HTTP endpoint (including an EWS
Server). Extension methods exist to instantiate an EwsClient instance based on the credentials of an
implementing class. SmartConnector’s native EWS readers and writers implement this interface.
9.3.4 IStaThreadedProcessor
If a Processor contains references to COM assemblies the Processor may be required to execute in an
STA thread. To instruct the Worker Manager to handle threading using STA threads, the author should
include the sub-class directive for this interface.
9.4.1 CollectionLengthAttribute
Found in the [Link] namespace, this attribute specifies the minimum and/or
maximum number of items that can be in any IEnumerable.
9.4.2 ConfigurationDefaultsAttribute
Found in the [Link] namespace. When attributed to a Processor sub-class, a
newly created ProcessConfiguration or EndpointConfiguration will automatically populate the
Name and Description with the supplied values.
9.4.3 ConfigurationIgnoreAttribute
Found in the [Link] namespace. Processor properties with this attribute will be
ignored by SmartConnector for the purposes of configuration and will not be displayed to the user in the
Portal.
9.4.4 EncryptedStringAttribute
Found in the [Link] namespace. Configuration properties derived from items
with this attribute will be encrypted when they are written to the SmartConnector database and
decrypted when they are read from the database.
9.4.5 NotTraverseableAttribute
Found in the [Link] namespace. Processor reference type properties with this
attribute will be considered NOT traversable when it would otherwise be traversable (e.g.
ITraversable or IEnumerable).
9.4.6 RandomStringDefaultValueAttribute
Found in the [Link] namespace. SmartConnector includes a sub-class of the
[Link] which will generate a random string value rather
than one the extension author defines.
9.4.7 TooltipAttribute
Found in the [Link] namespace. A Processor author can decorate any
configurable property with the Tooltip attribute. The contents of the “tip” will be rendered in the
SmartConnector Portal when the user clicks on the icon. This can be useful to provide context based
instructions and guidance to Portal users.
9.5 EwsServerDataAdapter
Managing native SmartConnector EWS Server data and the data relationships is done with the
EwsServerDataAdapter class. This class provides access and full CRUD capabilities to all aspects of native
SmartConnector EWS Servers.
Enforcement of the custom licensing features is the responsibility of the Extension author. This
enforcement is accomplished by overriding the ValidateCustomLicenseFeatures method and
returning the appropriate Prompt instance in the response. An example for the
LicensedNullProcessor is shown in Figure 81 below.
The custom license feature in this example is called “MaxSleep” and represents the maximum allowed
sleep value which the Processor can be configured for. By deferring this validation from design time
(using attribute validation) to runtime, different customers can operate the same Processor under
different constraints.
Access to the in-memory cache is done via a dependency injected instance of the ICache interface. See
Figure 82.
Processor and all EWS Server Processor base classes implement IProcessorValueHelper. See Figure
83.
SmartConnector provides a managed pool of EwsClient connections which works around this issue.
Access to the pool is done via a dependency injected instance of the IManagedEwsClient interface. See
Figure 84 for an example.
Similarly, the CspClient can also be run in a “managed” fashion using the IManagedCspClient
interface. Instantiation of this interface is performed in the same manner as the IEwsClient and is
shown in Figure 85 below.
9.10 Logging
SmartConnector extensively logs all activity. The Portal and SmartConnector Service log every request
and response in addition to all errors. Additionally, this NLog based logging framework is available to all
extension developers so they too can log to the same location.
What gets logged is determined by a combination of the global Logging Level Service Setting and Logging
Filters as described above.
See SmartConnector Installation and Configuration Guide on how to configure SmartConnector logging.
9.11.1 SoapUI
SoapUI is a free and open-source application available at [Link] By creating queries
the can be used to test EWS Server endpoints, SoapUI is helpful for verifying passwords, validating
object IDs, and confirming proper SOAP formatting.
• Create a new project referencing the EWS Server’s WSDL file (insert the actual endpoint exactly
as shown in EWS Server Detail Page.
• [Link]
Select the Create Requests option to generate base queries for each EWS method available for your
EWS Server as shown in Figure 87.
9.11.2 Fiddler
Fiddler can be downloaded for free from [Link] Fiddler is a web
debugging proxy which allows you to view the HTTP communication between any two endpoints.
Additionally, you can “fiddle” with the request and even create your own requests using the Composer.
Error! Reference source not found. shows the communication between SoapUI and the sample
SmartConnector EWS Server establishing connectivity (WSDL request) and then the HTTP Digest
Authentication used to GetWebServiceInformation.
• Windows 7 64 bit.
• Windows 10 64 bit.
• Windows Server 2008 64 bit.
• Windows Server 2012 64 bit.
• Windows Server 2016 64 bit.
• Local DB.
Document : Revision Revision date Page
[Link] 6 12/15/2017 Page 85 of 86
SmartConnector Developers Guide