Archive for the ‘csharp’ Category.

Amazon S3 Bucket Management with C#: Part 10 – Uploading all files in a directory recursively to an S3 Bucket

Before getting started

Skill Level: Intermediate

Assumptions:

  1. You already gone through Parts 1-9 of Managing Amazon AWS with C#.

Additional information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • Rhyous.SimpleArgs
  • Single Responsibility Principle (S in S.O.L.I.D.)
  • async, await, parallelism
  • 10/100 rule

Doing things by convention.

Step 1 – Add a method to get the list of files in a local directory

This isn’t the focus of our post, however, in order to upload all files in a directory recursively, we have to be able to list them. We are going to create a method that is 10 lines of code. The method has one single repsponsibility, to return all files in a directory recursively. It is not the responsibility of BucketManager.cs to do this. Hence we need a new class that has this responsibility.

Another reason to move this method to its own file is that this method is itself 10 lines of code. While you can have methods longer than ten lines, more than ten lines is usually the first sign that the Single Responsibility principal is broken. Most beginning developers have a hard time seeing the many ways a method may be breaking the single responsibility principle. So a much easier rule, is the 10/100 rule. In the 10/100 rule, a method can only have 10 lines. This rule is pretty soft. Do brackets count? It doesn’t matter. What matters is that the 10 line mark, with or without brackets, is where you start looking at refactoring the method by splitting it into two or more smaller and simpler methods. This is a a Keep It Super Simple (K.I.S.S.) rule.

  1. Add the following utility class: FileUtils.cs.
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Threading.Tasks;
    
    namespace Rhyous.AmazonS3BucketManager
    {
        public static class FileUtils
        {
            public static async Task<List<string>> GetFiles(string directory, bool recursive)
            {
                var files = Directory.GetFiles(directory).ToList();
                if (!recursive)
                    return files;
                var dirs = Directory.GetDirectories(directory);
                var tasks = dirs.Select(d => GetFiles(d, recursive)).ToList();
                while (tasks.Any())
                {
                    var task = await Task.WhenAny(tasks);
                    files.AddRange(task.Result);
                    tasks.Remove(task);
                }
                return files;
            }
        }
    }
    

Notice: The above class will get all files and directories, recursively. It will do it in parallel. Parallelism likely isn’t needed most of the time. Any non-parallel code that could list files and directories recursively would work. But if you were going to sync directories with tens of thousands of files each, parallelism might be a huge benefit.

Step 2 – Add an UploadFiles method to BucketManager.cs

  1. Edit file called BucketManager.cs.
  2. Enter this new method:
            public static async Task UploadFiles(TransferUtility transferUtility, string bucketName, string directory)
            {
                var files = await FileUtils.GetFiles(directory, true);
                var directoryName = Path.GetFileName(directory); // This is not a typo. GetFileName is correct.            
                var tasks = files.Select(f => UploadFile(transferUtility, bucketName, f, f.Substring(f.IndexOf(directoryName)).Replace('\\', '/')));
                await Task.WhenAll(tasks);
            }
    

Notice 1: We follow the “Don’t Repeat Yourself (DRY) principle by having UploadFiles() forward each file to the singular UploadFile().
Notice 2: We don’t use the await keyword when we redirect each file UploadFile. Instead we capture the returned Task objects and then we will await the completion of each of them.

Step 3 – Update the Action Argument

We should be very good at this by now. We need to make this method a valid action for the Action Argument.

  1. Edit the ArgsHandler.cs file to define an Action argument.
                        ...
                        AllowedValues = new ObservableCollection<string>
                        {
                            "CreateBucket",
                            "CreateBucketDirectory",
                            "CreateTextFile",
                            "DeleteBucket",
                            "DeleteBucketDirectory",
                            "ListFiles",
                            "UploadFile",
                            "UploadFiles"
                        },
                        ...
    

Note: There are enough of these now that I alphabetized them.

Step 4 – Delete the Parameter dictionary

In Part 4, we created a method to pass different parameters to different methods.We took note in Part 8 and Part 9 that we now have more exceptions than we have commonalities. It is time to refactor this.

Another reason to refactor this is because the OnArgumentsHandled method is seriously breaking the 10/100 rule.

