Last active
October 19, 2016 04:20
-
-
Save ewoo/6083179 to your computer and use it in GitHub Desktop.
A custom MediaTypeFormatter for wrangling incoming form-url-encoded snake case (ruby-style) field names into regular property names such that ASP.NET Web API's plumbing can properly bind them to .NET model objects.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Collections.Specialized; | |
using System.Diagnostics.CodeAnalysis; | |
using System.IO; | |
using System.Net.Http; | |
using System.Net.Http.Formatting; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using System.Web.Http.ModelBinding; | |
namespace WebApiExample | |
{ | |
/// <summary> | |
/// Acts much like the built-in JQueryMvcFormUrlEncodedFormatter but instead, escapes snake-case | |
/// property names and performs parameter binding with models having CamelCase property names. | |
/// </summary> | |
public class SnakCaseFormUrlEncodedMediaTypeFormatter : FormUrlEncodedMediaTypeFormatter | |
{ | |
public override bool CanReadType(Type type) | |
{ | |
if (type == null) | |
{ | |
throw new ArgumentNullException("type"); | |
} | |
return true; | |
} | |
private static FormDataCollection RewritePropertyNames(FormDataCollection formData) | |
{ | |
var keypairs = new List<KeyValuePair<string, string>>(); | |
foreach (var pair in formData) | |
{ | |
// Remove underscores from property names. That's it!!! | |
var propertyName = pair.Key.Replace("_", ""); | |
keypairs.Add(new KeyValuePair<string, string>(propertyName, pair.Value)); | |
} | |
return new FormDataCollection(keypairs); | |
} | |
// This method is a slightly modifie version of JQueryMvcFormUrlEncodedFormatter's implementation. | |
public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, | |
IFormatterLogger formatterLogger) | |
{ | |
if (type == (Type) null) | |
throw new ArgumentNullException("type"); | |
if (readStream == null) | |
throw new ArgumentNullException("readStream"); | |
if (base.CanReadType(type)) | |
return base.ReadFromStreamAsync(type, readStream, content, formatterLogger); | |
// The following expression could probably be better expressed by someone who's saavier with Tasks. | |
return base.ReadFromStreamAsync(typeof (FormDataCollection), readStream, content, formatterLogger) | |
.ContinueWith( | |
(obj => | |
{ | |
var local = RewritePropertyNames((FormDataCollection) obj.Result); | |
try | |
{ | |
return FormDataCollectionExtensions.ReadAs(local, type, string.Empty, | |
this.RequiredMemberSelector, | |
formatterLogger); | |
} | |
catch (Exception ex) | |
{ | |
if (formatterLogger == null) | |
{ | |
throw; | |
} | |
else | |
{ | |
formatterLogger.LogError(string.Empty, ex); | |
return MediaTypeFormatter.GetDefaultValueForType(type); | |
} | |
} | |
}), new CancellationToken()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's the wire-up code: