Implementing SQL function STR
Once you have the length of the integer portion, you can use the fx format specifier to get the correct number of decimals, which would clean up the string building part.

 return quantity.ToString("f" + (8 - length));


That should clean up the code some.

As I started typing that, I figured I'd check for edge cases too - since STR is filled with them (eg., it includes the negative sign in the length, returns ** if it overflows, etc.). You're handling the ** case, but a couple of edge-case values fail:

 Input       | Expected  | Actual
 999999999.5 | ********* | 1000000000
 123456789   | 123456789 | ArgOutOfRangeException
 123456789.5 | 123456790 | ArgOutOfRangeException
 -123456789  | ********* | ArgOutOfRangeException


I'd advise that if you're looking for 100% compatibility with STR here, you'll probably want some extensive unit tests.

Here's what I came up with that handles the edge-cases I threw at it, but I don't expect it's bullet proof either. Main changes are using the format specifier, and using .ToString to get the number of digits before the decimal place instead of Log10.

 public static string GetCustomStringQuantity(double quantity) {
    const int LENGTH = 9;
    // Include negative sign, just like STR()
    int numberOfIntDigits = Math.Round(quantity, MidpointRounding.AwayFromZero).ToString().Length;
    if (numberOfIntDigits == LENGTH) return quantity.ToString("f0");
    if (numberOfIntDigits &gt; LENGTH) return new string('*', LENGTH);

    int numberOfDecimals = LENGTH - numberOfIntDigits - 1; // include 1 for the decimal place
    return quantity.ToString("f" + numberOfDecimals); // uses MidpointRounding.AwayFromZero
}