Synapse.CustomController Commandline Utility
Overview
The Synapse.CustomController commandline utility can be used to create a code file and dll for a custom Contoller interface. The tool provides for a simple "Plan wrapper," but also supports more complex scenarios with custom code.
Synapse.CustomController.exe
Synapse.CustomController.exe takes a YAML template to create a c# code files and compile them to a dll. The tool can be executed to create the code files and dll (both), or each task independently. You may generate a sample .cs and .dll via the 'sample [verbose]' option. Syntax:
C:\Synapse\Controller\Assemblies\Custom>Synapse.CustomController.exe
Synapse Server Custom Controller Utility
Syntax: Synapse.CustomController.exe {path to settings file}|sample [verbose]
sample: Will generate sample settings file.
YAML Template: Top-Level Settings
Parameter | Type/Value | Required | Default Value | Description |
---|---|---|---|---|
OutputAssembly | string |
yes | none; will generate a random name if nothing provided | The filename for the dll to be created. |
ApiControllers | List |
yes* | n/a | If using the utility to create c# files, provide the settings below. |
YAML Template: ApiControllers Settings
Parameter | Type/Value | Required | Default Value | Description |
---|---|---|---|---|
Name | string |
yes | none; will generate a random name if nothing provided | Maps to class name in code; must be unique within the dll. |
AuthorizationTopic | string |
no | none | Provides a designated point in the code to check authorization as specified in Synapse.Server.config.yaml->Authotization section. |
RoutePrefix | string |
yes | none | The URL prefix for all subsequent ApiMethod routes. |
CreateHelloApiMethod | bool |
no | true | Creates a "Hello from [Name]Controller, World!" method for simple connectivity testing. |
CreateWhoAmIApiMethod | bool |
no | true | Creates a method to return the current security context from underlying Execute Controller. |
CreateDalApi | (section) | no | n/a | Optional declaration to generate a DataAccessLayer API for a given class. |
- Class | string | yes | none | The class name for which DAL methods will be created. This class must exist in the referenced code File . |
- File | string | yes | none | The path to the file containing the c# class code as referenced in the Class setting. |
CreateClassFileOnly | bool |
no | false | Prevents the generation of the controller dll as output - only the class files will be created. |
ApiMethods | List |
yes | n/a | The list of methods to be generated. |
Details on generating a DataAccesLayer API
The CreateDalApi->File
setting should reference a file with a complete c# class declaration in it, as shown below. Be sure the class is in the same namespace as the ApiController, which is Synapse.Custom
by default. The CreateDalApi->Class
setting simply reflects the name of the class as specified in the File
, but id declared in the CreateDalApi
settings for clarity.
using System;
using System.Collections.Generic;
//use the same namespace as the ApiContoller!
namespace Synapse.Custom
{
public partial class MyDataClass
{
public int Id { get; set; }
...
}
}
YAML Template: ApiMethods Settings
Parameter | Type/Value | Required | Default Value | Description |
---|---|---|---|---|
HttpMethod | string , HttpVerb |
yes | Get | Get, Put, Post, Delete, etc. See MSDN doc for a complete description. |
AuthorizationTopic | string |
no | none | Provides a designated point in the code to check authorization as specified in Synapse.Server.config.yaml->Authotization section. |
Route | string |
yes | none | The specific URL route to the method. See MSDN Attribute Routing doc for details on options. |
ReturnType | string |
yes | string |
The Type of the return value of the method. |
Name | string |
yes | none; will generate a random name if nothing provided | The name for the method in code. Must be unique within the Controller, or can be a duplicate name with a unique method signature. |
Parms | string |
no | none | The method parameters that map to the Plan. Specify parameters for better discoverability of intended method usage through utilities like swagger. See **note below. |
PlanName | string |
yes | none | The Synapse Plan to be executed by the method. |
ExecuteAsync | bool |
no | false | Specifies whether the underlying Execute Controller instance will run the Plan synchronously or asynchronously. If async, the ReturnType must be long . |
CodeBlob | string |
no | none | A manually coded block to be inserted in the metho between parameter gathering and Plan execution. Useful for parameter validation. |
Options | (section) | no | n/a | If executing a Plan sychronously, set values here to override default settings. |
- Path | string |
no | Actions[0]:Result:ExitData | Specify the path in the Plan.ResultPlan to the section or value to return when the Plan completes. |
- SerializationType | enum |
no | Json |
Options are: Yaml = 0, Xml = 1, Json = 2, Html = 3, Unspecified = 4 . You may provide the string or numeric value. |
- SetContentType | bool |
no | true | Sets ContentType value in HttpResponse Headers as specified in SerializationType. |
- PollingIntervalSeconds | int |
no | 1 | The time, in seconds, the Execute Controller will poll for Plan completion. |
- TimeoutSeconds | int |
no | 120 | The time, in seconds, before the ExecuteController will stop polling and kill the Plan execution. |
- NodeRootUrl | string |
no | none | An alternate Node at which to execute the Plan, other than that which is specified in the Execute Controller's Synapse.Server.config.yaml. |
**Note on how an auto-generated method will capture HttpRequest Parameters:
All auto-generated methods will capture the entire HttpRequest querystring, request body, and any URL template parameters used in attribute-based routing. The querystring and URL template parameters will be inserted into the DynamicParameters collection, keyed off the existing parameter name. The request body will be iserted in with a key of requestBody
. All of this data becomes accessible to the Plan via the Dynamic
section of Action->Config/Parameters
.
Example Usage
Sample Template Input
Assuming the file below is named myCustom.yaml
, usage to create the class file and dll output is as follows:
c:\Synapse\Controller\Assemblies\Custom\Synapse.CustomController.exe myCustom.yaml
myCustom.yaml
template:
OutputAssembly: Synapse.CustomAssm.Sample.dll
ApiControllers:
- Name: Custom
AuthorizationTopic: ApiTopic
RoutePrefix: my/route
CreateHelloApiMethod: true #default true, shown for example only
CreateWhoAmIApiMethod: true #default true, shown for example only
ApiMethods:
- HttpMethod: Get
AuthorizationTopic: MethodTopic
Route: '{interesting}/path'
ReturnType: object
Name: MyCustomMethod
Parms: string interesting, string aaa, string bbb, string ccc = "foo"
PlanName: sampleHtml
CodeBlob: string foo = "foo";
Options:
Path: Actions[0]:Result:ExitData
SerializationType: Html
SetContentType: true
PollingIntervalSeconds: 2
TimeoutSeconds: 10
The above will auto-generate a c# code file, which is then auto-compiled to a dll, all output into a subfolder called C:\Synapse\Controller\Assemblies\Custom\Synapse.CustomAssm.Sample
.
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Web.Http;
using Synapse.Core;
using Synapse.Services;
namespace Synapse.Custom
{
[SynapseCustomAuthorize( "ApiTopic" )]
[RoutePrefix( "my/route" )]
public class CustomController : ApiController
{
[HttpGet]
[Route( "hello" )]
public string Hello()
{
return "Hello from CustomController, World!";
}
[HttpGet]
[Route( "hello/whoami" )]
public string WhoAmI()
{
return GetExecuteControllerInstance().WhoAmI();
}
[SynapseCustomAuthorize( "MethodTopic" )]
[HttpGet]
[Route( "{interesting}/path" )]
public object MyCustomMethod(string interesting, string aaa, string bbb, string ccc = "foo")
{
Dictionary<string, string> parms = new Dictionary<string, string>( StringComparer.OrdinalIgnoreCase );
parms["interesting"] = string.Format( "{0}", interesting );
parms["aaa"] = string.Format( "{0}", aaa );
parms["bbb"] = string.Format( "{0}", bbb );
parms["ccc"] = string.Format( "{0}", ccc );
string foo = "foo";
return (object)StartPlan( planUniqueName: "sampleHtml", parms: parms, serializationType: SerializationType.Html, pollingIntervalSeconds: 2, timeoutSeconds: 10 );
}
IExecuteController GetExecuteControllerInstance()
{
System.Net.Http.Headers.AuthenticationHeaderValue auth = null;
if( Request != null )
if( Request.Headers != null )
auth = Request.Headers.Authorization;
return ExtensibilityUtility.GetExecuteControllerInstance( Url, User, auth );
}
object StartPlan(string planUniqueName, Dictionary<string, string> parms = null,
string path = "Actions[0]:Result:ExitData", SerializationType serializationType = SerializationType.Json,
bool setContentType = true, int pollingIntervalSeconds = 1, int timeoutSeconds = 120, string nodeRootUrl = null, bool executeAsync = false)
{
StartPlanEnvelope pe = new StartPlanEnvelope { DynamicParameters = new Dictionary<string, string>( StringComparer.OrdinalIgnoreCase ) };
IEnumerable<KeyValuePair<string, string>> queryString = this.Request.GetQueryNameValuePairs();
foreach( KeyValuePair<string, string> kvp in queryString )
pe.DynamicParameters.Add( kvp.Key, kvp.Value );
if( parms != null )
foreach( KeyValuePair<string, string> kvp in parms )
pe.DynamicParameters[kvp.Key] = kvp.Value;
string body = "body";
if( Url.Request.Properties.ContainsKey( body ) && Url.Request.Properties[body] != null )
pe.DynamicParameters["requestBody"] = Url.Request.Properties[body].ToString();
string dryrun = "dryRun";
bool dryRun = false;
if( pe.DynamicParameters.ContainsKey( dryrun ) )
bool.TryParse( pe.DynamicParameters[dryrun], out dryRun );
string requestnumber = "requestNumber";
string requestNumber = null;
if( pe.DynamicParameters.ContainsKey( requestnumber ) )
requestNumber = pe.DynamicParameters[requestnumber];
if( executeAsync )
return GetExecuteControllerInstance().StartPlan( planEnvelope: pe,
planUniqueName: planUniqueName, dryRun: dryRun, requestNumber: requestNumber, nodeRootUrl: nodeRootUrl );
else
return GetExecuteControllerInstance().StartPlanSync( planEnvelope: pe,
planUniqueName: planUniqueName, dryRun: dryRun, requestNumber: requestNumber,
path: path, serializationType: serializationType, setContentType: setContentType,
pollingIntervalSeconds: pollingIntervalSeconds, timeoutSeconds: timeoutSeconds, nodeRootUrl: nodeRootUrl );
}
}
}
Example of Directly Invoking the Compiler
The above will also generate a "make file," which is a alternate input that allows you to directly compile the code file(s) to a dll. This is useful is you need to manually edit the code files post-template-generation.
Usage:
c:\Synapse\Controller\Assemblies\Custom\Synapse.CustomController.exe Synapse.CustomAssm.Sample.dll.make.yaml
Where Synapse.CustomAssm.Sample.dll.make.yaml
is:
OutputAssembly: Synapse.CustomAssm.Sample.dll
Compiler:
WarningLevel: 3
TreatWarningsAsErrors: false
IncludeDebugInformation: false
CompilerOptions: /optimize
ReferencedAssemblies:
- Newtonsoft.Json.dll
- Synapse.Core.dll
- Synapse.Server.Extensibility.dll
- System.Net.Http.dll
- System.Net.Http.Formatting.dll
- System.Web.Http.dll
- YamlDotNet.dll
Files:
- Synapse.CustomAssm.Sample\Custom.cs
Declare your Custom Controller Interface
After you implement the custom interface and compile it to a dll, you need to specify it in Synapse.Server.config.yaml in the Controller->Assemblies section, as shown below. The syntax is simply to list the assembly name, as opposed to assembly:{namepsace:}class
, as in Handler declaration. Synapse Controller will discover all classes that inherit from System.Web.Http.ApiController
(MSDN).
# Configure the 'Assemblies' node of Synapse.Server.config.yaml
Service:
Name: Synapse.Controller
DisplayName: Synapse Controller
Role: Controller
...
Controller:
...
Assemblies:
- Name: Synapse.CustomController0
Config:
{any required config}
- Name: Synapse.CustomController1
Config:
{any required config}
- Name: Synapse.CustomController2
Config:
{any required config}
Dal:
...