Let’s start by deleting what we have.

  1. Delete the Dictionary line from Program.cs.
            static Dictionary<string, object[]> CustomParameters = new Dictionary<string, object[]>();
    
  2. Delete the section where we populated the dictionary.
                // Use the Custom or Common pattern
                CustomParameters.Add("CreateBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });
                CustomParameters.Add("CreateTextFile", new object[] { s3client, bucketName, Args.Value("Filename"), Args.Value("Text") });
                CustomParameters.Add("DeleteBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });
                CustomParameters.Add("DeleteFile", new object[] { transferUtility, bucketName, Args.Value("Filename") });
                CustomParameters.Add("UploadFile", new object[] { transferUtility, bucketName, Args.Value("File"), Args.Value("RemoteDirectory") });
    

Step 5 – Implement parameters by convention

To refactor the parameter passing, To refactor this, we are going use a convention.

A convention is some arbitrary rule that when followed makes the code work. You have to be very careful when using conventions because they are usually not obvious. Because they are not obvious, the first rule of using a convention is this: Conventions must be documented.

The convention is this: Make the Argument names match the method parameters. Argument names are not case sensitive, so we don’t have to worry about case. Just name.

There are two exceptions to this convention. AmazonsS3Client and TransferUtility. We will handle those exceptions statically in code.

Now, let’s implement our convention.

  • For each Argument, make sure the associated parameter is the same name.
    • Change bucketName to bucket in all methods.
    • Change file to filename in the DeleteFile method.
    • Change UploadLocation to RemoteDirectory in the UploadFile method.
    • Change directory to LocalDirectory in the UploadFiles method.
  • Create the following MethodInfoExtension.cs.
    using Amazon;
    using Amazon.S3;
    using Amazon.S3.Transfer;
    using Rhyous.SimpleArgs;
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.Reflection;
    
    namespace Rhyous.AmazonS3BucketManager
    {
        public static class MethodInfoExtensions
        {
            public static List<object> DynamicallyGenerateParameters(this MethodInfo mi)
            {
                var parameterInfoArray = mi.GetParameters();
                var parameters = new List<object>();
                var region = RegionEndpoint.GetBySystemName(ConfigurationManager.AppSettings["AWSRegion"]);
                foreach (var paramInfo in parameterInfoArray)
                {
                    if (paramInfo.ParameterType == typeof(AmazonS3Client) || paramInfo.ParameterType == typeof(TransferUtility))
                        parameters.Add(Activator.CreateInstance(paramInfo.ParameterType, region));
                    if (paramInfo.ParameterType == typeof(string))
                        parameters.Add(Args.Value(paramInfo.Name));
                }
    
                return parameters;
            }
        }
    }
    

    Notice this class will dynamically query the parameters. AmazonS3Client and TransferUtility are exceptions. The rest of the parameters are created using a convention and pulled from Argument values.

  • Update Program.cs to use this new extension method.
            internal static void OnArgumentsHandled()
            {
                var action = Args.Value("Action");
                var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
                MethodInfo mi = typeof(BucketManager).GetMethod(action, flags);
                List<object> parameters = mi.DynamicallyGenerateParameters();
                var task = mi.Invoke(null, parameters.ToArray()) as Task;
                task.Wait();
            }   
    

 

Notice: Look how simple Program.OnArgumentsHandled method has become. By using this convention, and by moving the parameter creation to an extension method, we are down to six lines. The total size for the Program.cs class is 25 lines, including spaces.

You can now move a directory to an Amazon S3 bucket using C#.

<h3>Design Pattern: Facade</h3>

Yes, we have just implement the popular Facade design pattern.

Our project, and most specifically BucketManger.cs, represent an entire system: Amazon S3. When code is written to represent an entire system or substem, that code is called a Facade.

Go to: Rhyous.AmazonS3BucketManager on GitHub to see the full example project from this 10 part tutorial.

Return to: Managing Amazon AWS with C#

Amazon S3 Bucket Management with C#: Part 9 – Uploading a file with its path to a Bucket

Before getting started

Skill Level: Beginner

Assumptions:

  1. You already gone through Parts 1-8 of Managing Amazon AWS with C#.

Additional information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • Rhyous.SimpleArgs

Step 1 – Alter the existing UploadFile method in BucketManager.cs

We need the UploadFile method to take in a parameter that specifies the remote directory, which is the directory path on the S3 bucket. However, if no directory is specified, the key should simply be the file name.

  1. Edit file called BucketManager.cs.
  2. Enter this new method:
    Note: We are in luck, the TransferUtility object has an overload that takes in the key.

            public static async Task UploadFile(TransferUtility transferUtility, string bucketName, string file, string uploadLocation = null)
            {
                var key = Path.GetFileName(file);
                if (!string.IsNullOrWhiteSpace(uploadLocation))
                {
                    uploadLocation = uploadLocation.EndsWith("/") ? uploadLocation : uploadLocation + "/";
                    key = uploadLocation + key;
                }
                await Task.Run(() => transferUtility.Upload(file, bucketName, key));
            }
    

Note: This method is already added to the Action Argument, so we don’t need to update it.

Step 2 – Add a RemoteDirectory Argument

If we are going to upload a file to a specific location, we should know what that specific location is. So add an Argument for it.

  1. Add the following argument to ArgsHandler.cs.
                    ...
                    new Argument
                    {
                        Name = "RemoteDirectory",
                        ShortName = "rd",
                        Description = "The remote directory on the S3 Bucket.",
                        Example = "{name}=My/Remote/Directory",
                        Action = (value) =>
                        {
                            Console.WriteLine(value);
                        }
                    }
                    ...
    

Step 4 – Update the parameter array passed to UploadFile

We’ve already create a custom parameter array for the UploadFile action. We simply need to add a method for it

            // Use the Custom or Common pattern
            CustomParameters.Add("CreateBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });
            CustomParameters.Add("CreateTextFile", new object[] { s3client, bucketName, Args.Value("Filename"), Args.Value("Text") });
            CustomParameters.Add("DeleteBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });
            CustomParameters.Add("DeleteFile", new object[] { transferUtility, bucketName, Args.Value("Filename") });
            CustomParameters.Add("UploadFile", new object[] { transferUtility, bucketName, Args.Value("File"), Args.Value("RemoteDirectory") });

Note: There are enough of these now that I alphabetized them.

You can now specify the remote directory when uploading a file.

Go to: Part 10 – Uploading all files in a directory recursively to an S3 Bucket

Return to: Managing Amazon AWS with C#

Amazon S3 Bucket Management with C#: Part 8 – Deleting a file in a Bucket

Before getting started

Skill Level: Beginner

Assumptions:

  1. You already gone through Parts 1-7 of Managing Amazon AWS with C#.

Additional information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • Rhyous.SimpleArgs
  • Don’t Repeat Yourself (DRY) Principal

Step 1 – Add a DeleteFile method to BucketManager.cs

  1. Edit file called BucketManager.cs.
  2. Enter this new method:
            public static async Task CreateTextFile(AmazonS3Client client, string bucketName, string filename, string text)
            {
                var dirRequest = new PutObjectRequest
                {
                    BucketName = bucketName,
                    Key = filename,
                    InputStream = text.ToStream()
                };
                await client.PutObjectAsync(dirRequest);
                Console.WriteLine($"Created text file in S3 bucket: {bucketName}/{filename}");
            }
    

Notice: The code is almost identical to that of deleting a directory, with only one exception. We aren’t ending with a /. We really should not have duplicate code. So lets fix this in the next step.

Step 2 – Solve the Repetitive Code

It is best practice to avoid having duplicate code. This is often called the “Don’t Repeat Yourself” principal. So let’s update the DeleteBucketDirectory code to forward to the DeleteFile code.

  1. Update the DeleteDirectory method so that both methods share code.
           public static async Task DeleteBucketDirectory(AmazonS3Client client, string bucketName, string directory)
            {
                if (!directory.EndsWith("/"))
                    directory = directory += "/";
                await DeleteFile(client, bucketName, directory);
            }
    

Now the delete directory code is no longer repetitive. A directory is the same as a file, just with a slash. So the Delete directory correctly makes sure that the directory name ends with a slash, then forwards the call to delete file.

Step 3 – Update the Action Argument

We should be very good at this by now. We need to make this method a valid action for the Action Argument.

  1. Edit the ArgsHandler.cs file to define an Action argument.
                        ...
                        AllowedValues = new ObservableCollection<string>
                        {
                            "CreateBucket",
                            "DeleteBucket",
                            "ListFiles",
                            "UploadFile",
                            "CreateBucketDirectory",
                            "DeleteBucketDirectory",
                            "CreateTextFile",
                            "DeleteFile"
                        },
                        ...
    

Note: There are no additional Arguments to add. To delete a file, we need the bucket name and a file name, which we already have Arguments for.

Step 4 – Fix the parameter mismatch problem

In Part 4, we created a method to pass different parameters to different methods. Let’s use that to pass in the correct parameters.

However, take note that we now have more exceptions than we had commonalities. This suggests that it is about time to refactor this code. For now, we will leave it.

            // Use the Custom or Common pattern
            CustomParameters.Add("UploadFile", new object[] { transferUtility, bucketName, Args.Value("File") });
            CustomParameters.Add("CreateBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });
            CustomParameters.Add("DeleteBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });
            CustomParameters.Add("CreateTextFile", new object[] { s3client, bucketName, Args.Value("Filename"), Args.Value("Text") });

You can now add a text file to an Amazon S3 bucket using C#.

Homework: There is some repetitiveness between CreateFolder and DeleteFolder. What is it? (Hint: Directories end with a slash.)

Go to: Part 9 – Uploading a file with its path to a Bucket

Return to: Managing Amazon AWS with C#

Amazon S3 Bucket Management with C#: Part 7 – Creating a text file in a Bucket

Before getting started

Skill Level: Beginner

Assumptions:

  1. You already gone through Parts 1-6 of Managing Amazon AWS with C#.

Additional information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • Rhyous.SimpleArgs
  • Rhyous.StringLibrary

Step 1 – Add NuGet Package

  1. Right-click on your project and choose Management NuGet Packages.
  2. Search for Rhyous.StringLibrary.
    This is a simple library for string extensions methods and more. String code that is not in .Net by default, yet the methods have proven over time to be commonly used.
  3. Install the Rhyous.StringLibrary NuGet package.

Step 2 – Add a CreateTextFile method to BucketManager.cs

  1. Edit file called BucketManager.cs.
  2. Enter this new method:
            public static async Task CreateTextFile(AmazonS3Client client, string bucketName, string filename, string text)
            {
                var dirRequest = new PutObjectRequest
                {
                    BucketName = bucketName,
                    Key = filename,
                    InputStream = text.ToStream()
                };
                await client.PutObjectAsync(dirRequest);
                Console.WriteLine($"Created text file in S3 bucket: {bucketName}/{filename}");
            }
    

Notice: The code is almost identical to that of creating a directory, with two exceptions. We aren’t ending with a /. And instead of assigning zero bytes to InputStream, we assigned text.ToStream(). Rhyous.StringLibrary provides us the ToStream() extension method.

Step 2 – Update the Action Argument

We now need to make this method a valid action for the Action Argument.

  1. Edit the ArgsHandler.cs file to define an Action argument.
                        ...
                        AllowedValues = new ObservableCollection&amp;amp;lt;string&amp;amp;gt;
                        {
                            "CreateBucket",
                            "DeleteBucket",
                            "ListFiles",
                            "UploadFile",
                            "CreateBucketDirectory",
                            "DeleteBucketDirectory",
                            "CreateTextFile",
                        },
                        ...
    

Step 3 – Add FileName and Text Arguments

If we are going to create a text file, we need to know the file name and the text to insert.

  1. Edit the ArgsHandler.cs file to define an Action argument.
                    ...
                    new Argument
                    {
                        Name = "FileName",
                        ShortName = "N",
                        Description = "The name of text a file to create.",
                        Example = "{name}=MyTextfile.txt",
                        Action = (value) =>
                        {
                            Console.WriteLine(value);
                        }
                    },
                    new Argument
                    {
                        Name = "Text",
                        ShortName = "T",
                        Description = "The text to put in a text file.",
                        Example = "{name}=\"This is some text!\"",
                        Action = (value) =>
                        {
                            Console.WriteLine(value);
                        }
                    }
                    ...
    

Step 4 – Fix the parameter mismatch problem

In Part 4, we created a method to pass different parameters to different methods. Let’s use that to pass in the correct parameters.

However, take note that we now have more exceptions than we had commonalities. This suggests that it is about time to refactor this code. For now, we will leave it.

            // Use the Custom or Common pattern
            CustomParameters.Add("UploadFile", new object[] { transferUtility, bucketName, Args.Value("File") });
            CustomParameters.Add("CreateBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });
            CustomParameters.Add("DeleteBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });
            CustomParameters.Add("CreateTextFile", new object[] { s3client, bucketName, Args.Value("Filename"), Args.Value("Text") });

You can now add a text file to an Amazon S3 bucket using C#.

Go to: Deleting a file in a Bucket

Return to: Managing Amazon AWS with C#

Amazon S3 Bucket Management with C#: Part 6 – Deleting a Directory in a Bucket

Before getting started

Skill Level: Beginner

Assumptions:

  1. You already gone through Parts 1-5 of Managing Amazon AWS with C#.

Additional information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • Rhyous.SimpleArgs

Step 1 – Add a DeleteBucketDirectory method to BucketManager.cs

  1. Edit file called BucketManager.cs.
  2. Enter this new method:
            public static async Task DeleteBucketDirectory(AmazonS3Client client, string bucketName, string directory)
            {
                var dirRequest = new DeleteObjectRequest
                {
                    BucketName = bucketName,
                    Key = directory + "/"
                };
                await client.DeleteObjectAsync(dirRequest);
                Console.WriteLine($"Created S3 bucket folder: {bucketName}/{directory}/");
            }
    

Note: Amazon S3 uses objects with a key ending in a / as a directory, so we have to call DeleteObjectAsync.

Step 2 – Update the Action Argument

We now need to make this method a valid action for the Action Argument.

  1. Edit the ArgsHandler.cs file to define an Action argument.
                        ...
                        AllowedValues = new ObservableCollection&amp;lt;string&amp;gt;
                        {
                            "CreateBucket",
                            "DeleteBucket",
                            "ListFiles",
                            "UploadFile",
                            "CreateBucketDirectory",
                            "DeleteBucketDirectory"
                        },
                        ...
    

Step 3 – Fix the parameter mismatch problem

In Part 4, we created a method to pass different parameters to different methods. Let’s use that to pass in the correct parameters.

            // Use the Custom or Common pattern
            CustomParameters.Add("UploadFile", new object[] { transferUtility, bucketName, Args.Value("File") });
            CustomParameters.Add("CreateBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });
            CustomParameters.Add("DeleteBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });

You can now Delete a directory on S3, using C#.

Go to:

Return to: Managing Amazon AWS with C#

Amazon S3 Bucket Management with C#: Part 5 – Creating a Directory in a Bucket

Before getting started

Skill Level: Beginner

Assumptions:

  1. You already gone through Parts 1-4 of Managing Amazon AWS with C#.

Additional information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • Rhyous.SimpleArgs

Step 1 – Add a CreateBucketDirectory method to BucketManager.cs

  1. Edit file called BucketManager.cs.
  2. Enter this new method:
            public static async Task CreateBucketDirectory(AmazonS3Client client, string bucketName, string directory)
            {
                var dirRequest = new PutObjectRequest
                {
                    BucketName = bucketName,
                    Key = directory + "/",
                    InputStream = new MemoryStream(new byte[0])
                };
                await client.PutObjectAsync(dirRequest);
                Console.WriteLine($"Created S3 bucket folder: {bucketName}/{directory}/");
            }
    

Note: Amazon S3 uses objects with a key ending in a / as a directory, so all we do is put a new empty object with a slash.

Step 2 – Update the Action Argument

We now need to make this method a valid action for the Action Argument.

  1. Edit the ArgsHandler.cs file to define an Action argument.
                        ...
                        AllowedValues = new ObservableCollection&amp;lt;string&amp;gt;
                        {
                            "CreateBucket",
                            "DeleteBucket",
                            "ListFiles",
                            "UploadFile",
                            "CreateBucketDirectory"
                        },
                        ...
    

Step 3 – Fix the parameter mismatch problem

In Part 4, we created a method to pass different parameters to different methods. Let’s use that to pass in the correct parameters.

            // Use the Custom or Common pattern
            CustomParameters.Add("UploadFile", new object[] { transferUtility, bucketName, Args.Value("File") });
            CustomParameters.Add("CreateBucketDirectory", new object[] { s3client, bucketName, Args.Value("Directory") });

You can now add a directory on S3, using C#.

Go to:

Return to: Managing Amazon AWS with C#

Amazon S3 Bucket Management with C#: Part 4 – Uploading a file to a Bucket

Before getting started

Skill Level: Beginner

Assumptions:

  1. You already gone through Parts 1, 2, and 3 of Managing Amazon AWS with C#.

Additional information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • async, await, Task
  • Rhyous.SimpleArgs
  • Dependency Inject (D in S.O.L.I.D.)
  • Reflection
  • Custom or Common pattern

Step 1 – Add an UploadFile method to BucketManager.cs

  1. Edit file called BucketManager.cs.
  2. Enter this new method:
            public static async Task UploadFile(TransferUtility transferUtility, string bucketName, string file)
            {
                await Task.Run(() => transferUtility.Upload(file, bucketName));
            }
    

    Notice 1: This method has different parameters. We are going to have to fix Program.cs later. Up until now, all of our methods had the same parameters.

  3. Notice 2: The content of this method is an action we would like to run asynchronously, but it is not asynchronous. Task.Run is a static method that runs any method you call inside it asynchronously.

Step 2 – Update the Action Argument

We now need to make this method a valid action for the Action Argument.

    1. Edit the ArgsHandler.cs file to define an Action argument.
                          ...
                          AllowedValues = new ObservableCollection<string>
                          {
                              "CreateBucket",
                              "DeleteBucket",
                              "ListFiles",
                              "UploadFile",
                          },
                          ...
      

Step 3 – Add a File Argument

If we are going to upload a file, we should know which file it is.

  1.                 new Argument
                    {
                        Name = "File",
                        ShortName = "f",
                        Description = "The file.",
                        Example = "{name}=c:\\some\file.txt",
                        CustomValidation = (value) =>
                        {
                            return File.Exists(value);
                        },
                        Action = (value) =>
                        {
                            Console.WriteLine(value);
                        }
                    }
    

    Notice: One of the cool features of SimpleArgs is the ability to declare custom validation. We don’t have to check elsewhere in our code if the file exists. We can use that to validate whether the File parameter is valid or not.

Step 4 – Fix the parameter mismatch problem

To be nice and S.O.L.I.D., our program now needs to determine the method’s dependencies and inject them into the method. It needs to do this dynamically at runtime.

Well, with only one exception, it is most easy to use the Custom or Common pattern. The Custom or Common pattern simply means checking for a customization and if no customization exists, use the common implementation.

To implement this, we could just use a simple IF condition. But just to demonstrate how a Dictionary can be used for the Custom or Common pattern, I will use it.

    class Program
    {
        static void Main(string[] args)
        {
            new ArgsManager<ArgsHandler>().Start(args);
        }

        static Dictionary<string, object[]> CustomParameters = new Dictionary<string, object[]>();

        internal static void OnArgumentsHandled()
        {
            var action = Args.Value("Action");
            var bucketName = Args.Value("Bucket");
            var file = Args.Value("File");

            var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
            MethodInfo mi = typeof(BucketManager).GetMethod(action, flags);

            var region = RegionEndpoint.GetBySystemName(ConfigurationManager.AppSettings["AWSRegion"]);
            var s3client = new AmazonS3Client(region);
            var transferUtility = new TransferUtility(region);

            // Use the Custom or Common pattern
            CustomParameters.Add("UploadFile", new object[] { transferUtility, bucketName, file });
            object[] parameters;
            if (!CustomParameters.TryGetValue(action, out parameters))
                parameters = new object[] { s3client, bucketName };

            var task = mi.Invoke(null, parameters) as Task;
            task.Wait();
        }
    }

Notice in line 8 we create a dictionary. In line 24 we populate the dictionary with a customization. In Lines 26 and 27, we try to get a custom parameter array and if we don’t find it, we use the default one.

Homework: What if every method had different parameters? What would you do?

Go to: Part 5 – Creating a Directory in a Bucket

Return to: Managing Amazon AWS with C#

Amazon S3 Bucket Management with C#: Part 3 – Listing files in a Bucket

Before getting started

Skill Level: Beginner

Assumptions:

  1. You already gone through Part 1 – Creating a Bucket and Part 2 – Deleting a Bucket

Additional information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • async, await, Task
  • Rhyous.SimpleArgs

Step 1 – Add a ListFiles method to BucketManager.cs

  1. Edit file called BucketManager.cs.
  2. Enter this new method:
            public static async Task ListFiles(AmazonS3Client client, string bucketName)
            {
                var listResponse = await client.ListObjectsV2Async(new ListObjectsV2Request { BucketName = bucketName });
                if (listResponse.S3Objects.Count > 0)
                {
                    Console.WriteLine($"Listing items in S3 bucket: {bucketName}");
                    listResponse.S3Objects.ForEach(o => Console.WriteLine(o.Key));
                }
            }
    

    Note: I noticed there was a ListObjectsAsync and a ListObjectsV2Async. I assumed the one with V2 is newer and should be used for new code. The documentation for ListObjectsV2Async confirmed this.

Step 2 – Update the Action Argument

We now need to make this method a valid action for the Action Argument.

  1. Edit the ArgsHandler.cs file to define an Action argument.
                        ...
                        AllowedValues = new ObservableCollection<string>
                        {
                            "CreateBucket",
                            "DeleteBucket",
                            "ListFiles"
                        },
                        ...
    

Notice: We didn’t have a step 3. We wrote some S.O.L.I.D. code in Part 1 and Part 2, which made it really easy for us to implement this method.

Homework: I also read in the documentation that only 1000 files will be listed when a call to ListObjectsV2Async is made. What if you have more than 1000 files, how would you list them all?

Go to: Part 4 – Uploading a file to a Bucket

Return to: Managing Amazon AWS with C#

Amazon S3 Bucket Management with C#: Part 2 – Deleting a Bucket

Before getting started

Skill Level: Beginner

Assumptions:

  1. You already gone through Part 1 – Creating a Bucket where you have already:
    1. Created a new Console Application Project
    2. Added NuGet Package
    3. Created a BucketManager.cs
    4. Coded Program.cs.
    5. Added command line arguments

Additional information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • async, await, Task
  • Reflection
  • Rhyous.SimpleArgs
  • Single Responsibility Principal (S of S.O.L.I.D.) or Don’t Repeat Yourself (DRY)
  • Dependency Injection – Method Injection (D of S.O.L.I.D.)

Step 1 – Add a DeleteBucket method to BucketManager.cs

  1. Edit file called BucketManager.cs.
  2. Enter this new method:
            public static async Task DeleteBucket(string bucketName)
            {
                var region = RegionEndpoint.GetBySystemName(ConfigurationManager.AppSettings["AWSRegion"]);
                var client = new AmazonS3Client(region);
                await AmazonS3Util.DeleteS3BucketWithObjectsAsync(client, bucketName);
                Console.WriteLine($"Deleted S3 bucket: {bucketName}");
            }
    

    Notice that there is more involved with deleting a bucket than creating a bucket. A bucket may not be empty. It could have files in it already. Because of this we call a helper method, DeleteS3BucketWithObjectsAsync, that deletes a bucket even if it has objects, i.e. files, in it.

Step 2 – Configure an Argument for the Action to call

Since BucketManager can now can both Create and Delete a bucket, we need an argument to specify what action we would like to call.

  1. Edit the ArgsHandler.cs file to define an Action argument.
    SimpleArgs allows for arguments to be declarative and provides most the features you would want in command line arguments without having to write those features for every new application.

                    new Argument
                    {
                        Name = "Action",
                        ShortName = "a",
                        Description = "The action to run.",
                        Example = "{name}=default",
                        DefaultValue = "Default",
                        AllowedValues = new ObservableCollection&lt;string&gt;
                        {
                            "CreateBucket",
                            "DeleteBucket"
                        },
                        IsRequired = true,
                        Action = (value) =&gt;
                        {
                            Console.WriteLine(value);
                        }
                    }
    

    Notice: We don’t have to validate that the correct method was passed in as a variable because SimpleArgs will do this for us by simply declaring them as AllowedValues. When AllowedValues is declared, only those values are allowed. Any other value will result in the application stopping and outputting the list of valid arguments.

Step 3 – Edit the Program.cs

We are now going to use reflection to call the appropriate function based on our action parameter.

    1. Edit the OnArgumentsHandled method of Program.cs.
              internal static void OnArgumentsHandled()
              {
                  var action = Args.Value("Action");
                  var bucketName = Args.Value("Bucket");
                  var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
                  MethodInfo mi = typeof(BucketManager).GetMethod(action, flags);
      
                  var task = mi.Invoke(null, new[] { bucketName }) as Task;
                  task.Wait();
              }
      

Step 4 – Make the code S.O.L.I.D.

We have broken the Single Responsibility Principal (S in S.O.L.I.D.) or Don’t Repeat Yourself (DRY) rule. Let’s notice it and fix it.

    1. Notice in BucketManager.cs that both methods are breaking two rules:
      • Don’t Repeat Yourself or DRY: We have two methods repeating the same two lines of code.
                    var region = RegionEndpoint.GetBySystemName(ConfigurationManager.AppSettings["AWSRegion"]);
                    var client = new AmazonS3Client(region);											
        
      • Single Responsibility Principal: Each method has one repsponsibility. CreateBucket should only create a bucket on the Amazon S3 server. DeletBucket should only delete a bucket. Currently, both methods are having to instantiate a client and figure out the region. That isn’t the responsibility of these methods.
    2. Let’s solve this with Method Injection. Method Injection is a form of Dependency Injection (D in S.O.L.I.D.). We will pass the client into the method.
      Note: I am using method injection because all the methods are static, so Constructor Injection is not an option. Property Injection is an option. A Lazy-injectable Property would also be a very good option here.
    3. Alter the methods to take in an AmazonS3Client object.
      using Amazon.S3;
      using Amazon.S3.Util;
      using System;
      using System.Threading.Tasks;
      
      namespace Rhyous.AmazonS3BucketManager
      {
          public class BucketManager
          {
              public static async Task CreateBucket(AmazonS3Client client, string bucketName)
              {
                  await client.PutBucketAsync(bucketName);
                  Console.WriteLine($"Created S3 bucket: {bucketName}");
              }
      
              public static async Task DeleteBucket(AmazonS3Client client, string bucketName)
              {
                  await AmazonS3Util.DeleteS3BucketWithObjectsAsync(client, bucketName);
                  Console.WriteLine($"Deleted S3 bucket: {bucketName}");
              }
          }
      }
      
    4. Update the Program.cs to instantiate the client and pass it into the methods.
              internal static void OnArgumentsHandled()
              {
                  var action = Args.Value("Action");
                  var bucketName = Args.Value("Bucket");
      
                  var flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
                  MethodInfo mi = typeof(BucketManager).GetMethod(action, flags);
      
                  var region = RegionEndpoint.GetBySystemName(ConfigurationManager.AppSettings["AWSRegion"]);
                  var client = new AmazonS3Client(region);
      
                  var task = mi.Invoke(null, new object[] { client, bucketName }) as Task;
                  task.Wait();
              }
      

      Notice we now only create a client one time.

      Note: The OnArgumentsHandled in our Program.cs is now doing four things. As you can see above, it has each thing it does in a pair of lines, with each pair of lines separated by a double space. This is where we want to be careful to not overdo it when following design patterns. We only have eight lines of code. Program.cs is supposed to be a program. It is fine for now. Let’s not change it. Notice it. Consider changing it. This time we decided to leave it, but we can keep it in mind. If more lines are added, then that method probably should be changed.

Go to: Part 3 – Listing files in a Bucket

Return to: Managing Amazon AWS with C#

Amazon S3 Bucket Management with C#: Part 1 – Creating a Bucket

Before getting started

Skill Level: Beginner

Assumptions:

  1. You already have Visual Studio installed.
  2. You are familiar with creating projects in Visual Studio.
  3. We assume you have already gone to AWS and registered with them. If you haven’t done that already, stop and go there now. Amazon has a free tier and you can create an account here: https://aws.amazon.com/free

Additional Information: I sometimes cover small sub-topics in a post. Along with AWS, you will also be exposed to:

  • .NET Core 2.0 – If you use .NET Framework, the steps will be slightly different, but as this is a beginner level tutorial, it should be simple.
  • async, await, Task
  • Rhyous.SimpleArgs

Step 1 – Create the project

  1. Open Visual Studio.
  2. Go to File | New Project.
  3. Choose Console Application.
    Give it any name you want.
    I am going to call my project Rhyous.AmazonS3BucketManager.

Step 2 – Add NuGet Packages

  1. Right-click on your project and choose Management NuGet Packages.
  2. Search for AWSSDK.S3.
  3. Install the NuGet package and all the dependencies.
  4. Search for System.Configuration.ConfigurationManager.
  5. Install it.

Step 3 – Create a BucketManager.cs file

  1. Create a new file called BucketManager.cs.
  2. Enter this code:
    using Amazon;
    using Amazon.S3;
    using System;
    using System.Configuration;
    using System.Threading.Tasks;
    
    namespace Rhyous.AmazonS3BucketManager
    {
        public class BucketManager
        {
            public static async Task CreateBucket(string bucketName)
            {
                var region = RegionEndpoint.GetBySystemName(ConfigurationManager.AppSettings["AWSRegion"]);
                var client = new AmazonS3Client(region);
                await client.PutBucketAsync(bucketName);
                Console.WriteLine($"Created S3 bucket: {bucketName}");
            }
        }
    }
    

Step 4 – Edit the Program.cs

  1. Add the following to Program.cs.
            static void Main()
            {
                var task = BucketManager.CreateBucket("my.new.bucket");
                task.Wait();
            }
    

Step 5 – Create/Edit the App.config

  1. If there isn’t an app.config in your project, create one.
  2. Right-click on your project and choose Add | New Item.
  3. Search for Application Configuration File.
    Make sure it is name app.config.
  4. Add an appSetting for your AWS profile name.
    Add an additional appSetting for your chosen AWS region.

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <appSettings>
        <add key="AWSProfileName" value="yourprofilename"/>
        <add key="AWSRegion" value="us-west-2" />
      </appSettings>
    </configuration>
    

Step 6 – Configure an Argument for the bucket name.

We are going to be adding to this program in subsequent posts. For this reason, we are going to use Rhyous.SimpleArgs library for our command line arguments as it provides ready-made command line argument features.

  1. Install another NuGet Package.
  2. Right-click on your project and choose Management NuGet Packages.
  3. Search for Rhyous.SimpleArgs
  4. Install it.
  5. Create an ArgsHandler.cs file to define the arguments:
    Note: If you used a .NET core project you have to create this file. If you created a .NET Framework file, this file should have been created for you and you have but to edit it.

    using Rhyous.SimpleArgs;
    using System;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;
    
    namespace Rhyous.AmazonS3BucketManager
    {
        public class ArgsHandler : ArgsHandlerBase
        {
            public override void InitializeArguments(IArgsManager argsManager)
            {
                Arguments.AddRange(new List<Argument>
                {
                    new Argument
                    {
                        Name = "Bucket",
                        ShortName = "b",
                        Description = "The bucket name to create. No uppercase or underscores allowed.",
                        Example = "{name}=my.first.bucket",
                        DefaultValue = "my.first.bucket",
                        IsRequired = true,
                        CustomValidation = (value) => 
                        {
                            return Regex.IsMatch(value, "^[a-z0-9.]+$");
                        },
                        Action = (value) =>
                        {
                            Console.WriteLine(value);
                        }
                    }
                });
            }
    
            public override void HandleArgs(IReadArgs inArgsHandler)
            {
                base.HandleArgs(inArgsHandler);
                Program.OnArgumentsHandled();
            }
        }
    }
    
  6. Update Program.cs as follows:
    using Rhyous.SimpleArgs;
    using System;
    
    namespace Rhyous.AmazonS3BucketManager
    {
        class Program
        {
            static void Main(string[] args)
            {
                new ArgsManager<ArgsHandler>().Start(args);
            }
    
            internal static void OnArgumentsHandled()
            {
                var bucketName = Args.Value("Bucket");
                var task = BucketManager.CreateBucket(bucketName);
                task.Wait();
            }
        }
    }
    

Now for fun, you can delete the app.config and change them to parameters.

Next:

  • Deleting a Bucket
  • Return to: Managing Amazon AWS with C#

    Understanding async and await, Task.WaitAll, Task.Run, and parallelism

    Ok. You are probably new to async and await or maybe you aren’t new but you’ve never deep dived into it. You may not understand some simple truths:

    1. aync/await does NOT give you parallelism for free.
    2. Tasks are not necessary parallel. They can be if you code them to be.
    3. The recommendation “You should always use await” is not really true when you want parallelism, but is still sort of true.
    4. Task.WhenAll is both parallel and async.
    5. Task.WaitAll only parallel.

    Here is a sample project that will help you learn.

    There is more to learn in the comments.
    There is more to learn by running this.

    Note: I used Visual Studio 2017 and compiled with .Net 7.1, which required that I go to the project properties | Build | Advanced | Language Version and set the language to C# 7.1 or C# latest minor version.

    using System;
    using System.Diagnostics;
    using System.Threading.Tasks;
    
    namespace MultipleAwaitsExample
    {
        class Program
        {
            static async Task Main(string[] args)
            {
                Console.WriteLine("Running with await");
                await RunTasksAwait();
                Console.WriteLine("Running with Task.WaitAll()");
                await RunTasksWaitAll();
                Console.WriteLine("Running with Task.WhenAll()");
                await RunTasksWhenAll();
                Console.WriteLine("Running with Task.Run()");
                await RunTasksWithTaskRun();
                Console.WriteLine("Running with Parallel");
                RunTasksWithParallel();
            }
    
            /// <summary>
            /// Pros: It works
            /// Cons: The tasks are NOT run in parallel.
            ///       Code after the await is not run while the await is awaited
            ///       **If you want parallelism, this isn't even an option.**
            ///       Slowest. Because of no parallelism.
            /// </summary>
            public static async Task RunTasksAwait()
            {
                var group = "await";
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                await MyTaskAsync(1, 500, group);
                await MyTaskAsync(2, 300, group);
                await MyTaskAsync(3, 100, group);
                Console.WriteLine("Code immediately after tasks.");
                watcher.Stop();
                Console.WriteLine($"{group} runtime: {watcher.ElapsedMilliseconds}");
            }
    
            /// <summary>
            /// WaitAll behaves quite differently from WhenAll
            /// Pros: It works
            ///       The tasks run in parallel
            /// Cons: It isn't clear whether the code is parallel here, but it is.
            ///       It isn't clear whether the code  is async here, but it is NOT.
            ///       There is a Visual Studio usage warning. You can remove async to get rid of it because it isn't an Async method.
            ///       The return value is wrapped the Result property of the task
            ///       Breaks Aync end-to-end
            ///       Note: I can't foresee usecase where WaitAll would be preferred over WhenAll.
            /// </summary>
            public static async Task RunTasksWaitAll()
            {
                var group = "WaitAll";
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                var task1 = MyTaskAsync(1, 500, group);
                var task2 = MyTaskAsync(2, 300, group);
                var task3 = MyTaskAsync(3, 100, group);
                Console.WriteLine("Code immediately after tasks.");
                Task.WaitAll(task1, task2, task3);
                watcher.Stop();
                Console.WriteLine($"{group} runtime: {watcher.ElapsedMilliseconds}");
            }
    
            /// <summary>
            /// WhenAll gives you the best of all worlds. The code is both parallel and async.
            /// Pros: It works
            ///       The tasks run in parallel
            ///       Code after the tasks run while the task is running
            ///       Doesn't break end-to-end async
            /// Cons: It isn't clear you are doing parallelism here, but you are.
            ///       There is a Visual Studio usage warning
            ///       The return value is wrapped the Result property of the task
            /// </summary>
            public static async Task RunTasksWhenAll()
            {
                var group = "WaitAll";
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                var task1 = MyTaskAsync(1, 500, group);  // You can't use await if you want parallelism
                var task2 = MyTaskAsync(2, 300, group);
                var task3 = MyTaskAsync(3, 100, group);
                Console.WriteLine("Code immediately after tasks.");
                await Task.WhenAll(task1, task2, task3); // But now you are calling await, so you are sort of still awaiting
                watcher.Stop();
                Console.WriteLine($"{group} runtime: {watcher.ElapsedMilliseconds}");
            }
    
            /// <summary>
            /// Pros: It works
            ///       The tasks run in parrallel
            ///       Code can run immediately after the tasks but before the tasks complete
            ///       Allows for running non-async code asynchonously
            /// Cons: It isn't clear whether the code is doing parallelism here. It isn't.
            ///       The lambda syntax affects readability
            ///       Breaks Aync end-to-end
            /// </summary>
            public static async Task RunTasksWithTaskRun()
            {
                var group = "Task.Run()";
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                await Task.Run(() => MyTask(1, 500, group));
                await Task.Run(() => MyTask(2, 300, group));
                await Task.Run(() => MyTask(3, 100, group));
                Console.WriteLine("Code immediately after tasks.");
                watcher.Stop();
                Console.WriteLine($"{group} runtime: {watcher.ElapsedMilliseconds}");
            }
    
            /// <summary>
            /// Pros: It works
            ///       It is clear in the code you want to run these tasks in parallel.
            ///       Code can run immediately after the tasks but before the tasks complete
            ///       Fastest
            /// Cons: There is no async or await.
            ///       Breaks Aync end-to-end. You can workaround this by wrapping Parallel.Invoke in a Task.Run method. See commented code.
            /// </summary>
            public /* async */ static void RunTasksWithParallel()
            {
                var group = "Parallel";
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                //await Task.Run(() => 
                Parallel.Invoke(
                    () => MyTask(1, 500, group),
                    () => MyTask(2, 300, group),
                    () => MyTask(3, 100, group),
                    () => Console.WriteLine("Code immediately after tasks.")
                );
                //);
                
                watcher.Stop();
                Console.WriteLine($"{group} runtime: {watcher.ElapsedMilliseconds}");
            }
    
            public static async Task MyTaskAsync(int i, int milliseconds, string group)
            {
                await Task.Delay(milliseconds);
                Console.WriteLine($"{group}: {i}");
            }
    
            public static void MyTask(int i, int milliseconds, string group)
            {
                var task = Task.Delay(milliseconds);
                task.Wait();
                Console.WriteLine($"{group}: {i}");
            }
        }
    }
    

    And here is the same example but this time with some return values.

    using System;
    using System.Diagnostics;
    using System.Threading.Tasks;
    
    namespace MultipleAwaitsExample
    {
        class Program1
        {
            static async Task Main(string[] args)
            {
                Console.WriteLine("Running with await");
                await RunTasksAwait();
                Console.WriteLine("Running with Task.WaitAll()");
                await RunTasksWaitAll();
                Console.WriteLine("Running with Task.WhenAll()");
                await RunTasksWhenAll();
                Console.WriteLine("Running with Task.Run()");
                await RunTasksWithTaskRun();
                Console.WriteLine("Running with Parallel");
                RunTasksWithParallel();
            }
    
            /// <summary>
            /// Pros: It works
            /// Cons: The tasks are NOT run in parallel.
            ///       Code after the await is not run while the await is awaited
            ///       **If you want parallelism, this isn't even an option.**
            ///       Slowest. Because of no parallelism.
            /// </summary>
            public static async Task RunTasksAwait()
            {
                var group = "await";
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                // You just asign the return variables as normal.
                int result1 = await MyTaskAsync(1, 500, group);
                int result2 = await MyTaskAsync(2, 300, group);
                int result3 = await MyTaskAsync(3, 100, group);
                Console.WriteLine("Code immediately after tasks.");
                watcher.Stop();
                // You now have access to the return objects directly.
                Console.WriteLine($"{group} runtime: {watcher.ElapsedMilliseconds}");
            }
    
            /// <summary>
            /// WaitAll behaves quite differently from WhenAll
            /// Pros: It works
            ///       The tasks run in parallel
            /// Cons: It isn't clear whether the code is parallel here, but it is.
            ///       It isn't clear whether the code  is async here, but it is NOT.
            ///       There is a Visual Studio usage warning. You can remove async to get rid of it because it isn't an Async method.
            ///       The return value is wrapped the Result property of the task
            ///       Breaks Aync end-to-end
            ///       Note: I can't foresee usecase where WaitAll would be preferred over WhenAll.
            /// </summary>
            public static async Task RunTasksWaitAll()
            {
                var group = "WaitAll";
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                var task1 = MyTaskAsync(1, 500, group);
                var task2 = MyTaskAsync(2, 300, group);
                var task3 = MyTaskAsync(3, 100, group);
                Console.WriteLine("Code immediately after tasks.");
                Task.WaitAll(task1, task2, task3);
                watcher.Stop();
                // You now have access to the return object using the Result property.
                int result1 = task1.Result;
                int result2 = task2.Result;
                int result3 = task3.Result;
                Console.WriteLine($"{group} runtime: {watcher.ElapsedMilliseconds}");
            }
    
            /// <summary>
            /// WhenAll gives you the best of all worlds. The code is both parallel and async.
            /// Pros: It works
            ///       The tasks run in parallel
            ///       Code after the tasks run while the task is running
            ///       Doesn't break end-to-end async
            /// Cons: It isn't clear you are doing parallelism here, but you are.
            ///       There is a Visual Studio usage warning
            ///       The return value is wrapped the Result property of the task
            /// </summary>
            public static async Task RunTasksWhenAll()
            {
                var group = "WaitAll";
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                var task1 = MyTaskAsync(1, 500, group);  // You can't use await if you want parallelism
                var task2 = MyTaskAsync(2, 300, group);
                var task3 = MyTaskAsync(3, 100, group);
                Console.WriteLine("Code immediately after tasks.");
                await Task.WhenAll(task1, task2, task3); // But now you are calling await, so you are sort of still awaiting
                watcher.Stop();
                Console.WriteLine($"{group} runtime: {watcher.ElapsedMilliseconds}");
            }
    
            /// <summary>
            /// Pros: It works
            ///       The tasks run in parrallel
            ///       Code can run immediately after the tasks but before the tasks complete
            ///       Allows for running non-async code asynchonously
            /// Cons: It isn't clear whether the code is doing parallelism here. It isn't.
            ///       The lambda syntax affects readability
            ///       Breaks Aync end-to-end
            /// </summary>
            public static async Task RunTasksWithTaskRun()
            {
                var group = "Task.Run()";
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                int result1 = await Task.Run(() => MyTask(1, 500, group));
                int result2 = await Task.Run(() => MyTask(2, 300, group));
                int result3 = await Task.Run(() => MyTask(3, 100, group));
                Console.WriteLine("Code immediately after tasks.");
                watcher.Stop();
                // You now have access to the return objects directly.
                Console.WriteLine($"{group} runtime: {watcher.ElapsedMilliseconds}");
            }
    
            /// <summary>
            /// Pros: It works
            ///       It is clear in the code you want to run these tasks in parallel.
            ///       Code can run immediately after the tasks but before the tasks complete
            ///       Fastest
            /// Cons: There is no async or await.
            ///       Breaks Aync end-to-end. You can workaround this by wrapping Parallel.Invoke in a Task.Run method. See commented code.
            /// </summary>
            public /* async */ static void RunTasksWithParallel()
            {
                var group = "Parallel";
                Stopwatch watcher = new Stopwatch();
                watcher.Start();
                // You have to declare your return objects before hand.
                //await Task.Run(() => 
                int result1, result2, result3;
                Parallel.Invoke(
                    () => result1 = MyTask(1, 500, group),
                    () => result2 = MyTask(2, 300, group),
                    () => result3 = MyTask(3, 100, group),
                    () => Console.WriteLine("Code immediately after tasks.")
                );
                //);
                // You now have access to the return objects directly.
                watcher.Stop();
                Console.WriteLine($"{group} runtime: {watcher.ElapsedMilliseconds}");
            }
    
            public static async Task<int> MyTaskAsync(int i, int milliseconds, string group)
            {
                await Task.Delay(milliseconds);
                Console.WriteLine($"{group}: {i}");
                return i;
            }
    
            public static int MyTask(int i, int milliseconds, string group)
            {
                var task = Task.Delay(milliseconds);
                task.Wait();
                Console.WriteLine($"{group}: {i}");
                return i;
            }
        }
    }
    

    Code faster and with higher quality using code generation

    Code generation is the idea of having a tool write code written for you. If you use a modern IDE, such Visual Studio, you likely use a type of code generation, even if you think you don’t.

    Anytime code is written for you, it is code generation. You use code generation whenever you do the following:

    1. Create a new solution or project – Each project is a template with a base set of code ready for you to use.
    2. Add a new class, interface, or another item to a project – When adding a new class to a project, the class comes with a pre-created class object. If you add a new class called Person, the following class file would be created and added to the project:
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading.Tasks;
      
      namespace LANDesk.Licensing.WebServices.File.Tests
      {
          class Person
          {
          }
      }
      

      The using statements are lines of code. The namespace and class definitions and the brackets are lines of code.  You get 11 lines of code not including the whitespace lines. This code was created for you because you didn’t have to write it. That doesn’t mean it is 100% useful. If you don’t use threading, the last using statement can be removed.

      Similarly, other items that are added have a base set of code.

    3. Use code snippets – Code Snippets are quite powerful. With a few characters and then the tab key twice, you can create a lot of code. There are many built-in code snippets. If you are using them, you should be.
    4. Other Visual Studio features – Visual Studio has some specific use cases where it provides code generation. For example, if you highlight a class name and choose Extract Interface, Visual Studio will generate and interface from the
    5. Plugins and 3rd party tools – Many plugins can generate code for you. For example, Resharper can do numerous code generation features, such as properly overriding the Equals method. ORMs, such as Entity Framework, have code generation tools. Entity Framework can generate most the Entities (class files that represent objects stored in database tables)  for you.

    You can enhance the code generation tools

    Most of these features are available as platforms for you to build upon. Enhancing these can be a simple as copying an existing item or as complex as developing your own product.

    In Visual Studio, you can do any of the following: (listed in order of ease of use)

    1. Create your own snippets.
    2. Create your own class/item templates
    3. Download or purchase additional code generation plugins
    4. Create your own Project/Solution templates
    5. Create your own Visual Studio plugins/3rd party tools

    If you are repeatedly writing the same code over an over again, you probably would benefit from creating a code generation solution.

    Faster and higher Quality

    When a human writes something, there is room for human error. If a person writes the same thing over and over, there is a tendency to minimize and cut corners. Also, there are many standard pieces of code that have already gone through significant use and bug fixes resulting in a stable and scalable piece of code. For example, overriding Equals in a class isn’t always straight forward. If you do it yourself, you might be left wondering if you have properly overridden Equals of if your implementation has well-known bugs? Do you leave those bugs in or research and fix them? If you research and fix them, how long will it take you each time you override Equals to make sure you accounted for all well-known bugs? However, if you use a generator with a standard, tested, and bug-free piece of code, your code will be higher quality and it will be created almost instantly. See, faster and higher quality.

    I am hoping to have time to create a series of posts on this topic, starting with Snippets. But to get you started, check out my Visual Studio snippets for C# on GitHub.

    https://github.com/rhyous/VisualCSharpSnippets

     

    SQL Query to Entity Framework Cheat Sheet

    The following are examples of SQL queries and how to execute them with Entity Framework

    SELECT * with Entity Framework

    SELECT * FROM Contacts
    
    var mydbContext.Contacts.ToList();
    

    SELECT Id with Entity Framework

    This is really for how to select any single column.

    SELECT Id FROM Contacts
    
    List<int> idList = dbContext.Contacts.Select( c => c.Id ).ToList(); // Assuming Id is of type int
    

    SELECT only one row with Entity Framework

    This is really for how to select any single row from a table.

    SELECT * FROM Contacts where Id = 10
    
    var id = 10;
    var contact = dbContext.Contacts.SingleOrDefault( c => c.Id = id );
    

    SELECT only one result with Entity Framework

    This is really for how to select any single value from a single row in a table.

    SELECT UserId FROM Contacts where Id = 10
    
    var id = 10;
    int userId = dbContext.Contacts.Where( c => c.Id = id ).Select( c => c.UserId ).SingleOrDefault();
    

    SELECT first result with Entity Framework

    This is really for how to select the first value from a list of returned rows from a table.

    SELECT TOP 1 * FROM Contacts
    
    var id = 10;
    int userId = dbContext.Contacts.FirstOrDefault();
    

    INSERT INTO with Entity Framework

    INSERT INTO dbo.LD_User (Name, Type, Active, CreateDate, CreatedBy)
    VALUES ('user1', 1, 1, GetDate(), 101)
    
    var user = new User { Name = "user1", Type = UserType.Contact, true, DateTime.Now, User.System };
    dbContext.Users.Add(user);
    dbContext.SaveChanges();
    

    Note: UserType.Contact and User.System are enums in the above example.

    INSERT INTO … SELECT with Entity Framework

    Imagine you have these three tables. Product, ProductGroup, ProductGroupMembership. You want to make Products a member of a group by inserting into the ProductGroupMembership table.

    INSERT INTO ProductGroupMembership (ProductId, GroupId, CreateDate, CreatedBy)
    SELECT Id, @GroupId, GetDate(), @CreatedBy FROM Product
    WHERE Id IN (1, 2, 3, 4, 5) -- there could be hundreds or thousands of numbers in the IN statement
    
    EPIC FAIL!!! Can't be done without raw sql and opening up to sql injection attacks.
    

    However, you can create a stored procedure that takes and user-defined table called ArrayOfInt. Then add EntityFrameworkExtras.EF6, which is available as a NuGet package, to call the storedprocedure and pass it an array.

    WHERE with many AND/ORs with Entity Framework

    Imagine you have these three tables. Product, ProductGroup, ProductGroupMembership. You want to make Products a member of a group by inserting into the ProductGroupMembership table.

    You have a list of software Products provided to you. However, the input only includes Product.Name and Product.Version. You now need to check if the products exist and get the id.

    SELECT Id FROM Product
    WHERE (Name = 'Product 1' AND Version = '10.0')
    WHERE (Name = 'Product 2' AND Version = '10.0')
    WHERE (Name = 'Product 3' AND Version = '10.1')
    WHERE (Name = 'Product 4' AND Version = '10.0')
    WHERE (Name = 'Product 5' AND Version = '1.0')
    
    EPIC FAIL!!! Can't be done without raw sql
    

    However, you can add LinqKit’s PredicateBuilder to do this. PredicateBuilder works on top of Entity Framework and is available as a NuGet package. See how I used it here: Entity Framework and many WHERE clauses

    Entity Framework and many WHERE clauses

    So today, I needed to get Entity Framework to return me a list of Products from the database based on a list of Product.Name and Product.Version values (not Ids). If it were Product.Id, it would have been simple as I could have used an IN statement, but it wasn’t.

    The query might get many (maybe hundreds at a time) products based on the list. Here is the query I imagined.

    So when doing a query like this, since there could be hundreds, I have a couple of options.

    1. Query the database once for each product.
      SELECT * FROM dbo.Product
      WHERE (Name = 'Product 1' AND Version = '10.0')
      

      Repeat this same query once for each Product.

    2. Query the database one time with an or clause for each Product.Name and Product.Version.
      SELECT * FROM dbo.Product
      WHERE (Name = 'Product 1' AND Version = '10.0')
         OR (Name = 'Product 2' AND Version = '10.0')
         OR (Name = 'Product 3' AND Version = '10.0')
         OR (Name = 'Product 4' AND Version = '1.0')
         -- There could be hundreds
      
    3. Query the database once and get all products and use code to find the ones I wanted.
      SELECT * FROM dbo.Product
      

    Option 1
    I didn’t like this option because I could end up doing hundreds of single queries. That doesn’t sound like a good idea. What would the performance impact would be when doing hundreds of single queries? The overhead of traversing over the network to the database would prevent this option from scaling.

    Option 2
    This is the option I imagined in my head. My gut said to use this option.

    Option 3
    This would work. We only have about two thousand products today and querying them all would, right now, not be bad at all. However, we just bought a company and will be adding more products. We plan to buy more companies. Also, we have two companies that we have already bought and have yet to add those products in. When would the number of Product rows in the database make the SELECT * and invalid option? Doing this would work now, but it leave a time bomb for some future developer encounter and have to fix.

    Winner: Option 2

    Problem
    Entity Framework doesn’t really have an easy way to create the Option 2 query.

    So, how do I create this query with many where statements?

    Here are the two options I’ve found:

    Inline SQL Query with Entity Framework

            private static List<Product> GetProductsByNameAndVersion(ActivationDbContext dbContext, IEnumerable<ProductRequest> products)
            {
                if (!products.Any())
                {
                    return new List<Product>();
                }
                var query = "Select * FROM Product WHERE ";
                var or = "";
                var template = "(Name = '{0}' AND Version = '{1}')";
                foreach (var prod in products)
                {
                    query += or;
                    query += string.Format(template, prod.Name, prod.Version);
                    or = " OR ";
                }
                var dbProducts = dbContext.Products.SqlQuery(query).ToList();
                return dbProducts.ToList();
            }
    

    This option means I have to create magic strings and make sure that I handle the strings correctly. It has bugs already. Such as what if a product only has a name and not a version (version could be null or empty, who knows) or vice-versa? How would this affect my query string?

    PredicateBuilder

    Predicate Builder from the LinqKit library which is available as a NuGet package.

            private static List<Product> GetProductsByNameAndVersionPredicate(ActivationDbContext dbContext, IEnumerable<ProductRequest> products)
            {
                if (!products.Any())
                {
                    return new List<Product>();
                }
    
                var predicate = PredicateBuilder.False<Product>();
    
                foreach (var prod in products)
                {
                    var inner = PredicateBuilder.True<Product>();
                    inner = inner.And(p => p.Name== prod.Name);
                    inner = inner.And(p => p.Version == prod.Version);
                    predicate = predicate.Or(inner);
                }
                var dbProducts = dbContext.Products.AsExpandable().Where(predicate).ToList();
                return dbProducts;            
            }
    

    PredicateBuilder isn’t very intuitive. For starters, what is the different between these methods:

    • PredicateBuilder.True() – from what I understand this would be more appropriate and understandable as PredicateBuilder.And()
    • PredicateBuilder.False() – from what I understand this would be more appropriate and understandable as PredicateBuilder.Or()

    Also, you have to remember to call AsExpandable() on the first call to a table in order to use it.

    Conclusion

    I am going to go with PredicateBuilder for now. It feels cleaner than rolling my own string query. But both solutions ultimately worked. That means that Entity Framework ultimately provided me a solution without an extra library. However, LinqKit saved me from magic strings. My only question is this: Why isn’t a predicate builder built into Entity Framework?

    10+ Reasons why Java needs C#’s property syntax

    Written in response, to all the Java developers who claim that Java doesn’t need C#’s property syntax.

    The truth is most C# developers can’t quantify all the benefits to C# properties because there are so many. Most arguments I have seen from C# developers have been weak at best. These arguments fail to provide the Java development team a good enough reason to implement C#-like properties.

    A proper analogy would be the Pyramids. You can’t point to one brick and say, “That brick makes the pyramid,” because every brick is small (relative the size of the who pyramid), but together, each brick is important to making the pyramid and altogether, they are one of the seven wonders of the world. Similarly, C# Properties provide many little features that together improve the language far more significantly than most can’t quantify.

    Properties are quite awesome and provide some great features that Java cannot do now.

    1. Easy refactoring when moving from a simple member variable to a property.

    Properties using the same syntax as a member variable enable more than one feature, but we are going to talk about only this feature here to start.

    public class MyObj
    {
       public int Id;
       public String Name;
    }
    

    The program starts off with this because for years simplicity is all that is needed.

    Note: A getter and a setter provide little to no benefit for a model object. If you aren’t encapsulating code on get and set, using a getter and setter gets in the way. Also, a using a getter and a setter is only a convention anyway, and not forced by the language. As such, getters and setters can’t be relied upon.

    A year later, you find that you need to add some feature on name set. You change your class. In Java, you have to create getters and setters.

    public class MyObj
    {
       public int id;
       private String _Name;
       public String getName(){return _Name;}
       public void setName(string value) {
          _Name = value; 
          // More work here
       }
    }
    

    Now every single line of code that calls MyObj.Name is broken. However, with properties, this wouldn’t the case.

    public class MyObj
    {
       public int id;
       private String Name {
          get { return _Name; } 
          set {
             _Name = value;
             // more work here
          }
       }
    }
    

    None of my existing code broke using the property example. This sounds trivial but what if you are an API that hundreds of other tools consume and use. Now this a breaking change that has a massive impact on a business. This feature is huge.

    Can Java change a class today from a member variable to a method without breaking an API? No, it cannot. Does this happen often? No, but when it does, it is a breaking change without properties, while with properties, it works without a second thought.

    Important: This feature is also why so many hacks that suggest that Java adds a language construct that creates getProperty and setProperty methods are still broken. I’ve seen recommendations such as this where the suggestion is for the compiler and IntelliSense to just convert these to getProperty and setProperty:

    public class MyObj
    {
       @get @set String Name;
       public MyObj()
       {
          setName("Rhyous");// Default value
       }
    }
    

    That syntax doesn’t solve the problem. In order to solve this problem, the syntax still has to be this:

    public class MyObj
    {
       @get @set String Name;
       public MyObj()
       {
          Name = "Rhyous";// Default value
       }
    }
    

    However, even with this, the suggested syntax is not the right suggestion. While the above syntax works for auto properties, how would code be added to the get or set method? The above syntactical sugar, while better than what java has now, is lacking compared to C#’s implementation and would result in fewer features.

    2. Replacing an object that uses member variables with an interface

    This is similar to #1. You have an object and need to create a layer of abstraction and use an interface for that object. But the object uses only member variables? How can you create an interface for the following syntax in Java?

    MyObj.Name
    

    You can’t. So to add a layer of abstraction, you now have to first refactor code. Again, as mentioned in #1, moving from MyObj.Name to MyObj.getName() and MyObj.setName() is a breaking change, especially in a API. It can have a massive impact.

    Now, before you argue that you would never need to add a layer of abstraction for a simple object, let me remind you that all objects are not simple. I agree, on a simple model object, abstraction wouldn’t be necessary. However, the problem is certainly with a method on an object that also has public members. But you need the whole object, not just the method. And interface with only methods won’t be enough.

    MyObj.Name
    MyObj.CallServer();
    

    Well, we can’t use the CallServer() method as is in a Unit Test. We need to use and interface and dependency injection and good language architecture. We have to refactor some. But we with properties we don’t need to make a breaking change. Without properties, we do. We have to change from MyObj.Name to MyObj.getName().

    3. Properties are different than member variables and methods and reflection reflects that.

    C# has reflection. You can loop through all members, properties, and methods separately. In Java, you have something similar. But no way to get properties separate from other methods.

    When you only want to loop through getters and setters in Java, how do you do that? Unless every getter and setter is perfectly named getProperty setProperty and none of the methods that are not getters or setters have the format of getSomething setComething, you can’t.

    Can you loop through only properties today in Java? Maybe. Java cannot guarantee this ability.

    4. Sharing objects between Java and C#.

    This feature goes beyond properties, but the lack of a Property syntax is the biggest barrier.

    In order to do this today, the object has to be written in Java and C#. C# developers have to live with the more verbose getProperty() setPropert() syntax. For example: MyObj.Id++ is nice and clean but the equivalent in java is MyObj.setId(MyOjb.getId() + 1);

    Some tools, such as Hibernate/NHibernate, would benefit greatly from this feature.

    5. Properties let you write with cleaner and shorter syntax.

    You save programming time. You save lines of code. Look below, as three lines become one.

    private String _Name;
    public String getName() { return _Name; };
    private void setName(String name) { _Name = name; }
    

    vs

    public string Name { get; set; }
    

    Java is not just a little more typing, it is a lot more typing. While you can argue that snippets or IDE code generator tools take care of this, I’d argue that C# has snippets and code generators, too. I can type prop tab in Visual Studio and have property pretty quickly so at best, snippets help Java almost catch up in development speed.

    Also, let’s not forget that this is one single feature. I could write a whole article about all the ways that C#’s property syntax is cleaner and shorter than Java’s syntax.

    How about adding one to an int?

    MyObj.Id++;

    vs in Java

    MyObj.setId(MyObj.getId() + 1);

    Again, a shorter and simpler syntax probably is a few dozen features as it will be used in so many different ways for so many different language benefits, not just one.

    6. Most the property data is in one place.

    This provides multiple features:

    • Easier to rename
    • Easier to copy and paste
    • Easier to identify as a property
    public string Name { get; set; }
    
    
    And in C#, a new syntax was added to make it so you no longer need to break this out to a backing field to set a default value.
    
    
    public string Name { get; set; } = "Rhyous";
    

    In java, there is no guarantee that properties are all together. I have seen code like this where the properties are not together in java.

    public class MyObj 
    {
      // Members
      private Integer _Id;
      private String _Name;
    
      // Getters
      public Integer getId() { return _Id; };
      public String getName() { return _Name; };
    
      // Setters
      public void setId(int id) { _Id = id; };
      public void setName(String name) { _Name = name; }
    }
    

    While this is fine, it makes renaming have to occur in 7 places in three lines that are separated and could be anywhere in the class file. (Count all the times Name or Id is used and it is 7 times.) In C#, it is once with an auto property and only four times with a property with a backing field. Of course, C# has the same problem once you use a backing field. The backing field isn’t always together with the property, that is only two items that can be separate, not three. In Java, keeping it together would have to be by convention. I use this convention in C# to keep backing fields together.

    public string Name 
    { 
      get {return _Name; } 
      set {_Name = value;}
    } private string _Name;
    

    7. In Aspect-oriented programming (AOP), you can inject code into only Properties.

    Using tools like AspectJ, can you do a pointcut only on properties in java? No, you cannot. You can do it on methods and filter it on methods that start with “get” or start with “set”, but we all know that get and set are only conventions and so any method that doesn’t follow convention won’t get the injected code (point cut in AspectJ), and worse, methods that aren’t getters or setters but start with get or set might get the pointcut, which is undesired.

    8. Names of properties in a class match when doing Xml or Json serialization

    Xml and Json serialization are very common. In C#, for newly developed code, there is no need to decorate the code with any C# Attributes as the names will serialize to JSON and Xml as is.

    Imagine we want to get this following Xml from code.

    <Person>
      <FirstName>Jared</FirstName>
      <LastName>Barneck</LastName>
    </Person>
    

    Or the following JSON.

    {  
       "FirstName":"Jared",
       "LastName":"Barneck"
    }
    

    In C#, we create this poco class. Note: Poco = plain old class object.

    public class Person
    {
       public string FirstName { get; set; }
       public string LastName { get; set; }
    }
    

    In Java, the class is not so simple. There is not an easy or a guaranteed to work way to do this without a lot more code and without annotations. Here is the same object in Java and what you would have to do to have both getters and setters, private members and serialize using Simple. See my article on Java’s Simple Xml Serialization library.

    public class Person
    {
       @FirstName
       private String _FirstName {get;set;}
       public String getFirstName() { return _FirstName; }
       public void setFirstName(string value) { _FirstName = value; }
    
       @LastName
       private String _LastName {get;set;}
       public String getLastName() { return _LastName ; }
       public void setLastName(string value) { _LastName = value; }
    }
    

    So in Java, names don’t match, requiring the developer to add a fourth line, an annotation, just to make this work. And this is new code, not legacy code.

    So when Java developers tell me that they don’t need properties, they are saying that they prefer four lines of code per property over one line per property when doing serialization. There is no argument. Of the two serializable class syntaxes above, C# is the winner by a long way.

    Now some serializers other than Simple are made by using magic strings, where they hope that the get and set convention is used and if it is used, everything after the get or set is serialized. So getPerson() will serialize to Person. Still, this leaves the names not matching, and it requires magic strings of “get” and “set” and a hope (or requirement) that convention was followed.

    C# also allows for taking of property of one name and serializing it to another name.

    public class Person
    {
       [XmlElement("fName")]
       public string FirstName { get; set; }
       [XmlElement("lName")]
       public string LastName { get; set; }
    }
    

    Yes, both C# and Java have this feature. The difference is, this is only needed to accommodate existing or legacy systems and not needed for brand new code and systems.

    9. Names of properties in a class match when using a database ORM (or CSV or Excel headers)

    Ok, this is almost an identical reason as #8, but serialization for JSON and Xml is vastly different than using a database ORM. But the same issue applies. And really Json and Xml are separate reasons and used often, so I could have broken those out into two features instead of one. But let’s not forget that this also benefits Excel output and CSV output as well as database table output. So, yes, this is a big, huge separate feature than serialization.

    If you have a table:

    CREATE TABLE [dbo].[User]
    (
    	[Id] [int] IDENTITY(1,1) NOT NULL,
    	[Username] [nvarchar](255) NULL,
    	[CreateDate] [datetime] NOT NULL,
    	[LastUpdated] [datetime] NULL,
    	[CreatedBy] [int] NOT NULL,
    	[LastUpdatedBy] [int] NULL
    )
    

    With properties, the naming scheme matches exactly.

    public class User
    {
       public int Id { get; set; }
       public string Username { get; set; }
       public DateTime CreateDate { get; set; }
       public DateTime LastUpdated { get; set; }
       public int CreatedBy { get; set; }
       public int LastUpdatedBy { get; set; }
    }
    

    That is simple and pretty with the six members making up six lines. What do we do in Java?

    public class Person
    {   
       @Column(name = "Id")
       private String _Id {get;set;}
       public String getFirstName() { return _Id ; }
       public void setFirstName() { _Id = value; }
    
       @Column(name = "FirstName")
       private String _FirstName {get;set;}
       public String getFirstName() { return _FirstName; }
       public void setFirstName(string value) { _FirstName = value; }
       
       // Sorry, it is too tedious to even type out the rest of the java example, 
       // I would have to create 16 more lines of code for remaining four columns. Ugh!!!
    }
    

    10. Making convention a language construct and not just a convention

    Multiple times, we have mentioned that trying to require the get and set convention and having tools key of magic strings (starts with “get” or starts with “set”) is not really a good practice. The convention cannot be enforced. I will say that Java has done a tremendous job of trying to enforce this convention. But in the end, it is still a questionable practice that keys off of magic strings that are not guaranteed to be there.

    However, by implementing simpler properties, the convention goes away. Everyone who wants property features gets them. Tools no longer have to key off of magic strings.

    One might argue that in C#, you can still write the Java way, by writing out getProperty() setProperty(Property value) methods, and that using Properties instead of methods is also only a convention. But that is not true and is shortsighted. Properties are properties. Whereas java only has two object members: member variables and methods; C# has three: member variables, properties, and methods. Properties are not just methods. As noted earlier, properties are separate in reflection, in a different list in the object type information. There is a clear and distinct difference between properties and methods and member variables and how they behave in C#. Because of this, magic strings are not needed to execute code.

    Don’t just copy, improve too

    Salesforce added C# like properties to Apex, their originally java-based language. Only they enhanced the properties by not requiring a separate backing field. In C#, if you call a property from the get, you create an infinite loop. In Apex, any calls to the variable inside the get don’t create an infinite loop. They copy and improved. Java should do the same.

    From the Apex documentation on properties:

    Apex properties are based on their counterparts in C#, with the following differences:

    • Properties provide storage for values directly. You do not need to create supporting members for storing values.
    • It is possible to create automatic properties in Apex. For more information, see Using Automatic Properties.

    This is outdated information as C# has had the second item, auto properties, for many years now. However, C# doesn’t have the first improvement yet. Good job Salesforce and Apex. They didn’t just see a good thing and copy it, they saw it, copied it, and improved on it.

    Properties Provide More Features

    The benefits are many and far more valuable than Java developers or even most C# developer realize. The Pyramid analogy is really accurate. There are so many little features of C# properties that the sum of the feature set is, like sum of bricks in a pyramid, huge.

    I surely missed many such features that properties provide.

    What features do properties give you that would benefit the Java language?
    What shorter syntaxes do properties give you over Java’s getter setter syntax?