Random Points on Cylinder Surface

There appears to be no other way than to calculate the surface area of the three sections of the cylinder (top cap, body, bottom cap) and then use the random number generator to decide which section of the cylinder our point will be on:

/// <summary>Returns a random point on the surface of a cylinder</summary>
/// <param name="randomNumberGenerator">Random number generator that will be used</param>
/// <param name="orientation">Orientation of the cylinder</param>
/// <param name="radius">Radius of the cylinder</param>
/// <param name="length">Length of the cylinder</param>
/// <returns>A random point on the volume's surface</returns>
public static Vector3 GenerateRandomPointOnSurface(
  System.Random randomNumberGenerator,
  Matrix orientation, float radius, float length
) {

  // Calculate the surface areas of the three sections our cylinder has:
  // Upper cap, side and lower cap
  float capArea = MathHelper.Pi * (radius * radius);
  float sideArea = 2.0f * MathHelper.Pi * radius * length;
  float capAndSideArea = capArea + sideArea;

  // We need a phi value (angle of the random point) in any of the cases
  float phi = (float)randomNumberGenerator.NextDouble() * MathHelper.TwoPi;

  // Choose the section that the random point will be generated on in relation
  // to its surface area so the probability is constant on the entire surface
  float section = (float)randomNumberGenerator.NextDouble() * (capArea * 2.0f + sideArea);

  // Depending on the section, these two values are calculated differently
  float randomRadius;
  float randomZ;

  // Upper cap: Generate a random radius
  if(section < capArea) {
    randomZ = length / 2.0f;
    randomRadius = (float)Math.Sqrt(randomNumberGenerator.NextDouble()) * radius;

  // Side: Generate a random height
  } else if(section < capAndSideArea) {
    randomZ = ((float)randomNumberGenerator.NextDouble() - 0.5f) * length;
    randomRadius = radius;

  // Lower cap: Generate a random radius
  } else {
    randomZ = -length / 2.0f;
    randomRadius = (float)Math.Sqrt(randomNumberGenerator.NextDouble()) * radius;
  }

  // Now transform the point to cartesian coordinates and rotate it into
  // the global coordinate frame
  return Vector3.Transform(
    new Vector3(
      randomRadius * (float)Math.Cos(phi),
      randomRadius * (float)Math.Sin(phi),
      randomZ
    ),
    orientation
  );

}