secondo me non è il finally, ma la chiusura della connessione che c'e' dentro.
Ti ripeto, l'SQLDataReader è un oggetto connesso, non in memoria come il Dataset

Questo è il primo metodo che usavi, chiudevi sia il reader che la connessione.
Il finally viene eseguito sempre, è un problema di flusso e logica, l'errore che ottenevi infatti te lo diceva: "Invalid attempt to call FieldCount when reader is closed".
Inoltre non restituisci il reader nel punto giusto secondo me, andrebbe restituito alla fine...
codice:
public SqlDataReader ddlGruppi(int soluzione)
        {
            SqlDataReader reader = null;
            try
            {
                SqlCommand cmd = new SqlCommand("select_gruppi_soluzione", conn);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@soluzione#", soluzione);
                cmd.Connection = conn;
                conn.Open();
                reader = cmd.ExecuteReader();
                return reader;
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                if (reader != null)
                {
                    reader.Close();
                }
                conn.Close();
            }
        }