# Technical documentation — serverless-net-core

Evidence date: 2026-10-04.

Source: `git@bitbucket.org:overdrive/serverless-net-core.git`, `master` at `ca18f8f` (2021-06-01).

`Handler.cs` contains a MySQL password. This document names the host, user, and database. It does not copy the password.

## What this repository is

A Serverless Framework service (`service: ozow-lambda-test`) that deploys a prebuilt .NET Core 3.1 Lambda zip. Two API Gateway GET routes call two public methods on `AwsDotnetCsharp.Handler`. One method queries MySQL. The other echoes query-string parameters.

The tree arrived as a starter in `402beb4` (2021-02-16). That first README pointed at `github.com/pharindoko/serverlessDotNetStarter` and included `serverless create --template-url` for that GitHub repository. `8f9e962` replaced those links with this Bitbucket repository and added the Silicon sequence. The README title is still `serverlessDotNetStarter`. The opening code fence around the install commands was removed in that same commit, so the install block in the current README is not a fenced snippet. Later commits added `MySql.Data`, pointed `HelloWorld` at database `qaunity`, and switched the .NET Lambda tools profile to `unity` / `eu-west-1`.

## Repository layout

```text
serverless.yml                      service, provider, two functions
Handler.cs                          HelloWorld, GetQuerystring, CreateResponse, LogMessage
AwsDotnetCsharp.csproj              netcoreapp3.1 Lambda project
aws-lambda-tools.default.json       dotnet lambda / Visual Studio defaults
build.cmd                           Windows package script
build.sh                            Debian zip install + package script
setup.sh                            installs Lambda Test Tool 3.1 at 0.9.5
README.md                           starter guide plus Silicon sequence
renovate.json                       extends config:base
Properties/launchSettings.json      mock tool profile, port 5050
.vscode/launch.json                 VS Code F5, program path is a {user} placeholder
.vscode/tasks.json                  preLaunchTask: dotnet build
resources/images/lambda_test_tool.png
.gitignore                          Visual Studio ignore plus node_modules and .serverless
```

No `bitbucket-pipelines.yml`, Dockerfile, `.sln`, test project, `package.json`, `sonar-project.properties`, or `sonarqube_scan.bat`. The onboarding issue listed the two Sonar filenames from a scan on 2026-09-28. They are not in this revision.

## Runtime and deploy template

From `serverless.yml`:

| Setting | Value |
|---|---|
| Framework service | `ozow-lambda-test` |
| Provider | `aws` |
| Runtime | `dotnetcore3.1` |
| Stage | not set |
| Region | not set |
| AWS profile | not set |
| Memory | not set |
| Timeout | not set |
| Package | `individually: true` |
| Plugins | none |
| Framework version pin | commented out (`frameworkVersion: "=X.X.X"`) |

Handler wiring:

| Function key | Handler | Artifact | Event |
|---|---|---|---|
| `hello` | `AwsDotnetCsharp::AwsDotnetCsharp.Handler::HelloWorld` | `bin/release/netcoreapp3.1/hello.zip` | `GET /hello` |
| `getquerystring` | `AwsDotnetCsharp::AwsDotnetCsharp.Handler::GetQuerystring` | same zip | `GET /getquerystring` |

The handler format is `Assembly::Namespace.Class::Method`. Assembly name follows the project file name `AwsDotnetCsharp`. Namespace and class are `AwsDotnetCsharp.Handler`.

Commented and inactive under `provider`: `stage`, `region`, `iamRoleStatements` (sample S3 list/put on the deployment bucket), `environment`. Commented and inactive under `getquerystring`: websocket, S3, schedule, SNS, DynamoDB stream, Alexa, IoT, CloudWatch, Cognito user-pool trigger. The `resources` CloudFormation example (`AWS::S3::Bucket` named `my-new-bucket`) is commented out.

`aws-lambda-tools.default.json` is not read by `serverless deploy` unless someone passes it. It is the defaults file for `dotnet lambda` and the Visual Studio deployment wizard. Current values: profile `unity`, region `eu-west-1`, configuration `Release`, framework `netcoreapp3.1`, template `serverless.yml`. `ca18f8f` changed profile from `default` and region from `eu-central-1`.

The README Silicon sequence runs `serverless deploy --aws-profile ozow` and shows a curl to `https://4row8qyxh1.execute-api.us-east-1.amazonaws.com/dev/hello`. That URL was not requested during this inspection.

REST paths are deployed under the stage name. The template does not set `stage` and has no `custom.customDomain`. The README examples use `/dev`. **Requires confirmation** of the stage and domain that were actually created.

## Application structure

Single project, SDK `Microsoft.NET.Sdk`.

`AwsDotnetCsharp.csproj`:

- `TargetFramework`: `netcoreapp3.1`
- `GenerateRuntimeConfigurationFiles`: true
- `AWSProjectType`: Lambda

`Handler.cs`:

