# CD Agent for .Net Application

## Onboarding the .Net CD Agent <a href="#sealightscdagentfor.netapplication-onboardingthe.netcdagent" id="sealightscdagentfor.netapplication-onboardingthe.netcdagent"></a>

These steps outline the onboarding steps needed on the environment, with the CD agent, added to each component that builds up the Application Under Test.

### Configuration steps <a href="#sealightscdagentfor.netapplication-configurationsteps" id="sealightscdagentfor.netapplication-configurationsteps"></a>

1. **Download an Agent Token (**[generating-a-token](https://docs.sealights.io/knowledgebase/setup-and-configuration/getting-started/steps-for-successful-onboarding/generating-a-token "mention")) **from the dashboard** and make it available to each component configured with our agent.
   * This can be done by placing it in a file accessible to the agent or through an environment variable directly or through a secret manager.
2. **Download the CD agent** and make it available to each component by copying it in, downloading it during startup, or mounting an external volume containing the agent. Please refer to the dedicated section below for details.
3. **Optional (required only when onboarding multiple services into a single Integration Build).** Create an “Integration Build Lab ID” entry of type “CD only” in the dashboard for the tested application (see picture on the right).
   * Do so in the settings of the SeaLights dashboard, under '**Cockpit & Onboarding** → **Integration Build Labs** → **CD Only**'
   * The lab ID from this integration build entry needs to be provided to the CD agent through an environment variable.
4. **Add the CD agent to your environment to attach it as a Profiler to your Application Under Test**.
5. **Set the relevant parameters and/or environment variables to be used** (See samples below)

<figure><img src="https://4057366433-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FAjqTCMRYvHhDgsdPLUnc%2Fuploads%2FjejsgyRz8v3YqzKDaA2c%2Fimage.png?alt=media&#x26;token=b4b28ce2-7199-474c-b744-a5db2f14eace" alt=""><figcaption></figcaption></figure>

{% hint style="success" %}
When the **application is up** and running and the **Sealights CD Agent configured**, you can see it is properly running from the ***Cockpit -> Live Agents Monitor*** screen.
{% endhint %}

## Sample Commands <a href="#sealightscdagentfor.netapplication-samplecommands" id="sealightscdagentfor.netapplication-samplecommands"></a>

### Downloading the agent <a href="#sealightscdagentfor.netapplication-downloadingtheagent" id="sealightscdagentfor.netapplication-downloadingtheagent"></a>

{% hint style="info" %}
The different available options to download the agent are documented in a dedicated central page:  [downloading-the-.net-core-agent](https://docs.sealights.io/knowledgebase/setup-and-configuration/sealights-agents-and-plugins/.net-core-agent/downloading-the-.net-core-agent "mention")
{% endhint %}

For example, you can use the following commands to automate the process

{% tabs %}
{% tab title="Linux" %}
{% code overflow="wrap" lineNumbers="true" %}

```powershell
wget -nv -O sealights-dotnet-agent-linux.tar.gz https://agents.sealights.co/dotnetcore/latest/sealights-dotnet-agent-linux-self-contained.tar.gz
mkdir sl-dotnet-agent && tar -xzf ./sealights-dotnet-agent-linux.tar.gz --directory ./sl-dotnet-agent
echo "[Sealights] .NetCore Agent version is: `cat ./sl-dotnet-agent/version.txt`"
```

{% endcode %}
{% endtab %}

{% tab title="Windows" %}
{% code overflow="wrap" lineNumbers="true" %}

```powershell
iwr -OutFile sealights-dotnet-agent.zip -UseBasicParsing -Uri https://agents.sealights.co/dotnetcore/latest/sealights-dotnet-agent-windows-self-contained.zip
Expand-Archive .\sealights-dotnet-agent.zip -DestinationPath sl-dotnet-agent -Force
Write-Output "[Sealights] .NetCore Agent version is: $(Get-Content .\sl-dotnet-agent\version.txt)"
```

{% endcode %}
{% endtab %}
{% endtabs %}

### Sample configuration in a docker file <a href="#sealightscdagentfor.netapplication-sampleconfigurationinadockerfile" id="sealightscdagentfor.netapplication-sampleconfigurationinadockerfile"></a>

{% code overflow="wrap" lineNumbers="true" %}

```docker
ENV CORECLR_ENABLE_PROFILING=1
ENV CORECLR_PROFILER="{3B1DAA64-89D4-4999-ABF4-6A979B650B7D}"
ENV CORECLR_PROFILER_PATH_32=/sealights/libSL.DotNet.ProfilerLib.Linux.so
ENV CORECLR_PROFILER_PATH_64=/sealights/libSL.DotNet.ProfilerLib.Linux.so
ENV SL_PROFILER_INITIALIZECOLLECTOR=1
ENV SL_PROFILER_INITIALIZECOLLECTOR_MODE="cdAgent"
ENV SL_PROFILER_BLOCKING_CONNECTION_STARTUP="ASYNC"
ENV SL_FEATURES_IDENTIFYMETHODSBYFQN="true"
ENV SL_SESSION_TOKENFILE=/sealights/sltoken.txt

ARG BUILD_NUMBER
ENV SL_GENERAL_APPNAME="otel_cartservice"
ENV SL_GENERAL_BRANCHNAME="main"
ENV SL_GENERAL_BUILDNAME=$BUILD_NUMBER
ENV SL_LABID="my_lab"
ENV SL_SCAN_BINDIR="/app"
ENV SL_SCAN_INCLUDENAMESPACES_0="cartservice.*"
ENV SL_SCAN_INCLUDEASSEMBLIES="*cartservice"
```

{% endcode %}

### Sample K8s yaml <a href="#sealightscdagentfor.netapplication-samplek8syaml" id="sealightscdagentfor.netapplication-samplek8syaml"></a>

{% code overflow="wrap" lineNumbers="true" %}

```yaml
spec:
  initContainers:
  - name: sealights-dotnet-agent
    image: ubuntu:latest
    imagePullPolicy: IfNotPresent
    command: ["/bin/sh", "-c"]
    args:
      - |
		wget -nv -O sealights-dotnet-agent-linux.tar.gz https://agents.sealights.co/dotnetcore/latest/sealights-dotnet-agent-linux-self-contained.tar.gz
		tar -xzf ./sealights-dotnet-agent-linux.tar.gz --directory /sealights
		echo "[Sealights] .NetCore Agent version is: $(cat /sealights/version.txt)"
    volumeMounts:
      - mountPath: /sealights
        name: sealights-dotnet-agent-file
  
  containers:
  - name: your-app-service-container
    # other container configurations
	# [...]
    env:
	### SL Profiler - Generic vars
	- name: SL_TOKEN
	    secretKeyRef:
          name: sealights
          key: SL_TOKEN
	- name: CORECLR_ENABLE_PROFILING
	  value: "1"
	- name: CORECLR_PROFILER
	  value: "{3B1DAA64-89D4-4999-ABF4-6A979B650B7D}"
	- name: CORECLR_PROFILER_PATH_32
	  value: /sealights/libSL.DotNet.ProfilerLib.Linux.so
	- name: CORECLR_PROFILER_PATH_64
	  value: /sealights/libSL.DotNet.ProfilerLib.Linux.so
	- name: SL_PROFILER_INITIALIZECOLLECTOR_MODE
	  value: "cdAgent"
	- name: SL_PROFILER_INITIALIZECOLLECTOR
	  value: 1
	- name: SL_PROFILER_BLOCKING_CONNECTION_STARTUP
	  value: "ASYNC"
	- name: SL_FEATURES_IDENTIFYMETHODSBYFQN
	  value: "true"

	### SL Profiler - Env Specific vars
	- name: SL_SCAN_BINDIR
	  value: "/app"
	- name: SL_LABID
	  value: "integ_poc_sl"

	### SL Profiler - App Specific vars
	- name: SL_GENERAL_APPNAME
	  value: "myproject-myapp-service"
	- name: SL_GENERAL_BRANCHNAME
	  value: "sample-branch"
	- name: SL_GENERAL_BUILDNAME
	  value: "1.0.2"
	- name: SL_SCAN_INCLUDENAMESPACES_0
	  value: "myproject.*"
	- name: SL_SCAN_INCLUDEASSEMBLIES
      #reduce files to scan to speed up startup
	  value: "*myproject*"

	volumeMounts:
    - mountPath: /sealights
      name: sealights-dotnet-agent-file
  volumes:
    - name: sealights-dotnet-agent-file
      emptyDir: {}
```

{% endcode %}

### IIS Application <a href="#sealightscdagentfor.netapplication-iisapplication" id="sealightscdagentfor.netapplication-iisapplication"></a>

* Make sure that the publish mode is not “Single file“ or “Portable“.
* Prepare the environment variables below (absolute paths are better)&#x20;

{% hint style="info" %}
In the snippet below, pmake sure to update according to your environment:

* `C:\AbsolutePathToAgentFolder` , to the right path
* All mandatory variables to the right value: SL\_SESSION\_TOKENFILE, SL\_GENERAL\_APPNAME, SL\_GENERAL\_BUILDNAME, SL\_SCAN\_INCLUDENAMESPACE
  {% endhint %}

{% code overflow="wrap" lineNumbers="true" %}

```
COR_ENABLE_PROFILING=1
COR_PROFILER={01CA2C22-DC03-4FF5-8350-59E32A3536BA}
COR_PROFILER_PATH=C:\AbsolutePathToFolder\SL.DotNet.ProfilerLib.Windows_x64.dll
COR_PROFILER_PATH_32=C:\AbsolutePathToFolder\SL.DotNet.ProfilerLib.Windows_x86.dll
COR_PROFILER_PATH_64=C:\AbsolutePathToFolder\SL.DotNet.ProfilerLib.Windows_x64.dll
CORECLR_ENABLE_PROFILING=1
CORECLR_PROFILER={01CA2C22-DC03-4FF5-8350-59E32A3536BA}
CORECLR_PROFILER_PATH_32=C:\AbsolutePathToFolder\SL.DotNet.ProfilerLib.Windows_x86.dll
CORECLR_PROFILER_PATH_64=C:\AbsolutePathToFolder\SL.DotNet.ProfilerLib.Windows_x64.dll

SL_PROFILER_INITIALIZECOLLECTOR=1
SL_PROFILER_INITIALIZECOLLECTOR_MODE=cdAgent
SL_FEATURES_IDENTIFYMETHODSBYFQN=true

SL_PROFILER_BLOCKING_CONNECTION_STARTUP=ASYNC
SL_AGENT_PORT=31031
SL_EXE_PATH=C:\AbsolutePathToFolder\SL.DotNet.exe
SL_SESSION_TOKENFILE=C:\AbsolutePathToFolder\sltoken.txt

useMsProfiler=False
SL_GENERAL_BUILDNAME=PICCDAGENT-IIS-5
SL_GENERAL_APPNAME=TestAppWeatherApi
SL_GENERAL_BRANCHNAME=main

SL_SCAN_BINDIR=c:\inetpub\TestWebApp\
SL_LABID=integ_main_TestAppWeatherApi

SL_SCAN_INCLUDENAMESPACE=StatelessWebApp.*
SL_SCAN_INCLUDEASSEMBLIES=*StatelessWebApp*
SL_PROFILER_INCLUDEPROCESSFILTER=*TestWebApp*

SL_LOGGING_ENABLED=true
SL_LOGLEVEL=Info
SL_LOGGING_TOFILE=true
SL_LOGDIRECTORY=C:\AbsolutePathToFolder\logs
```

{% endcode %}

* Set the environment variables to IIS Services in the Windows Registry.
  * For that, open the registry keys `Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\WAS` and `Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W3SVC`
  * Add a new **Multi-String** value called **Environment**

    <figure><img src="https://4057366433-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FAjqTCMRYvHhDgsdPLUnc%2Fuploads%2FXcrIZoDp76JyKLUOe9nW%2Fimage-20240425-142701.png?alt=media&#x26;token=6422eb15-b293-45e5-8fee-16dc3e7a470e" alt=""><figcaption></figcaption></figure>
* Restart the IIS Server via the usual `iisreset /restart`
* Perform the query to the web application to wake it up.

### Simple Web App (Desktop, Windows) <a href="#sealightscdagentfor.netapplication-simplewebapp-desktop-windows" id="sealightscdagentfor.netapplication-simplewebapp-desktop-windows"></a>

This simple use case illustrates how to collect coverage with the CD agent from a web application started without parameters.

{% code overflow="wrap" lineNumbers="true" %}

```bash
C:\Sealights\Agent\SL.DotNet.exe cdAgent --appName "TestApp" --branchName "main" --buildName "1.16.10" --labId "integ_demo_DesktopWeatherApp" \
    --binDir "C:\Program Files\WeatherApi" --includeNamespace "WeatherApi*" --target "C:\Program Files\WeatherApi\WeatherApi.exe" 
```

{% endcode %}

### Microservice (Alpine-based docker file) <a href="#sealightscdagentfor.netapplication-microservice-alpine-baseddockerfile" id="sealightscdagentfor.netapplication-microservice-alpine-baseddockerfile"></a>

DockerFile

{% code overflow="wrap" lineNumbers="true" %}

```docker
FROM mcr.microsoft.com/dotnet/runtime:6.0-alpine

WORKDIR /app
COPY --from=build /app/out .
COPY Scripts/start-app.sh .

# Sealights - install prereq, agent, token, bsid
# Best practice it to mount a pre-existing sealights directory depending on the environment (test or prod)
RUN mkdir -p /sealights/{agent,logs}
RUN wget -nv -O sealights-dotnet-agent-alpine.tar.gz https://agents.sealights.co/dotnetcore/latest/sealights-dotnet-agent-alpine-self-contained.tar.gz
RUN tar -xzf ./sealights-dotnet-agent-alpine.tar.gz --directory /sealights/agent
COPY ["SeaLights/sltoken.txt", "/sealights/"]
RUN chmod -R 777 /sealights

# Set the script as the entrypoint
ENTRYPOINT ["sh", "start-app.sh", "YourAppName.dll"]
```

{% endcode %}

Startup script

{% code overflow="wrap" lineNumbers="true" %}

```sh
#!/bin/sh
# Check if sealights folder exists
if [ -d "/app/sealights/" ]; then
    /app/sealights/agent/SL.DotNet cdAgent --appName ms-gateway-api --branchName poc --buildName $(cat /app/version.txt) \
                  --binDir /app --includeNamespace MyCompany.* --target dotnet --targetArgs $1 --workingDir /app \
                  --identifyMethodsByFqn --profilerLogLevel 6 --profilerLogDir /app/sealights/logs --labId integ_POC_DemoApp
else
    dotnet $1
fi
```

{% endcode %}

## Agent’s Parameters Reference <a href="#sealightscdagentfor.netapplication-agentsparametersreference" id="sealightscdagentfor.netapplication-agentsparametersreference"></a>

### Mandatory parameters - .Net/Agent <a href="#sealightscdagentfor.netapplication-mandatoryparameters-.net-agent" id="sealightscdagentfor.netapplication-mandatoryparameters-.net-agent"></a>

<table><thead><tr><th width="239.00006103515625">Variable</th><th width="84">Required</th><th width="306.33349609375">Description</th><th>Property (CLI)</th></tr></thead><tbody><tr><td><code>COR_ENABLE_PROFILING</code></td><td>Yes</td><td>Instructs the runtime to enable profiling. Set to: <code>1</code></td><td>N/A</td></tr><tr><td><code>COR_PROFILER</code></td><td>Yes</td><td>Instructs the runtime which profiler to use. Set to: <code>{3B1DAA64-89D4-4999-ABF4-6A979B650B7D}</code></td><td>N/A</td></tr><tr><td><code>COR_PROFILER_PATH_32</code></td><td>Yes</td><td>Instructs the runtime where to find the 32 bit version of the profiler<br>Set to the path of <code>libSL.DotNet.ProfilerLib.Linux.so</code></td><td>N/A</td></tr><tr><td><code>COR_PROFILER_PATH_64</code></td><td>Yes</td><td>Instructs the runtime where to find the 64 bit version of the profiler<br>Set to the path of <code>libSL.DotNet.ProfilerLib.Linux.so</code></td><td>N/A</td></tr><tr><td><code>CORECLR_ENABLE_PROFILING</code></td><td>Yes</td><td>Instructs the runtime to enable profiling for .NET Core<br>Set to: <code>1</code></td><td>N/A</td></tr><tr><td><code>CORECLR_PROFILER</code></td><td>Yes</td><td>Instructs the runtime which profiler to use for .NET Core<br>Set to: <code>{3B1DAA64-89D4-4999-ABF4-6A979B650B7D}</code></td><td>N/A</td></tr><tr><td><code>CORECLR_PROFILER_PATH_32</code></td><td>Yes</td><td>Instructs the runtime where to find the 32 bit version of the profiler for .NET Core<br>Set to the path of <code>libSL.DotNet.ProfilerLib.Linux.so</code></td><td>N/A</td></tr><tr><td><code>CORECLR_PROFILER_PATH_64</code></td><td>Yes</td><td>Instructs the runtime where to find the 64 bit version of the profiler for .NET Core<br>Set to the path of <code>libSL.DotNet.ProfilerLib.Linux.so</code></td><td>N/A</td></tr><tr><td><code>SL_PROFILER_INITIALIZECOLLECTOR</code></td><td>Yes</td><td>Instructs the Sealights profiler to initialize its own collector when starting up<br>Set to: <code>1</code></td><td>N/A</td></tr><tr><td><code>SL_PROFILER_INITIALIZECOLLECTOR_MODE</code></td><td>Yes</td><td>Instructs the Sealights profiler in which mode to start up<br>Set to: <code>cdAgent</code></td><td><code>cdAgent</code></td></tr><tr><td><code>SL_FEATURES_IDENTIFYMETHODSBYFQN</code></td><td>Yes</td><td>Set to <code>true</code></td><td><code>--identifyMethodsByFQN</code></td></tr></tbody></table>

### Mandatory parameters - Application specific <a href="#sealightscdagentfor.netapplication-mandatoryparameters-applicationspecific" id="sealightscdagentfor.netapplication-mandatoryparameters-applicationspecific"></a>

<table><thead><tr><th width="241">Env variable</th><th width="101">Required</th><th width="280.41015625">Description</th><th>Property (CLI)</th></tr></thead><tbody><tr><td><code>SL_SESSION_TOKENFILE</code> or <code>SL_SESSION_TOKEN</code></td><td>Yes</td><td>Provides the Sealights agent the token to work with.<br>Set to the token itself or the path to the token file.</td><td><code>--token</code> or <code>--tokenFile</code></td></tr><tr><td><code>SL_GENERAL_APPNAME</code></td><td>Yes</td><td>Name of the target application</td><td><code>--appName</code></td></tr><tr><td><code>SL_GENERAL_BRANCHNAME</code></td><td>No</td><td>Component branch name. Defaults to <code>unspecified</code> if not provided.</td><td><code>--branchName</code></td></tr><tr><td><code>SL_GENERAL_BUILDNAME</code></td><td>Yes</td><td><p><strong>Note!</strong> The build label/version of the current artifact</p><p>The exact same value must be provided for the same version of the service being deployed multiple times<br>Recommendation: The buildname should allow you to trace back the service’s changes in your SCM. ex. the buildname comes from the Jenkin’s deployment job that shows the artifact version, which can be used to get SCM commit hash. This is useful when identifying changes identified in TGA report to those who made the changes for example.</p></td><td><code>--buildName</code></td></tr><tr><td><code>SL_LABID</code>, <code>SL_SESSION_LABID</code></td><td>Yes</td><td>The labId generated for the Integration Build entry in Step #3, or a unique, hard-coded free-text labId when not using an Integration Build.</td><td><code>--labId</code></td></tr><tr><td><code>SL_SCAN_BINDIR</code></td><td>Yes</td><td>Path to the scanned folder where all binary files are located.</td><td><code>--binDir</code></td></tr><tr><td><code>SL_SCAN_INCLUDENAMESPACES</code></td><td>Yes</td><td>Comma-separated list of namespaces to include in the scan.<br>Supports wildcard (<code>*</code> = any string, <code>?</code> = any character) characters.</td><td><code>--includeNamespace</code></td></tr></tbody></table>

### Optional parameters <a href="#sealightscdagentfor.netapplication-optionalparameters" id="sealightscdagentfor.netapplication-optionalparameters"></a>

These parameters may be required due to your specific configuration or environment’s limitations (e.g., proxy).

<table><thead><tr><th width="240.666748046875">Env variable</th><th width="342.333251953125">Description</th><th>Parameter (CLI)</th></tr></thead><tbody><tr><td><code>SL_SCAN_EXCLUDENAMESPACES</code></td><td><p>Comma-separated list of namespaces to exclude from the scan. Supports wildcard (<code>*</code> = any string, <code>?</code> = any character) characters.</p><p>Default value: <code>System.*, Microsoft.*</code></p></td><td><code>--excludeNamespace</code></td></tr><tr><td><code>SL_SCAN_INCLUDEFILES</code></td><td><p>Comma-separated list of files to include in scan. Supports wildcard (<code>*</code> = any string, <code>?</code> = any character) characters.</p><p>Default value: <code>*.dll,*.exe</code></p></td><td><code>--include</code></td></tr><tr><td><code>SL_SCAN_EXCLUDEFILES</code></td><td>Comma-separated list of files to exclude from the scan. Supports wildcard (<code>*</code> = any string, <code>?</code> = any character) characters.<br>Default value: <code>System.", "Microsoft.</code></td><td><code>--exclude</code></td></tr><tr><td><code>SL_SCAN_INCLUDEASSEMBLIES</code></td><td>Comma-separated list of assemblies to include. Supports wildcard (<code>*</code> = any string, <code>?</code> = any character) characters.</td><td><code>--includedAssemblies</code></td></tr><tr><td><code>SL_SCAN_EXCLUDEASSEMBLIES</code></td><td><p>Comma-separated list of assemblies to exclude from the scan. Supports wildcard (<code>*</code> = any string, <code>?</code> = any character) characters.</p><p>Default value: <code>mscorlib, System., Microsoft.</code></p></td><td><code>--excludedAssemblies</code></td></tr><tr><td><code>SL_SCAN_SRCROOTDIR</code></td><td>The project source root directory, where all paths will be made relative to</td><td><code>--srcRootDir</code></td></tr><tr><td><code>SL_PROFILER_TARGET</code></td><td>The name of the target application that will be started</td><td><code>--target</code></td></tr><tr><td><code>SL_PROFILER_TARGETARGS</code></td><td>Arguments to be passed to the target process</td><td><code>--targetArgs</code></td></tr><tr><td><code>SL_PROFILER_WORKINGDIR</code></td><td>The path to the working directory. By default, it’s using current working directory.</td><td><code>--workingDir</code></td></tr></tbody></table>

### Logging parameters <a href="#sealightscdagentfor.netapplication-loggingparameters" id="sealightscdagentfor.netapplication-loggingparameters"></a>

To enable logs, you can set the following parameters

<table><thead><tr><th width="190.3333740234375">Env variable</th><th width="404.6666259765625">Description</th><th>Parameter (CLI)</th></tr></thead><tbody><tr><td><code>SL_LOGGING_ENABLED</code></td><td>Set to <code>true</code> to enable logging to the console</td><td></td></tr><tr><td><code>SL_LogLevel</code></td><td><p>Log level. Default and Recommended value is <code>6</code></p><ul><li><code>0</code>=None</li><li><code>3</code>=Errors</li><li><code>4</code>=Warnings</li><li><code>6</code>=Info (Light Debug)</li><li><code>7</code>=Debug(Full)</li></ul></td><td></td></tr><tr><td><code>SL_Logging_toFile</code></td><td>Set to <code>true</code> to enable logging to a file</td><td></td></tr><tr><td><code>SL_LogDir</code></td><td>Folder to save the log files to</td><td></td></tr><tr><td><code>SL_LOGGING_FileName</code></td><td>File name to save the log to</td><td></td></tr></tbody></table>
