0

I am trying to pass byte[] as value and a string as text to Html.DropDownList using SelectList. However the values associated with the text in the dropdown show up as "System.Byte[]". This causes model binding issues which results in the following exception:

The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.FormatException: The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.

  1. I create a list of BAModels
  2. Inside the create Action I save the list as ViewBag.site_OID
  3. Then in the view I use the above item from ViewBag in the @Html.DropDownList

Model:

public class BAModel
{
    public byte[] mfg_site_OID { get; set; }
    public string mfg_site_id { get; set; }
}

Action:

 public ActionResult Create()
    {
        //ViewBag.site_OID = new SelectList(db.mfg_site, "mfg_site_OID", "mfg_site_id");
        var BAList = new List<BAModel>();
        BAList.Add(new BAModel { mfg_site_OID= new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, mfg_site_id ="london" });
        BAList.Add(new BAModel { mfg_site_OID = new byte[] { 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21 }, mfg_site_id = "new york" });
        ViewBag.site_OID = new SelectList(BAList, "mfg_site_OID", "mfg_site_id");
        return View();
    }

Relevant code from the View:

@{
    ViewBag.Title = "Create";
    SelectList list = ViewBag.site_OID;
}
<div class="form-group">
    @Html.LabelFor(model => model.site_OID, "site_OID", htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.DropDownList("site_OID", list, htmlAttributes: new { @class = "form-control" })
        @Html.ValidationMessageFor(model => model.site_OID, "", new { @class = "text-danger" })
    </div>
</div>

So it seems new SelectList(BAList, "mfg_site_OID", "mfg_site_id") when translates to DropDownList is not understanding the byte[] and using the data type instead. Looking for help on how to fix this from anyone who have used byte[] as the value of the DropDownList items.

user3885927
  • 3,363
  • 2
  • 22
  • 42
  • Could you not use string? – Win Jul 19 '17 at 23:26
  • I simplified the issue with a mock model but in reality I am dealing with a pre-existing SQL Server DB with OID columns that are of binary type. Binary turns into byte[] in .Net models. – user3885927 Jul 19 '17 at 23:29
  • What is stored in the binary column? That table doesn't have any primary key column which you can use to bind to dropdownlist? – Chetan Jul 19 '17 at 23:39

1 Answers1

0

Answer is you cannot. SelectListItem requires string value, so you will need to convert to Base64String if you really want to store as Byte Array.

public class BAModel
{
    public string mfg_site_OID { get; set; }
    public string mfg_site_id { get; set; }
}

mfg_site_OID = Convert.ToBase64String(new byte[] { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 })

Then you convert back to Byte Array on postback to get the original value.

If you want to know more about DropDownList in MVC, I suggest you to look at this answer.

Win
  • 61,100
  • 13
  • 102
  • 181
  • 1
    It should be noted that doing this, in general is a hugely *bad* idea. Using a byte[] as your value means that you have to actually send down all this data embedded in your HTML document. Worse, since you must convert to Base64 in order to actually do this, the data you're including in the HTML expands by roughly 150%, since Base64 will use multiple bytes in the string to encode a single byte in the array. Depending on the size of these byte arrays, you could be forcing a download of megabytes or even gigabytes simply to render an HTML document. In other words, **don't**. – Chris Pratt Jul 19 '17 at 23:58