My problem seemed to be with my client-side JavaScript code. I was writing code similar to the following:
// Bad example - DO NOT FOLLOW
$.ajax({
url: '/url/',
data: { 'Data': properties },
type: 'PUT'
}).fail(function() { alert('Oh no'); });
I changed a few lines of code, and everything began working as expected.
// Better example - could probably do better
$.ajax({
url: '/url/',
data: JSON.stringify({ 'Data': properties }),
contentType: 'application/json',
type: 'PUT'
}).fail(function() { alert('Oh no'); });
This version of the AJAX call specifies content type and uses a JSON string for the data.
According to the jQuery documentation for the ajax function, the default content type is ''application/x-www-form-urlencoded; charset=UTF-8". This default is inappropriate for this particular use case.
The call to JSON.stringify is also important because jQuery's .ajax() function does not convert the data for you.