0

So I'm using the MySql.Data package for my .NET Core project and store password hashes and salts (of type byte[]) as varbinary() to the database. When selecting the password hash and salt from a user I need a way to convert the result back to a byte array. Given this sample code

Stream passwordHashStream = dbDataReader.GetStream(0);
byte[] passwordHash;
                        
using (MemoryStream memoryStream = new MemoryStream())
{
    await passwordHashStream.CopyToAsync(memoryStream);
    passwordHash = memoryStream.ToArray();
}

the first line will throw this exception

System.IndexOutOfRangeException: Data index must be a valid index in the field at MySql.Data.MySqlClient.Interceptors.ExceptionInterceptor.Throw(Exception exception) at MySql.Data.MySqlClient.MySqlConnection.Throw(Exception ex) at MySql.Data.MySqlClient.MySqlDataReader.Throw(Exception ex) at MySql.Data.MySqlClient.MySqlDataReader.GetBytes(Int32 i, Int64 fieldOffset, Byte[] buffer, Int32 bufferoffset, Int32 length) at System.Data.Common.DbDataReader.GetStream(Int32 ordinal) at Infrastructure.Persistence.Repositories.UsersRepository.<>c.<b__1_0>d.MoveNext() in /.../Infrastructure/Persistence/Repositories/UsersRepository.cs:line 60

although the reader contains the correct database results as you can see here down below (password is 32 bytes, hash is 16 bytes)

enter image description here

The error was reported in 2018

https://bugs.mysql.com/bug.php?id=93374

and has a verified status. Are there any good solutions / workarounds on how to solve it? I don't want to use the GetBytes method because it requires me to pass in the length of the byte array and I would like to stay independent from that.

3
  • Does GetItem(0) cast to byte[] work? Commented Jul 11, 2020 at 12:26
  • sorry, this method does not exist. dbDataReader.GetItem(0) Commented Jul 11, 2020 at 13:05
  • My bad, wrong namespace Commented Jul 11, 2020 at 14:14

2 Answers 2

2

Uninstall MySql.Data and replace it with MySqlConnector.

(Disclosure: I'm the reporter of the MySql bug you found and the primary contributor to MySqlConnector.)

As well as fixing that issue and many other bugs, MySqlConnector adds true async I/O support and performance improvements.

I don't want to use the GetBytes method because it requires me to pass in the length of the byte array and I would like to stay independent from that.

If you don't want to switch libraries, a little-known feature of GetBytes (supported by both MySql.Data and MySqlConnector) is that passing in a null buffer returns the needed length, so you don't need to hard-code it:

// get the length of the column and allocate a buffer
var length = dbDataReader.GetBytes(0, 0, null, 0, 0);
var passwordHash = new byte[length];

// fill the buffer from the column
dbDataReader.GetBytes(0, 0, passwordHash, 0, passwordHash.Length);
Sign up to request clarification or add additional context in comments.

Comments

0

public static async Task<MemoryStream> ToMemoryStream(this Stream stream)
    {
      var memStream = stream as MemoryStream;
      if (memStream == null)
      {
        memStream = new MemoryStream();
        await stream.CopyToAsync(memStream);
      }
      return memStream;
    }

2 Comments

sorry, I don't understand your solution. Could you explain it a little bit?
Asy function should call from asy function .I am not aware the function where you call CopyToAsync

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.