Q:

Existe alguma diferença em utilizar o método Read() do objeto SqlDataReader?

Estou executando o trecho de código abaixo, porém, fiquei com dúvida relacionada ao método Read() do objeto SqlDataReader.
using (SqlDataReader reader = cmd.ExecuteReader())
{
    if (reader.HasRows)
    {
        if (reader.Read())
        {
             pconfigWS.Usuario = reader["usuario"].ToString();
             pconfigWS.Senha = reader["senha"].ToString();
             pconfigWS.EndConWSPorto = reader["endConWSPorto"].ToString();
        }
    }
}

Gostaria de saber se existe diferença em usar While(reader.Read()), if(reader.Read()) e reader.Read()
Sei que o resultado da query será apenas uma linha, porém, estou com essa dúvida.
Alguém sabe dizer ?
Obrigado

A:

Cada chamada a Read() vai avançar a leitura dos resultados da pesquisa.
Nesse caso, a diferença seria:
//contiuna lendo o próixmo até não houver mais
while (reader.Read())
{
  ...
}

//lê o próximo e me fala se for sucedido...
if (reader.Read())
{
  ...
}

//lê o próximo
reader.Read();

Acho importante saber que if(reader.Read()) vai avançar até o próximo registro, então o próximo reader.Read() vai ser o registro seguinte, não o atual.
Por exemplo, seu códio explicado:
using (SqlDataReader reader = cmd.ExecuteReader())
{
    if (reader.HasRows) //verifique se o leitor tem dado algum
    {
        if (reader.Read()) //lê os dados - se tiver mais de um registro, não está sendo lido
        {
             pconfigWS.Usuario = reader["usuario"].ToString();
             pconfigWS.Senha = reader["senha"].ToString();
             pconfigWS.EndConWSPorto = reader["endConWSPorto"].ToString();
        }
    }
}

E um exemplo que pode dar resultados inesperados:
using (SqlDataReader reader = cmd.ExecuteReader())
{
    List<PConfigWS> resultados = new List<obj>();
    if (reader.Read())
    {
        while (reader.Read())
        {
             var pconfigWS = new PConfigWS();
             pconfigWS.Usuario = reader["usuario"].ToString();
             pconfigWS.Senha = reader["senha"].ToString();
             pconfigWS.EndConWSPorto = reader["endConWSPorto"].ToString();
             resultados.Add(pconfigWS);
        }
    }
}

Nesse caso, o primeiro registro seria ignorado (por causa do if(reader.Read()), que provavelmente não seria o resultado desejado. Usar reader.HasRows seria a maneira certa, como você usou.
Não há necessariamente 'boas práticas' entre essas funções - são literalmente a mesma função, sendo utilizada em formas diferentes. Tudo depende se você está lendo apenas um registro ou vários.