- Assembly attribute `LambdaSerializer` = `Amazon.Lambda.Serialization.Json.JsonSerializer`.
- Namespace `AwsDotnetCsharp`, class `Handler`.
- Public methods `HelloWorld` and `GetQuerystring`, both `(APIGatewayProxyRequest request, ILambdaContext context)`.
- Private `LogMessage` and `CreateResponse`.
- `using var` for the MySQL connection (C# 8).

`GetQuerystring` and `CreateResponse` are the starter methods from `402beb4`. `HelloWorld` is the method `f5b7278` pointed at MySQL.

No controllers, no `Startup`, no `LambdaEntryPoint`. `Amazon.Lambda.AspNetCoreServer` is referenced and no ASP.NET pipeline is present in the tree. **Inferred:** that package is unused by the two handlers except as a possible source of the `APIGatewayEvents` types. A build was not run, so unused-reference warnings were not collected.

## Dependencies

Direct `PackageReference` versions:

| Package | Version | Introduced |
|---|---|---|
| `Amazon.Lambda.Core` | 1.2.0 | `402beb4` |
| `Amazon.Lambda.Serialization.Json` | 1.8.0 | `402beb4` |
| `Amazon.Lambda.AspNetCoreServer` | 5.3.0 | `402beb4` |
| `MySql.Data` | 8.0.23 | `f5b7278` |
| `Newtonsoft.Json` | 12.0.3 | `402beb4` |

`Handler.cs` imports `Amazon.Lambda.APIGatewayEvents`. There is no direct package reference with that id. This inspection did not restore NuGet packages, so the compile closure is **Unknown**.

Global tools named in docs, not in the project file:

| Tool | Version in repo |
|---|---|
| Serverless Framework CLI | README says greater than 1.5. No version pin |
| .NET SDK | README says `dotnet` greater than 3.1. Project targets `netcoreapp3.1` |
| `Amazon.Lambda.Tools` | README expected list: 4.0.0. Not installed by `setup.sh` |
| `Amazon.Lambda.TestTool-3.1` | `setup.sh`: 0.9.5. README expected list: 0.10.0 |

`dotnet lambda package` requires `Amazon.Lambda.Tools` on the machine that runs `build.cmd` or `build.sh`.

Renovate config is `config:base` only. No lockfile exists (`packages.lock.json` is not in the tree). Floating restores are possible. **Unknown** whether a committed lockfile was ever intended.

.NET Core 3.1 and the Lambda runtime `dotnetcore3.1` are out of vendor support. Those support dates are not written in the repository.

## Data

One SQL statement, in `HelloWorld`:

```text
SELECT * FROM `sysUser`
```

Connection, **Implemented** as a literal:

| Field | Value |
|---|---|
| Server | `qaunity.cehgxa1eerul.eu-west-1.rds.amazonaws.com` |
| User | `qaunity` |
| Password | present in `Handler.cs`; omitted here |
| Database | `qaunity` |

`MySqlConnection` is opened with `con.Open()`. The command uses `ExecuteScalar()`. The connection is disposed with `using var`. There is no transaction, retry, timeout override, or connection pool setting.

No migration, no `CREATE TABLE`, and no column list. Columns of `sysUser` are **Unknown**. `ExecuteScalar` returns the first column of the first row only. The `SELECT *` still asks the server for a full row projection.

The scalar is inserted as a dictionary key. `CreateResponse` serializes that dictionary with Newtonsoft.Json. A successful body looks like `{ "<scalar>": "" }`. The hello/world body is commented out.

`GetQuerystring` serializes `request.QueryStringParameters` (`IDictionary<string, string>` on the API Gateway request type). It does not write to a database.

## HTTP behaviour

`CreateResponse`:

| Result | Status | Body | Headers |
|---|---|---|---|
| Non-null dictionary | 200 | JSON object | `Content-Type: application/json`, `Access-Control-Allow-Origin: *` |
| Null | 500 | empty string | same headers |

`HelloWorld` has no `try/catch`. Failures propagate to the Lambda runtime. This repo does not map those to an HTTP status.

`GetQuerystring` catches exceptions only after it has already touched `QueryStringParameters.Count` and only around the `foo` lookup and the success response. See business rule BR-005.

Logging goes to `ILambdaContext.Logger` (CloudWatch for a deployed function). No log library, no correlation id besides `AwsRequestId` on the `GetQuerystring` path, no metric or trace SDK.

## Authentication

None in the template or the handler. No JWT, no IAM authorizer, no API key, no Cognito resource. The database uses a MySQL user and password, not RDS IAM authentication.

## Build

`build.cmd`:

```text
dotnet restore
dotnet lambda package --configuration release --framework netcoreapp3.1 --output-package bin/release/netcoreapp3.1/hello.zip
```

`build.sh`:

- If `/etc/debian_version` exists, `apt` installs `zip` (the comment says the Microsoft .NET container has no zip).
- `dotnet restore`
- `dotnet lambda package --configuration Debug --framework netcoreapp3.1 --output-package bin/release/netcoreapp3.1/hello.zip`

The output directory is named `release` in both scripts because `--output-package` says so. The compiler configuration is `release` on Windows and `Debug` on the shell script. `.gitignore` ignores `[Bb]in/` and `[Oo]bj/`, so the zip is a local deploy input, not a git object.

`.vscode/tasks.json` runs `dotnet build` with problem matcher `$msCompile`. That build is for the debugger. It is not the Serverless artifact step.

No CI configuration was found. Nothing in git runs tests, Sonar, or a pipeline.

## Local debug

| File | Role |
|---|---|
| `setup.sh` | `dotnet tool install --global Amazon.Lambda.TestTool-3.1 --version 0.9.5` |
| `Properties/launchSettings.json` | Profile `Mock Lambda Test Tool`, executable under `%USERPROFILE%\.dotnet\tools\`, args `--port 5050`, working directory `.\bin\$(Configuration)\netcoreapp3.1` |
| `.vscode/launch.json` | `coreclr` launch named `.NET Core Launch (console)`, `preLaunchTask` `build`, `program` still `/Users/{user}/.dotnet/tools/dotnet-lambda-test-tool-3.1` |
| README | Says to replace `{user}`, press F5, execute a function, expect hello world |

The VS Code `program` path uses a Unix-style `/Users/{user}` path in both the Windows and the Mac/Linux README examples. The Visual Studio profile uses `%USERPROFILE%\.dotnet\tools\dotnet-lambda-test-tool-3.1.exe`. Those are different paths for the same tool.

`HelloWorld` will try the real `qaunity` database during a local execute. The connection string does not switch on an environment name.

## Deployment and infrastructure

Deploy, as documented, creates a CloudFormation stack via the Serverless Framework. The README sample names the stack `myService-dev` and region `us-east-1`. The service field in the file is `ozow-lambda-test`, so a default-stage deploy would be named `ozow-lambda-test-dev` if Serverless naming is the usual `{service}-{stage}`. That stack name is **Inferred** from the service field plus the README's `dev` stage. It was not confirmed in AWS.

Resources the template will create are whatever Serverless generates for two Lambda functions, one shared zip, and two API Gateway GET methods, plus the default log groups and IAM execution role. No extra IAM statements are active, so the role is the framework default (CloudWatch logs). RDS network access is not declared. If the database is private, `HelloWorld` cannot open it from a Lambda that has no VPC. Whether the RDS instance is public is **Unknown / Requires Confirmation**.

Destroy is documented as `sls remove`.

There is no Terraform, no CDK, no Docker, and no environment-specific config file.

## Security

Observed in the tree:

- A database password is committed in `Handler.cs` and remains in history from `f5b7278`. It is omitted from Silicon Ark. Treat it as exposed.
- Both routes are unauthenticated.
- CORS origin on handler responses is `*`.
- `HelloWorld` returns a `sysUser` scalar to that unauthenticated route, with no row filter.
- `GetQuerystring` reflects caller-supplied query parameters into the JSON body and into CloudWatch (`foo`'s value is logged).
- No secret store, no `.env`, no encryption setting, and no `.pfx` (the gitignore excludes `*.pfx` and `*.publishsettings`).

Not observed: rate limiting, authorizer, VPC, security-group rules, WAF, or a dependency audit in CI.

## Testing

No test project and no test source file. The README's tests are manual:

- Lambda Test Tool, function dropdown, sample JSON for `getquerystring`.
- After deploy: Postman or `curl` against `/hello` and `/getquerystring?foo=test`.

This inspection did not build, deploy, or call the API.

## Configuration reference

| Location | Key | Value at `ca18f8f` |
|---|---|---|
| `serverless.yml` | `service` | `ozow-lambda-test` |
| `serverless.yml` | `provider.runtime` | `dotnetcore3.1` |
| `serverless.yml` | function artifact | `bin/release/netcoreapp3.1/hello.zip` |
| `aws-lambda-tools.default.json` | `profile` | `unity` |
| `aws-lambda-tools.default.json` | `region` | `eu-west-1` |
| `aws-lambda-tools.default.json` | `configuration` | `Release` |
| `aws-lambda-tools.default.json` | `framework` | `netcoreapp3.1` |
| `aws-lambda-tools.default.json` | `template` | `serverless.yml` |
| `Handler.cs` | MySQL server | `qaunity.cehgxa1eerul.eu-west-1.rds.amazonaws.com` |
| `Handler.cs` | MySQL database and user | `qaunity` |
| README Silicon sequence | deploy profile | `ozow` |
| README Silicon sequence | example API host | `4row8qyxh1.execute-api.us-east-1.amazonaws.com` |
| `Properties/launchSettings.json` | test tool port | `5050` |
| `setup.sh` | test tool version | `0.9.5` |
| `renovate.json` | extends | `config:base` |
