MVC3 - posting byte array to a controller - Database RowVersion

15,183

Solution 1

My client side ViewModel contains a SQL Server RowVersion property, which is a byte[]

Make it so that instead of a byte[] your view model contains a string property which is the base64 representation of this byte[]. Then you won't have any problems roundtripping it to the client and back to the server where you will be able to get the original byte[] from the Base64 string.

Solution 2

Json.NET automatically encodes byte arrays as Base64.

You can use JsonNetResult instead of JsonResult:

from https://gist.github.com/DavidDeSloovere/5689824:

using System;
using System.Web;
using System.Web.Mvc;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

public class JsonNetResult : JsonResult
{
    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        var response = context.HttpContext.Response;

        response.ContentType = !string.IsNullOrEmpty(this.ContentType) ? this.ContentType : "application/json";

        if (this.ContentEncoding != null)
        {
            response.ContentEncoding = this.ContentEncoding;
        }

        if (this.Data == null)
        {
            return;
        }

        var jsonSerializerSettings = new JsonSerializerSettings();
        jsonSerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
        jsonSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        var formatting = HttpContext.Current != null && HttpContext.Current.IsDebuggingEnabled ? Formatting.Indented : Formatting.None;
        var serializedObject = JsonConvert.SerializeObject(Data, formatting, jsonSerializerSettings);
        response.Write(serializedObject);
    }
}

Usage:

[HttpPost]
public JsonResult Save(Contact contact) {
    return new JsonNetResult { Data = _contactService.Save(contact) };
}
Share:
15,183

Related videos on Youtube

Garry English
Author by

Garry English

Updated on June 06, 2022

Comments

  • Garry English
    Garry English about 2 years

    I am working on an MVC3 application. My client side ViewModel contains a SQL Server RowVersion property, which is a byte[]. It is rendered as an Object array on the client side. When I attempt to post my view model to a controller, the RowVersion property is always null.

    I am assuming that the Controller serializer (JsonValueProviderFactory) is ignoring the Object array property.

    I have seen this blog, however this does not apply, as I am posting JSON and not the form markup: http://thedatafarm.com/blog/data-access/round-tripping-a-timestamp-field-with-ef4-1-code-first-and-mvc-3/

    My view renders my viewmodel like so:

    <script type="text/javascript">
      var viewModel = @Html.Raw( Json.Encode( this.Model ) );
    </script>
    

    I then post the viewModel to the controller like so:

        var data = {
            'contact': viewModel
        };
    
        $.ajax({
            type: 'POST',
            url: '/Contact/Save',
            contentType: "application/json; charset=utf-8",
            data: JSON.stringify(data),
            dataType: 'json',
            success: function (data) {
                // Success
            },
            error: function (XMLHttpRequest, textStatus, errorThrown) {
                alert(XMLHttpRequest.responseText);
            }
        });
    

    Here is my action in the controller:

      [HttpPost]
      public JsonResult Save(Contact contact) {
         return this.Json( this._contactService.Save( contact ) );
      }
    

    UPDATE: based on Darin's answer.

    I was hoping for a cleaner solution, but since Darin provided the only answer, I will have to add a custom property that will serialize my byte[] "row_version" property to a Base64 string. And when the Base64 string is set to the new custom property, it converts the string back to a byte[]. Below is the custom "RowVersion" property that I added to my model:

      public byte[] row_version {
         get;
         set;
      }
    
      public string RowVersion {
         get {
    
            if( this.row_version != null )
               return Convert.ToBase64String( this.row_version );
    
            return string.Empty;
         }
         set {
    
            if( string.IsNullOrEmpty( value ) )
               this.row_version = null;
            else
               this.row_version = Convert.FromBase64String( value );
         }
      }
    
    • Tocco
      Tocco almost 13 years
      Hey, can you post your controller action code?
    • Tocco
      Tocco almost 13 years
      Hey @Darin Dimitrov, Can you add the serialization tag?
    • Tocco
      Tocco almost 13 years
      See it. A similar question on SO
    • Garry English
      Garry English almost 13 years
      Tocco - adding jQuery.ajaxSettings.traditional did not help
  • Maksim Vi.
    Maksim Vi. about 10 years
    Convert.ToBase64String(byte[])
  • Christos
    Christos over 7 years
    very nice solution (+1) !