Skip to content

.NET: Hosted-Files sample + AgentSessionFiles SDK companion + integration test#5698

Open
rogerbarreto wants to merge 10 commits intomicrosoft:mainfrom
rogerbarreto:issues/5691-net-hosted-files
Open

.NET: Hosted-Files sample + AgentSessionFiles SDK companion + integration test#5698
rogerbarreto wants to merge 10 commits intomicrosoft:mainfrom
rogerbarreto:issues/5691-net-hosted-files

Conversation

@rogerbarreto
Copy link
Copy Markdown
Member

Closes #5691.

What

Adds a .NET parallel of the Python 06_files Hosted Agents sample plus a code-first companion that exercises the alpha Azure.AI.Projects.AgentSessionFiles SDK, and an end-to-end integration test in the new Foundry.Hosting.IntegrationTests harness (#5598).

Why

Issue #5691 asks for a .NET Hosted Agents - File Sample paralleling the Python one. The new Azure.AI.Projects 2.1.0-beta.1 ships an alpha AgentSessionFiles API for managing per-session sandbox files; we showcase it here as the code-first equivalent of azd ai agent files upload.

Changes

  • samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/ — server agent with three local function tools (GetHomeDirectory, ListFiles, ReadFile) reading from the per-session $HOME sandbox volume. Mirrors python 06_files.
  • samples/.../Using-Samples/SessionFilesClient/ — REPL companion using AgentSessionFiles (upload / ls / download / rm) and the explicit-isolation-key session lifecycle from Sample_SessionFiles.md.
  • tests/Foundry.Hosting.IntegrationTests — adds a session-files scenario alongside the other six in the multi-scenario harness:
    • TestContainer/Program.cs — new CreateSessionFilesAgent switch case + the same three file tools.
    • Fixtures/SessionFilesHostedAgentFixture.cs — sets IT_SCENARIO=session-files.
    • SessionFilesHostedAgentTests.csUploadAndAgentReadsFileAsync exercises the full flow: create session with isolation key, upload, list, invoke agent (with agent_session_id pinned via CreateResponseOptions.Patch), assert the response contains a deterministic token from the file, cleanup.
    • scripts/it-bootstrap-agents.ps1 + README.mdsession-files added to the scenario list.
    • Foundry.Hosting.IntegrationTests.csprojAzure.AI.Projects 2.1.0-beta.1 override; testdata linked from the sample so there is one source of truth.
  • agent-framework-dotnet.slnx — registers the two new sample projects.

Validation

  • dotnet format --verify-no-changes (CI parity via mcr.microsoft.com/dotnet/sdk:10.0 Docker) on all four changed projects: clean.
  • dotnet build on all four projects: clean.
  • Live IT against tao-foundry-prj (image pushed to acrhostedagenttao, it-session-files agent bootstrapped + RBAC propagated): UploadAndAgentReadsFileAsync passed in 35 s.
  • Full Foundry.Hosting.IntegrationTests: 25 / 6 passed / 19 skipped (existing placeholders) / 0 failed.
  • Full Foundry.IntegrationTests: 67 / 43 passed / 24 skipped / 0 failed (no regression).

… + integration test

Closes microsoft#5691

- Hosted-Files server sample (mirrors python 06_files): 3 local tools reading
  the per-session \C:\Users\rbarreto sandbox volume.
- SessionFilesClient REPL companion: code-first equivalent of
  �zd ai agent files upload using the alpha
  Azure.AI.Projects.AgentSessionFiles SDK (upload/ls/download/rm + session
  lifecycle with isolation key).
- session-files scenario added to the Foundry.Hosting.IntegrationTests
  multi-scenario harness (PR microsoft#5598): SessionFilesHostedAgentFixture +
  SessionFilesHostedAgentTests.UploadAndAgentReadsFileAsync, end-to-end
  validating upload then agent-reads-file (agent_session_id pinned via
  CreateResponseOptions.Patch). Bundled testdata is linked from the sample
  so there is a single source of truth.
Copilot AI review requested due to automatic review settings May 7, 2026 15:00
@moonbox3 moonbox3 added documentation Improvements or additions to documentation .NET labels May 7, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a .NET “Hosted-Files” hosted-agent sample (mirroring Python 06_files), a code-first REPL companion using the alpha Azure.AI.Projects.Agents.AgentSessionFiles API, and a new end-to-end session-files scenario in the Foundry.Hosting integration test harness.

Changes:

  • Introduces a Hosted-Files sample agent with local function tools that read from the per-session $HOME sandbox volume.
  • Adds SessionFilesClient, a console REPL to upload/list/download/delete per-session sandbox files via AgentSessionFiles.
  • Extends Foundry.Hosting.IntegrationTests with a new session-files scenario (fixture, container branch, and E2E test), plus bootstrap script + docs updates.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
dotnet/tests/Foundry.Hosting.IntegrationTests/SessionFilesHostedAgentTests.cs New E2E test that creates a session, uploads a file via AgentSessionFiles, pins agent_session_id, and asserts the agent reads the file.
dotnet/tests/Foundry.Hosting.IntegrationTests/Fixtures/SessionFilesHostedAgentFixture.cs New fixture selecting IT_SCENARIO=session-files.
dotnet/tests/Foundry.Hosting.IntegrationTests/Foundry.Hosting.IntegrationTests.csproj Adds Azure.AI.Projects override and links shared test data from the sample.
dotnet/tests/Foundry.Hosting.IntegrationTests/README.md Documents the new session-files scenario.
dotnet/tests/Foundry.Hosting.IntegrationTests/scripts/it-bootstrap-agents.ps1 Adds session-files to the stable agent bootstrap list.
dotnet/tests/Foundry.Hosting.IntegrationTests.TestContainer/Program.cs Wires a new session-files agent branch and exposes file tools (GetHomeDirectory, ListFiles, ReadFile).
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/Program.cs New hosted agent sample implementing the file tools against $HOME.
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/README.md Sample documentation including how to upload files and invoke the agent.
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/HostedFiles.csproj New web sample project configuration and dependencies.
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/resources/contoso_q1_2026_report.txt Shared deterministic sample test data.
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/Dockerfile Standard container build for end-users (NuGet-based scenario).
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/Dockerfile.contributor Contributor-oriented container workflow (pre-published output).
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/.dockerignore Docker context hygiene for the sample.
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/agent.yaml Hosted agent deployment descriptor.
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/agent.manifest.yaml Agent manifest metadata for discovery/gallery use.
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/.env.example Local/dev environment variable template.
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/SessionFilesClient/Program.cs New REPL implementing upload/ls/download/rm against a specific session.
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/SessionFilesClient/README.md REPL usage and CLI parity documentation.
dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/SessionFilesClient/SessionFilesClient.csproj New console sample project configuration and dependencies.
dotnet/agent-framework-dotnet.slnx Registers the two new sample projects in the solution.

Comment thread dotnet/tests/Foundry.Hosting.IntegrationTests/SessionFilesHostedAgentTests.cs Outdated
Comment thread dotnet/tests/Foundry.Hosting.IntegrationTests/SessionFilesHostedAgentTests.cs Outdated
Comment thread dotnet/tests/Foundry.Hosting.IntegrationTests/SessionFilesHostedAgentTests.cs Outdated
Comment thread dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/README.md Outdated
Comment thread dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/Program.cs Outdated
Comment thread dotnet/tests/Foundry.Hosting.IntegrationTests.TestContainer/Program.cs Outdated
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated Code Review

Reviewers: 4 | Confidence: 87%

✓ Correctness

The PR adds a well-structured session-files sample, companion REPL, and integration test that correctly follows established patterns in the codebase. The test properly uses the HostedAgentFixture infrastructure, ChatClientAgentRunOptions for injecting agent_session_id via JSON patch, and the standard Azure SDK ClientResult implicit conversion pattern. No correctness bugs found in the logic, error handling, or API usage.

✓ Security Reliability

The PR is well-structured with proper resource cleanup and timeout handling. The primary security concern is that ResolveSessionPath in both the sample and test container accepts absolute paths and .. traversals without validation, unlike the framework's own FileSystemAgentFileStore.ResolveSafePath which canonicalizes and prefix-checks. In the intended deployment (isolated per-session container), this is mitigated by isolation. However, when run locally with dotnet run (as the README instructs for development), the LLM's tool calls can read arbitrary files from the developer's machine — exploitable via indirect prompt injection through uploaded file content.

✓ Test Coverage

The test coverage for this PR is solid. The integration test UploadAndAgentReadsFileAsync exercises the complete end-to-end flow: session creation, file upload with byte-count verification, file listing with multi-field assertion, agent invocation with session pinning via JsonPatch, and content verification using a deterministic token from the test data file. Assertions are meaningful (not just 'no exception' checks), cleanup is handled properly in finally blocks, and the test infrastructure reuse (HostedAgentFixture base class, TestConfiguration, TestAzureCliCredentials) is consistent with existing patterns. The test container correctly registers the three file tools only with the session-files scenario agent. No blocking issues found.

✗ Design Approach

I found one design-level issue. The new SessionFilesClient sample reimplements “latest deployed version” selection by lexicographically comparing version strings, which can silently choose the wrong agent version once version numbers reach double digits. The rest of the hosted-files sample and integration-test wiring lines up with the repo’s existing hosted-agent patterns.

Flagged Issues

  • dotnet/samples/04-hosting/FoundryHostedAgents/responses/Using-Samples/SessionFilesClient/Program.cs:263 picks the latest version with string.CompareOrdinal(version.Version, latest.Version), so a deployed set like versions 2 and 10 will incorrectly resolve to 2. The repo already uses the service-provided latest-version path instead: dotnet/src/Microsoft.Agents.AI.Workflows.Declarative.Foundry/AzureAgentProvider.cs:152-160 and dotnet/samples/02-agents/AgentProviders/Agent_With_AzureAIProject/Program.cs:42-46.

Automated review by rogerbarreto's agents

Comment thread dotnet/samples/04-hosting/FoundryHostedAgents/responses/Hosted-Files/Program.cs Outdated
@rogerbarreto rogerbarreto self-assigned this May 7, 2026
@rogerbarreto rogerbarreto moved this to In Progress in Agent Framework May 7, 2026
@rogerbarreto rogerbarreto changed the title .NET: Hosted-Files sample + AgentSessionFiles SDK companion + integration test .NET: Hosted-Files sample + AgentSessionFiles SDK companion + integration test [WIP] May 7, 2026
@rogerbarreto rogerbarreto marked this pull request as draft May 7, 2026 15:20
… end-to-end

Adds an 'ask <prompt>' command to SessionFilesClient that pins
agent_session_id (via CreateResponseOptions.Patch) so the agent invoked from
the REPL reads files this REPL just uploaded. Surfaces the file content as
agent knowledge in the same in-process loop instead of telling the user to
shell out to azd ai agent invoke.
…esClient becomes thin chat REPL

The previous SessionFilesClient leaned on the alpha AgentSessionFiles SDK
to upload files at runtime, which made it diverge from the canonical
Using-Samples shape (SimpleAgent / SimpleInvocationsAgent: tiny chat REPLs).

This change:

- Bakes the sample resources/ directory into the published output via a
  Content Include in HostedFiles.csproj. Inside the container the files live
  at /app/resources/. Two local function tools (ListFiles, ReadFile) surface
  them to the model.
- Reshapes SessionFilesClient as a thin FoundryAgent chat REPL, identical
  shape to SimpleAgent. AGENT_ENDPOINT + AGENT_NAME, that is it.
- Demo flow: user asks 'Give me the total revenue in the contoso file' and
  the agent answers with the figure read from its bundled file. Validated
  end-to-end locally against Hosted-Files on http://localhost:60419.
- Bypasses SampleEnvironment alias on optional env vars to avoid stdin
  prompts when running unattended.

The Foundry.Hosting.IntegrationTests session-files scenario continues to
validate the alpha AgentSessionFiles SDK end-to-end (upload + agent reads
from session HOME) and is unchanged.
…ion-files tools to $HOME

Addresses the path-traversal review comment on the session-files scenario:
ResolveSessionPath in TestContainer used to allow absolute paths and ..
traversals, which (when chained with indirect prompt injection in an
uploaded file) would let the model read or list arbitrary container files
via the ReadFile / ListFiles tools.

Mirrors the canonicalize + StartsWith(home) pattern from the framework's
own FileSystemAgentFileStore.ResolveSafePath: rejects rooted paths, calls
Path.GetFullPath, and verifies the result stays under $HOME, throwing
ArgumentException otherwise.

The Hosted-Files sample is already safe (uses Path.GetFileName which strips
any directory component) so no change there. The integration test continues
to upload and read 'contoso_q1_2026_report.txt', a single relative filename
which passes the new validation unchanged.
The previous test attempted to pin agent_session_id into the /responses
payload via JsonPatch so the agent would read the file uploaded through
AgentSessionFiles. The Foundry alpha service now consistently rejects the
explicit-session-id pin with HTTP 400 conflict on /responses, regardless
of whether the session was pre-created via AgentAdministrationClient or
left to be auto-provisioned, so the agent leg of the test is no longer
reachable from the SDK surface.

Reshape the test to exercise what the alpha SDK actually guarantees:
create session, upload, list (assert presence + size), download (assert
deterministic token), delete (assert removed), cleanup. Everything stays
inside Azure.AI.Projects.Agents.AgentSessionFiles.

Verified live against tao-foundry-prj:
  UploadListDownloadAndDeleteAsync passed in 30s.
  Full Foundry.Hosting.IntegrationTests run: 25 total, 6 passed, 19
  skipped (existing placeholders), 0 failed.
…ent.RunAsync e2e

Per review feedback the integration test must validate the hosted agent
itself: client uploads a file via the alpha AgentSessionFiles SDK, then
FoundryAgent.RunAsync invokes the deployed agent and the agent's
container-side ReadFile tool surfaces the uploaded file content into the
response.

Test flow:
  1. agent.RunAsync(warmup) - platform provisions a per-session container.
  2. AgentAdministrationClient.GetSessionsAsync(latest) - resolve the
     just-provisioned agent_session_id.
  3. AgentSessionFiles.UploadSessionFileAsync - upload contoso file to
     that session, asserts BytesWritten + GetSessionFiles listing.
  4. agent.RunAsync(real prompt, options=PreviousResponseId chain) -
     chained to warmup so the platform routes back to the same container.
  5. Assert response contains '1,482.6' (deterministic token from file).
  6. Best-effort cleanup.

The test is annotated with [Fact(Skip=...)] right now: the Foundry alpha
service consistently returns HTTP 400 conflict on /responses requests
that link to a prior session via previous_response_id, conversation_id,
or agent_session_id pinning - verified across multiple retries with
multiple chaining strategies. Without that link we cannot route the
second invocation to the same container the file was uploaded to. When
the platform regression is resolved, removing the Skip will exercise
the full flow.

Full Foundry.Hosting.IntegrationTests run with this change: 25 total,
5 passed, 20 skipped (existing placeholders + this one), 0 failed.
…ent.RunAsync now passes

The blocker was a routing problem combined with a platform race:

1. Routing two /responses calls to the same per-session container.
   - agent_session_id pin in body -> 400 (platform treats it as create)
   - conversation_id created at project root -> 404 at agent endpoint
   - previous_response_id chain -> different session
   The working answer is to create the conversation on a per-agent
   ProjectOpenAIClient (AgentName option, URL becomes
   /agents/{name}/endpoint/protocols/openai/conversations) and pass that
   conversation_id on both calls. Both then resolve to the SAME
   x-agent-session-id (verified by capturing the response header).

2. Race after AgentSessionFiles upload. The upload mutates session/
   conversation revision; a /responses call issued immediately after
   400-conflicts with 'modified concurrently. Please retry.' Bounded
   exponential retry handles it (5 attempts, 2*attempt seconds).

Test flow:
  1. Create per-agent OpenAI client + ProjectConversationsClient + ProjectResponsesClient.
  2. CreateProjectConversationAsync on the per-agent client.
  3. Warm-up agent.RunAsync(prompt, ChatOptions { ConversationId = ... })
     - captures x-agent-session-id from the response header via a custom pipeline policy.
  4. AgentSessionFiles.UploadSessionFileAsync to that session id.
  5. ProjectResponsesClient.CreateResponseAsync (raw, retry-on-conflict)
     with the same conversation_id -> routes back to the same container.
  6. Assert response contains '1,482.6' (deterministic token from file).
  7. Cleanup: delete file, leave session for TTL.

Verified live against tao-foundry-prj:
  UploadedFile_IsReadByHostedAgentAsync passed in 24.9s.
  Full Foundry.Hosting.IntegrationTests run: 25 total, 6 passed, 19
  skipped (existing placeholders), 0 failed.
@rogerbarreto rogerbarreto moved this from In Progress to In Review in Agent Framework May 7, 2026
@rogerbarreto rogerbarreto marked this pull request as ready for review May 7, 2026 21:51
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated Code Review

Reviewers: 3 | Confidence: 87%

✓ Security Reliability

The PR introduces solid defense-in-depth path traversal protection in the TestContainer's ResolveSessionPath (canonicalize + prefix check). The Hosted-Files sample safely uses Path.GetFileName to strip directory components. Most security issues are already covered by existing review comments. One new finding: the agent.manifest.yaml description and tool list are incorrect for the Hosted-Files sample — they describe the session-files scenario instead.

✓ Test Coverage

The integration test UploadedFile_IsReadByHostedAgentAsync is comprehensive for the happy path (upload → list → invoke → assert deterministic token), with meaningful assertions and bounded retry for platform race conditions. However, there are two notable test coverage gaps: (1) the server-side conversation created by the test is never cleaned up, unlike the established pattern in HappyPathHostedAgentTests which uses try/finally with DeleteConversationAsync, and (2) the ResponseHeaderCapturePolicy helper captures LastRequestBody but no test reads or asserts it, making it dead test code.

✓ Design Approach

I found two design-level mismatches in the new sample set. First, the shipped Hosted-Files manifest advertises a session-sandbox file agent, but the actual implementation only reads baked /app/resources content, so uploaded session files are never reachable through the deployed sample. Second, the new SessionFilesClient companion does not exercise AgentSessionFiles at all; it is just a chat REPL over FoundryAgent, so the PR still lacks the code-first SDK companion described in the change rationale.


Automated review by rogerbarreto's agents

- agent.manifest.yaml: description + tags now reflect bundled-files agent (image-baked /app/resources), not the obsolete session-sandbox tools the prior shape claimed.
- SessionFilesHostedAgentTests: wrap test body in try/finally to call DeleteConversationAsync on the conversation we created (matches HappyPathHostedAgentTests pattern; prevents conversation leakage across runs).
- ResponseHeaderCapturePolicy: drop unused LastRequestBody capture left over from diagnosis.

Test still passes live (40s).
The previous Hosted-Files agent only exposed bundled (image-baked) file
knowledge. The platform also surfaces session-uploaded files at \C:\Users\rbarreto
inside the per-session container per container-image-spec.md line 172
(verified live by SessionFilesHostedAgentTests). The sample now teaches
both patterns.

Two distinct tool pairs, each scoped to its own root:

  Bundled (image-baked):    ListBundledFiles, ReadBundledFile
                            -> /app/resources/ (BUNDLED_FILES_DIR override)

  Session-uploaded (\C:\Users\rbarreto): ListSessionFiles, ReadSessionFile
                            -> \C:\Users\rbarreto (default /home/session per container spec)

Security model -- distinct tools, distinct sandboxes:
  - Tool input is a fileName, not a path. Schema-level: model cannot
    request directories or traversals.
  - Path.GetFileName(input) strips any directory components.
  - Path.GetFullPath + StartsWith(root) check rejects anything outside
    the tool's root, mirroring FileSystemAgentFileStore.ResolveSafePath.
  - Read-only, non-recursive listing. No glob, no '..'.
  - Failures non-revealing: 'File <name> not found in <scope>.'

The two roots are physically isolated (image-baked vs platform-mounted
per-session volume). A bundled-root tool can never reach a session file
and vice-versa, even if the implementation has a bug.

README updated to document both flows, the security pattern, and cite
the container-image-spec.md line 172 contract for \C:\Users\rbarreto. Live IT
SessionFilesHostedAgentTests.UploadedFile_IsReadByHostedAgentAsync
re-passed in 42s after the change (TestContainer is unchanged; the
sample-agent split does not affect the IT).
@rogerbarreto rogerbarreto changed the title .NET: Hosted-Files sample + AgentSessionFiles SDK companion + integration test [WIP] .NET: Hosted-Files sample + AgentSessionFiles SDK companion + integration test May 8, 2026
Copy link
Copy Markdown
Member

@SergeyMenshykh SergeyMenshykh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review — .NET Hosted-Files sample + AgentSessionFiles SDK + integration test

Overall this is a well-structured, thorough PR. The security model (3-layer path traversal defense) is solid, the integration test exercises the full end-to-end flow, and the docs are detailed. A few items to address:


Issues

1. agent.manifest.yaml description is stale
The manifest describes only two tools (ListFiles, ReadFile), but the actual Program.cs exposes four tools: ListBundledFiles, ReadBundledFile, ListSessionFiles, ReadSessionFile. The manifest description should be updated to reflect the dual-source tool surface.

2. SessionFilesClient/README.md references wrong tool names

The agent's container-side ListFiles and ReadFile tools surface the bundled file contents to the model.

These tool names don't exist on the Hosted-Files agent anymore — they should be ListBundledFiles/ReadBundledFile (and ListSessionFiles/ReadSessionFile for session files).

3. Missing trailing newline in Hosted-Files/README.md
The file ends without a newline (line 543 of the diff: \ No newline at end of file). Minor, but will cause noise in future diffs and may trip linters.


Nits / suggestions

  • DevTemporaryTokenCredential is duplicated across samples (also exists in other Hosted-* samples). Consider extracting to a shared helper if the sample set keeps growing — though duplication is acceptable for standalone samples.

  • In SessionFilesHostedAgentTests, the retry loop for the 400 "modified concurrently" race is well-guarded (the 5th attempt's exception propagates naturally), but a brief comment noting why rawResponse is declared null! (the compiler can't see through the retry control flow) would help future readers.


What looks good

  • Path traversal defense: The GetFileNameGetFullPathStartsWith(root + sep) pattern is textbook defense-in-depth, and the controlled error message avoids leaking canonical paths.
  • Separate tool pairs instead of a single ReadFile(path) — excellent attack-surface minimization.
  • Test data sharing: Linking the contoso_q1_2026_report.txt via <Content Include="..." Link="..."> keeps a single source of truth.
  • Retry logic for the platform's concurrent-modification race is pragmatic and bounded.
  • Documentation is thorough — the READMEs, inline comments, and the security rationale in the code header are all high quality.

@rogerbarreto rogerbarreto added this pull request to the merge queue May 8, 2026
@github-merge-queue github-merge-queue Bot removed this pull request from the merge queue due to failed status checks May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation .NET

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

.NET Hosted Agents - File Sample

5 participants