Develop with Refinitiv WebSocket API Docker Image with C# in VS Code Using the Remote - Containers extension
- version: 2.0
- Last update: July 2023
- Environment: Docker
- Compiler: C#
- Prerequisite: Demo prerequisite
Example Code Disclaimer: ALL EXAMPLE CODE IS PROVIDED ON AN “AS IS” AND “AS AVAILABLE” BASIS FOR ILLUSTRATIVE PURPOSES ONLY. REFINITIV MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, AS TO THE OPERATION OF THE EXAMPLE CODE, OR THE INFORMATION, CONTENT, OR MATERIALS USED IN CONNECTION WITH THE EXAMPLE CODE. YOU EXPRESSLY AGREE THAT YOUR USE OF THE EXAMPLE CODE IS AT YOUR SOLE RISK.
The main configuration file that tells VS Code how to access (or create) a devcontainer with a well-defined tool and runtime stack is named the devcontainer.json file. The dev container configuration is either located under .devcontainer/devcontainer.json or stored in a file named .devcontainer.json file (note the dot-prefix) in the root of the project.
Note: Make sure to commit a .devcontainer folder to your version control system.
Let me explain these configurations:
// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
// https://github.com/microsoft/vscode-dev-containers/tree/v0.202.5/containers/
{
"name": "WebSocket_dotNet",
"build": {"dockerfile": "Dockerfile"},
"runArgs": [
"--env-file=.devcontainer/.env.devcontainer"
],
"customizations": {
"vscode": {
"extensions": ["ms-dotnettools.csharp"],
"settings": {
"omnisharp.useModernNet": false,
"omnisharp.sdkPath": "/usr/bin/dotnet"
}
}
},
"workspaceFolder": "/opt/refinitiv/websocket-api/Applications/Examples/RDP/CSharp",
"mounts": [
"source=${localWorkspaceFolder}/.vscode,target=${containerWorkspaceFolder}/.vscode,type=bind,consistency=cached",
"source=${localWorkspaceFolder}/shareFolder,target=${containerWorkspaceFolder}/shareFolder,type=bind,consistency=cached"
],
"shutdownAction":"stopContainer"
}The detail of the configurations above are:
name: A display name for the container.build: The location of a Dockerfile that defines the contents of the container.runArgs: An array of Docker CLI arguments that VS Code uses when running the container. I am setting the--env-fileoption that sets the container's environment variables via a file named .env.devcontainer.customizations.vscode.extensions: Specify VS Code extension IDs that will be installed inside the container. I am setting the C# extension for Visual Studio Code here.customizations.vscode.settings: Adds default settings.json values into a container/machine specific settings file. I am setting the C# extension configurations here.workspaceFolder: Sets the default path that VS Code should open when connecting to the container. This devcontainer sets the default path to /opt/refinitiv/websocket-api/Applications/Examples/RDP/CSharp which is the RTO C# examples location in the container.mounts: Add mount points to the container when created for sharing files between the host and devcontainer. I am mounting the.vscodefolder for the C# running/debugging configurations and theshareFolderto share files between host and devcontainer.shutdownAction: set the VS Code stops the container when the editor window is closed/shut down.
The development container is not limited to Docker Images or a Dockerfile, it supports Docker Compose too. You can build your image(s) to match your development requirements, and then share Dockerfile and/or docker-compose.yml inside a .devcontainer folder (with a devcontainer.json file) with your colleagues to help them to set up the same development environment.
Please find more details about all devcontainer.json configuration parameters on the VS Code - devcontainer.json reference page.
The refinitivapis/websocket_api Docker Image has the Python runtime and dependencies pre-installed for the Python WebSocket examples. However, it is based on the Linux OS Image, so we can build a new Docker image on top of it and install compilers, SDKs, or runtime for the other WebSocket examples.
A Dockerfile for the RTO C# WebSocket examples is as follows:
# Pulling Image from https://hub.docker.com/r/refinitivapis/websocket_api
FROM refinitivapis/websocket_api:latest
LABEL maintainer="Developer Advocate"
ARG dotnet_version="6.0"
# Install updates, dotnet-sdk and tools for VS Code devcontainer.
RUN yum update -y \
&& yum -y install dotnet-sdk-${dotnet_version} wget tar.x86_64 which \
# Clean up unnecessary files to reduce Image size
&& yum clean all
# Set work directory to be RDP/CSharp
WORKDIR /opt/refinitiv/websocket-api/Applications/Examples/RDP/CSharp
# Set Docker to start bash
CMD /bin/bash
The above Dockerfile instructions do the following tasks.
- Pull refinitivapis/websocket_api as the Base Image with the
FROMinstruction. - Install .NET SDK and runtime to the Image (As of July 2023: The RTO C# examples support .NET version 6.0).
- Install additional packages for VS Code and the Remote - Containers extension.
- Set a new working directory to /opt/refinitiv/websocket-api/Applications/Examples/RDP/CSharp folder with the
WORKDIRinstruction.
Please note that you can build and run this Dockerfile with the Docker engine CLI too.
According to the methodology 3rd factor of the Twelve-Factor App methodology, it is a good practice to keep configuration information and credentials as environment variables, then inject them into the application on runtime.
I am keeping the RTO credentials (both V1 and V2 Authentication) in a file named .env.devcontainer file under the .devcontainer folder as follows:
#V 1
RTO_USERNAME=<Version 1 RTO Machine-ID>
RTO_PASSWORD=<Version 1 RTO Password>
RTO_CLIENTID=<Version 1 RTO AppKey>
#V 2
RTO_CLIENTID=<Version 2 Client-ID>
RTO_CLIENTSECRET=<Version 2 Client-Secret>Please note that the environment variable file above contains the V1 and V2 Authentication. If you have only V1 or V2, please change the file based on your preference.
Then, we set this .env.devcontainer file to Docker on runtime with the devcontainer.json's "runArgs": ["--env-file=.devcontainer/.env.devcontainer"] configuration. Once the devcontainer creation is successful, developers can access RTO credentials via the following methods:
- In a container's bash: via the
$<variable name>syntax like$RTO_USERNAME(V1) or$RTO_CLIENTID(V2) - In VS Code launch.json: via the
${env:<variable name>}syntax like${env:RTO_USERNAME}(V1) or${env:RTO_CLIENTID}(V2)
You should not share this .env.devcontainer file to your peers or commit/push it to the version control. You should add the file to the .gitignore file to avoid adding it to version control or public repository accidentally.
You can create a .env.devcontainer.example file as a template for environment variables file sharing. The file has the same parameters' keys as a .env.devcontainer file but without sensitive values.
VS Code has built-in debugging support for various programming languages. Developers can configure and save their debugging setup detail in a lunch configuration file named launch.json located in a .vscode folder of the workspace (project root folder).
To set a devcontainer to run and debug the MarketPriceRdpGwServiceDiscoveryExample application with the .NET Core runtime, I am setting a launch.json configuration as follows:
{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/MarketPriceRdpGwClientCredAuthExample/bin/Debug/net6.0/MarketPriceRdpGwClientCredAuthExample_NET6.0.dll",
"args": ["--user","${env:RTO_USERNAME}","--password","${env:RTO_PASSWORD}","--clientid","${env:RTO_CLIENTID}","--ric","/EUR="],
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}{
"version": "0.2.0",
"configurations": [
{
// Use IntelliSense to find out which attributes exist for C# debugging
// Use hover for the description of the existing attributes
// For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
"name": ".NET Core Launch (console)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/MarketPriceRdpGwClientCredAuthExample/bin/Debug/net6.0/MarketPriceRdpGwClientCredAuthExample_NET6.0.dll",
"args": ["--clientid","${env:RTO_CLIENTID}","--clientsecret","${env:RTO_CLIENTSECRET}","--ric","/EUR="],
"cwd": "${workspaceFolder}/MarketPriceRdpGwClientCredAuthExample",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
"console": "internalConsole",
"stopAtEntry": false
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
}
]
}Please noticed that the args attribute has been set to map a container environment variable to the example application parameters. This setting makes VS Code automatic passes the RTO credentials in a devcontainer's environment variables to the MarketPriceRdpGwServiceDiscoveryExample command line options. Developers do not need to manual paste their credentials in a devcontainer anymore.
Developers can save their building, packaging, testing, or deploying steps in a tasks configuration file named tasks.json located in a .vscode folder of the workspace (project root folder). A tasks.json file for automatic builds of the RTO C# WebSocket CSharpRdpGwExamples_NET6.0 solution with the following configurations:
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/CSharpRdpGwExamples_NET6.0.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary"
],
"problemMatcher": "$msCompile"
},
....
]
}We mount this .vscode folder to a Docker Container with the devcontainer.json's "mounts": ["source=${localWorkspaceFolder}/.vscode,target=${containerWorkspaceFolder}/.vscode,type=bind,consistency=cached"] configuration. Once the devcontainer creation is successful, developers can start run and debug RTO C# Websocket examples session in VS Code directly.
Please find more detail about VS Code Debugging and Tasks configurations from the following resources:
- VS Code: Debugging User Guide.
- VS Code: Integrate with External Tools via Tasks.
- Configuring launch.json for C# debugging.
- Console (terminal) window setting.
Docker Desktop/engine should be running before the next step.
You can connect to the container and start developing within it by selecting the Remote-Containers: Reopen in Container command from the VS Code Command Palette (F1).
Alternatively, the VS Code can detect whether there is a folder containing a Dev container configuration file, and then asks you if you want to reopen the folder in a container.
Next, the VS Code window (instance) reloads and builds a Docker image from a Dockerfile, then starts a devcontainer. Please note that if the image is already built, the process will be faster.
There may be a message “There are unresolved dependencies. Please execute the restore command to continue” At this point. This message is generated from VS Code C# extension. Please click the Restore button.
Once this build completes, VS Code automatically connects to the container at the path we set to the workspaceFolder property which is the /opt/refinitiv/websocket-api/Applications/Examples/RDP/CSharp folder. You can check the VS Code Remote connection status from the button left toolbar.
If you click this toolbar, VS Code shows the Container Remote connection menu options at the top of the editor.
To close the remote connection, choose the "Close Remote Connection" from the drop-down menu.
This devcontainer already has the C# extension built-in and VS Code's launch.json and tasks.json configurations files, developers can run the MarketPrice RDP Service Discovery Example (MarketPriceRdpGwServiceDiscoveryExample) by pressing the F5 button or selecting Run then Start Debugging option from VS Code menu.
VS Code automatic runs the MarketPriceRdpGwServiceDiscoveryExample application with the RTO credentials, and --ric command-line options set in a launch.json file. All RTO credentials are available in the container environment variables, so developers do not need to manually set them. Developers can change the RIC code or add other options in the args attribute of a launch.json file. Please find more detail about other options in the solution readme file.
Alternatively, developers can run the example in bash manually via the following steps (I am demonstrating with the V2 Authentication):
$>dotnet build CSharpRdpGwExamples_NET6.0.sln
$>cd MarketPriceRdpGwClientCredAuthExample/bin/Debug/net6.0/
$>dotnet MarketPriceRdpGwClientCredAuthExample_NET6.0.dll --clientid $RTO_CLIENTID --clientsecret $RTO_CLIENTSECRET --ric <RIC Code>This C# devcontainer is based on the refinitivapis/websocket_api Docker Image, so developers can run the Python WebSocket examples too.
The steps to run the RTO Python WebSocket example are as follows:
$>cd /opt/refinitiv/websocket-api/Applications/Examples/RDP/python
$>python market_price_rdpgw_service_discovery.py --clientid $RTO_CLIENTID --clientsecret $RTO_CLIENTSECRET --ric <RIC Code>






