diff --git a/CSharp/GettingStarted/01_HelloWorld/HelloWorld.csproj b/CSharp/GettingStarted/01_HelloWorld/HelloWorld.csproj
index 882a976..c80e8d7 100644
--- a/CSharp/GettingStarted/01_HelloWorld/HelloWorld.csproj
+++ b/CSharp/GettingStarted/01_HelloWorld/HelloWorld.csproj
@@ -2,25 +2,14 @@
Exe
- net462
- Microsoft.Azure.Batch.Samples.HelloWorld
+ net8.0
+ Azure.Compute.Batch.Samples.HelloWorld
-
-
-
-
-
-
-
-
-
-
-
-
- PreserveNewest
-
+
+
+
\ No newline at end of file
diff --git a/CSharp/GettingStarted/01_HelloWorld/HelloWorld.sln b/CSharp/GettingStarted/01_HelloWorld/HelloWorld.sln
index 67cb5a4..6308683 100644
--- a/CSharp/GettingStarted/01_HelloWorld/HelloWorld.sln
+++ b/CSharp/GettingStarted/01_HelloWorld/HelloWorld.sln
@@ -1,12 +1,10 @@
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26430.12
+# Visual Studio Version 17
+VisualStudioVersion = 17.9.34728.123
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloWorld", "HelloWorld.csproj", "{FE62D509-B9A9-4592-81BB-779306C22F95}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Batch.Samples.Common", "..\..\Common\Microsoft.Azure.Batch.Samples.Common.csproj", "{612B170A-1697-4C40-BD57-26A6C8AC6534}"
-EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -17,12 +15,11 @@ Global
{FE62D509-B9A9-4592-81BB-779306C22F95}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE62D509-B9A9-4592-81BB-779306C22F95}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE62D509-B9A9-4592-81BB-779306C22F95}.Release|Any CPU.Build.0 = Release|Any CPU
- {612B170A-1697-4C40-BD57-26A6C8AC6534}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {612B170A-1697-4C40-BD57-26A6C8AC6534}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {612B170A-1697-4C40-BD57-26A6C8AC6534}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {612B170A-1697-4C40-BD57-26A6C8AC6534}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {33B77A65-5D1C-46B7-918E-D922919D6884}
+ EndGlobalSection
EndGlobal
diff --git a/CSharp/GettingStarted/01_HelloWorld/HelloWorldSample.cs b/CSharp/GettingStarted/01_HelloWorld/HelloWorldSample.cs
new file mode 100644
index 0000000..43356b1
--- /dev/null
+++ b/CSharp/GettingStarted/01_HelloWorld/HelloWorldSample.cs
@@ -0,0 +1,150 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+
+using Azure.Core;
+using Azure.Identity;
+using Azure.ResourceManager;
+using Azure.ResourceManager.Batch;
+using Azure.ResourceManager.Batch.Models;
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace Azure.Compute.Batch.Samples.HelloWorld
+{
+ public class HelloWorldSample
+ {
+ private ArmClient _armClient;
+ private BatchClient _batchClient;
+
+ ///
+ /// Creates a pool with a configurable number of nodes, then submits tasks which print a 'Hello world' message.
+ /// The resulting stdout.txt or stderr.txt (depending on each task's exit code) is then printed to the console.
+ ///
+ /// After running, the job will be terminated and the pool will be deleted.
+ ///
+ /// The ARM resource ID of the Batch account.
+ /// A task which completes when the sample has finished running.
+ public async Task Run(string batchAccountResourceId)
+ {
+ var batchAccountIdentifier = ResourceIdentifier.Parse(batchAccountResourceId);
+
+ var credential = new DefaultAzureCredential();
+ _armClient = new ArmClient(credential);
+
+ BatchAccountResource batchAccount = await _armClient.GetBatchAccountResource(batchAccountIdentifier).GetAsync();
+
+ _batchClient = new BatchClient(new Uri($"https://{batchAccount.Data.AccountEndpoint}"), credential);
+
+ var poolName = GenerateUniqueName("HelloWorldPool");
+ var imageReference = new BatchImageReference()
+ {
+ Publisher = "canonical",
+ Offer = "0001-com-ubuntu-server-jammy",
+ Sku = "22_04-lts",
+ Version = "latest"
+ };
+ string nodeAgentSku = "batch.node.ubuntu 22.04";
+
+ BatchAccountPoolResource pool = (await batchAccount.GetBatchAccountPools().CreateOrUpdateAsync(WaitUntil.Completed, poolName, new BatchAccountPoolData()
+ {
+ VmSize = "Standard_DS1_v2",
+ DeploymentConfiguration = new BatchDeploymentConfiguration()
+ {
+ VmConfiguration = new BatchVmConfiguration(imageReference, nodeAgentSku)
+ },
+ ScaleSettings = new BatchAccountPoolScaleSettings()
+ {
+ FixedScale = new BatchAccountFixedScaleSettings()
+ {
+ TargetDedicatedNodes = 1
+ }
+ }
+ })).Value;
+
+ string jobId = GenerateUniqueName("HelloWorldJob");
+
+ try
+ {
+ await _batchClient.CreateJobAsync(new BatchJobCreateContent(jobId, new BatchPoolInfo() { PoolId = poolName }));
+
+ for (int i = 0; i < 5; i++)
+ {
+ string taskId = $"task-{i}";
+ Console.WriteLine("Submitting {0}", taskId);
+ await _batchClient.CreateTaskAsync(jobId, new BatchTaskCreateContent(taskId, $"echo Hello world from {taskId}"));
+ }
+
+ Console.WriteLine("Waiting for all tasks to complete on job: {0} ...", jobId);
+ await waitForTasksToComplete(jobId);
+
+ var completedTasks = _batchClient.GetTasksAsync(jobId, filter: "state eq 'completed'");
+ await foreach (BatchTask t in completedTasks)
+ {
+ var outputFileName = t.ExecutionInfo.ExitCode == 0 ? "stdout.txt" : "stderr.txt";
+
+ Console.WriteLine("Task {0} exited with code {1}. Output ({2}):",
+ t.Id, t.ExecutionInfo.ExitCode, outputFileName);
+
+ BinaryData fileContents = await _batchClient.GetTaskFileAsync(jobId, t.Id, outputFileName);
+ using (var reader = new StreamReader(fileContents.ToStream()))
+ {
+ Console.WriteLine(await reader.ReadLineAsync());
+ }
+ }
+ }
+ finally
+ {
+ Console.WriteLine("Terminating job {0} and deleting pool {1}", jobId, poolName);
+ await Task.WhenAll([
+ _batchClient.TerminateJobAsync(jobId),
+ pool.DeleteAsync(WaitUntil.Completed)]);
+ }
+ }
+
+ ///
+ /// Poll all the tasks in the given job and wait for them to reach the completed state.
+ ///
+ /// The ID of the job to poll
+ /// A task that will complete when all Batch tasks have completed.
+ /// Thrown if all tasks haven't reached the completed state after a certain period of time
+ private async Task waitForTasksToComplete(String jobId)
+ {
+ // Note that this timeout should take into account the time it takes for the pool to scale up
+ var timeoutAfter = DateTime.Now.AddMinutes(10);
+ while (DateTime.Now < timeoutAfter)
+ {
+ var allComplete = true;
+ var tasks = _batchClient.GetTasksAsync(jobId, select: ["id", "state"]);
+ await foreach (BatchTask task in tasks)
+ {
+ if (task.State != BatchTaskState.Completed)
+ {
+ allComplete = false;
+ break;
+ }
+ }
+
+ if (allComplete)
+ {
+ return;
+ }
+
+ await Task.Delay(10000);
+ }
+
+ throw new TimeoutException("Task(s) did not complete within the specified time");
+ }
+
+ ///
+ /// Generate a unique name with the given prefix using the current user name and a timestamp.
+ ///
+ /// The name's prefix.
+ /// The generated name.
+ private static string GenerateUniqueName(string prefix)
+ {
+ string currentUser = new string(Environment.UserName.Where(char.IsLetterOrDigit).ToArray());
+ return string.Format("{0}-{1}-{2}", prefix, currentUser, DateTime.Now.ToString("yyyyMMdd-HHmmss"));
+ }
+ }
+}
diff --git a/CSharp/GettingStarted/01_HelloWorld/Program.cs b/CSharp/GettingStarted/01_HelloWorld/Program.cs
index 3a07942..bf0338e 100644
--- a/CSharp/GettingStarted/01_HelloWorld/Program.cs
+++ b/CSharp/GettingStarted/01_HelloWorld/Program.cs
@@ -1,176 +1,23 @@
-//Copyright (c) Microsoft Corporation
+// Copyright (c) Microsoft Corporation. All rights reserved.
-namespace Microsoft.Azure.Batch.Samples.HelloWorld
-{
- using System;
- using System.IO;
- using System.Collections.Generic;
- using System.Threading.Tasks;
- using Auth;
- using Batch.Common;
- using Common;
- using Microsoft.Extensions.Configuration;
+using System;
+using System.Threading.Tasks;
+namespace Azure.Compute.Batch.Samples.HelloWorld
+{
///
/// The main program of the HelloWorld sample
///
public static class Program
{
- public static void Main(string[] args)
- {
- try
- {
- AccountSettings accountSettings = SampleHelpers.LoadAccountSettings();
- Settings helloWorldSettings = new ConfigurationBuilder()
- .SetBasePath(Directory.GetCurrentDirectory())
- .AddJsonFile("settings.json")
- .Build()
- .Get();
-
- HelloWorldAsync(accountSettings, helloWorldSettings).Wait();
- }
- catch (AggregateException aggregateException)
- {
- // Go through all exceptions and dump useful information
- foreach (Exception exception in aggregateException.InnerExceptions)
- {
- Console.WriteLine(exception.ToString());
- Console.WriteLine();
- }
+ private static string batchAccountResourceId = "your-batch-account-resource-id";
- throw;
- }
+ public async static Task Main(string[] args)
+ {
+ await new HelloWorldSample().Run(batchAccountResourceId);
Console.WriteLine("Press return to exit...");
Console.ReadLine();
}
-
- ///
- /// Submits a job to the Azure Batch service, and waits for it to complete
- ///
- private static async Task HelloWorldAsync(
- AccountSettings accountSettings,
- Settings helloWorldConfigurationSettings)
- {
- Console.WriteLine("Running with the following settings: ");
- Console.WriteLine("-------------------------------------");
- Console.WriteLine(helloWorldConfigurationSettings.ToString());
- Console.WriteLine(accountSettings.ToString());
-
- // Set up the Batch Service credentials used to authenticate with the Batch Service.
- BatchSharedKeyCredentials credentials = new BatchSharedKeyCredentials(
- accountSettings.BatchServiceUrl,
- accountSettings.BatchAccountName,
- accountSettings.BatchAccountKey);
-
- // Get an instance of the BatchClient for a given Azure Batch account.
- using (BatchClient batchClient = BatchClient.Open(credentials))
- {
- // add a retry policy. The built-in policies are No Retry (default), Linear Retry, and Exponential Retry
- batchClient.CustomBehaviors.Add(RetryPolicyProvider.ExponentialRetryProvider(TimeSpan.FromSeconds(5), 3));
-
- string jobId = GettingStartedCommon.CreateJobId("HelloWorldJob");
-
- try
- {
- // Submit the job
- await SubmitJobAsync(batchClient, helloWorldConfigurationSettings, jobId);
-
- // Wait for the job to complete
- await WaitForJobAndPrintOutputAsync(batchClient, jobId);
- }
- finally
- {
- // Delete the job to ensure the tasks are cleaned up
- if (!string.IsNullOrEmpty(jobId) && helloWorldConfigurationSettings.ShouldDeleteJob)
- {
- Console.WriteLine("Deleting job: {0}", jobId);
- await batchClient.JobOperations.DeleteJobAsync(jobId);
- }
- }
- }
- }
-
- ///
- /// Creates a job and adds a task to it.
- ///
- /// The BatchClient to use when interacting with the Batch service.
- /// The configuration settings
- /// The ID of the job.
- /// An asynchronous representing the operation.
- private static async Task SubmitJobAsync(
- BatchClient batchClient,
- Settings configurationSettings,
- string jobId)
- {
- // create an empty unbound Job
- CloudJob unboundJob = batchClient.JobOperations.CreateJob();
- unboundJob.Id = jobId;
-
- // For this job, ask the Batch service to automatically create a pool of VMs when the job is submitted.
- unboundJob.PoolInformation = new PoolInformation()
- {
- AutoPoolSpecification = new AutoPoolSpecification()
- {
- AutoPoolIdPrefix = "HelloWorld",
- PoolSpecification = new PoolSpecification()
- {
- TargetDedicatedComputeNodes = configurationSettings.PoolTargetNodeCount,
- VirtualMachineSize = configurationSettings.PoolNodeVirtualMachineSize,
- VirtualMachineConfiguration = new VirtualMachineConfiguration(
- imageReference: new ImageReference(
- publisher: configurationSettings.ImagePublisher,
- offer: configurationSettings.ImageOffer,
- sku: configurationSettings.ImageSku,
- version: configurationSettings.ImageVersion
- ),
- nodeAgentSkuId: configurationSettings.NodeAgentSkuId),
- },
- KeepAlive = false,
- PoolLifetimeOption = PoolLifetimeOption.Job
- }
- };
-
- // Commit Job to create it in the service
- await unboundJob.CommitAsync();
-
- // create a simple task. Each task within a job must have a unique ID
- await batchClient.JobOperations.AddTaskAsync(jobId, new CloudTask("task1", "cmd /c echo Hello world from the Batch Hello world sample!"));
- }
-
- ///
- /// Waits for all tasks under the specified job to complete and then prints each task's output to the console.
- ///
- /// The BatchClient to use when interacting with the Batch service.
- /// The ID of the job.
- /// An asynchronous representing the operation.
- private static async Task WaitForJobAndPrintOutputAsync(BatchClient batchClient, string jobId)
- {
- Console.WriteLine("Waiting for all tasks to complete on job: {0} ...", jobId);
-
- // We use the task state monitor to monitor the state of our tasks -- in this case we will wait for them all to complete.
- TaskStateMonitor taskStateMonitor = batchClient.Utilities.CreateTaskStateMonitor();
-
- List ourTasks = await batchClient.JobOperations.ListTasks(jobId).ToListAsync();
-
- // Wait for all tasks to reach the completed state.
- // If the pool is being resized then enough time is needed for the nodes to reach the idle state in order
- // for tasks to run on them.
- await taskStateMonitor.WhenAll(ourTasks, TaskState.Completed, TimeSpan.FromMinutes(10));
-
- // dump task output
- foreach (CloudTask t in ourTasks)
- {
- Console.WriteLine("Task {0}", t.Id);
-
- //Read the standard out of the task
- NodeFile standardOutFile = await t.GetNodeFileAsync(Constants.StandardOutFileName);
- string standardOutText = await standardOutFile.ReadAsStringAsync();
- Console.WriteLine("Standard out:");
- Console.WriteLine(standardOutText);
-
- Console.WriteLine();
- }
- }
}
}
diff --git a/CSharp/GettingStarted/01_HelloWorld/Settings.cs b/CSharp/GettingStarted/01_HelloWorld/Settings.cs
deleted file mode 100644
index cb7d6d7..0000000
--- a/CSharp/GettingStarted/01_HelloWorld/Settings.cs
+++ /dev/null
@@ -1,38 +0,0 @@
-namespace Microsoft.Azure.Batch.Samples.HelloWorld
-{
- using System.Text;
- using Common;
-
- public partial class Settings
- {
- public string PoolId { get; set; }
- public int PoolTargetNodeCount { get; set; }
- public string PoolOSFamily { get; set; }
- public string PoolNodeVirtualMachineSize { get; set; }
- public bool ShouldDeleteJob { get; set; }
- public string ImagePublisher { get; set; }
- public string ImageOffer { get; set; }
- public string ImageSku { get; set; }
- public string ImageVersion { get; set; }
- public string NodeAgentSkuId { get; set; }
-
- public override string ToString()
- {
- StringBuilder stringBuilder = new StringBuilder();
-
- SampleHelpers.AddSetting(stringBuilder, "PoolId", this.PoolId);
- SampleHelpers.AddSetting(stringBuilder, "PoolTargetNodeCount", this.PoolTargetNodeCount);
- SampleHelpers.AddSetting(stringBuilder, "PoolOSFamily", this.PoolOSFamily);
- SampleHelpers.AddSetting(stringBuilder, "PoolNodeVirtualMachineSize", this.PoolNodeVirtualMachineSize);
- SampleHelpers.AddSetting(stringBuilder, "ShouldDeleteJob", this.ShouldDeleteJob);
- SampleHelpers.AddSetting(stringBuilder, "ImagePublisher", this.ImagePublisher);
- SampleHelpers.AddSetting(stringBuilder, "ImageOffer", this.ImageOffer);
- SampleHelpers.AddSetting(stringBuilder, "ImageSku", this.ImageSku);
- SampleHelpers.AddSetting(stringBuilder, "ImageVersion", this.ImageVersion);
- SampleHelpers.AddSetting(stringBuilder, "NodeAgentSkuId", this.NodeAgentSkuId);
-
-
- return stringBuilder.ToString();
- }
- }
-}
diff --git a/CSharp/GettingStarted/01_HelloWorld/settings.json b/CSharp/GettingStarted/01_HelloWorld/settings.json
deleted file mode 100644
index 39747d6..0000000
--- a/CSharp/GettingStarted/01_HelloWorld/settings.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "poolTargetNodeCount": 2,
- "poolNodeVirtualMachineSize": "standard_d2_v3",
- "poolOSFamily": "5",
- "poolId": "HelloWorld-Pool",
- "shouldDeleteJob": true,
- "imagePublisher": "MicrosoftWindowsServer",
- "imageOffer": "WindowsServer",
- "imageSku": "2016-Datacenter-smalldisk",
- "imageVersion": "latest",
- "nodeAgentSkuId": "batch.node.windows amd64"
-}