Created
August 16, 2013 07:55
-
-
Save andreea-anastasescu/6248104 to your computer and use it in GitHub Desktop.
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
namespace Me.WebApi.Mobile | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.IO; | |
using System.Net; | |
using System.Net.Http.Formatting; | |
using System.Net.Http.Headers; | |
using System.Threading.Tasks; | |
using System.Net.Http; | |
using Newtonsoft.Json.Converters; | |
/// <summary> | |
/// Media formatter used to produce customized json serialization so that a root element is produced in the json for classes decorated with <see cref="JsonCustomRootAttribute"/>. | |
/// </summary> | |
public class RootFormatter : JsonMediaTypeFormatter | |
{ | |
private string rootFieldName = null; | |
/// <summary> | |
/// Initializes a new instance of the RootFormatter class. | |
/// </summary> | |
public RootFormatter() | |
{ | |
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); | |
} | |
/// <summary> | |
/// Determines whether this <see cref="T:System.Net.Http.Formatting.JsonMediaTypeFormatter"/> can write objects of the specified <paramref name="type"/>. | |
/// </summary> | |
/// <returns> | |
/// true if objects of this <paramref name="type"/> can be written, otherwise false. | |
/// </returns> | |
/// <param name="type">The type of object that will be written.</param> | |
public override bool CanWriteType(Type type) | |
{ | |
return true; | |
} | |
/// <summary> | |
/// Returns a specialized instance of the <see cref="T:System.Net.Http.Formatting.MediaTypeFormatter"/> that can format a response for the given parameters. | |
/// </summary> | |
/// <returns> | |
/// Returns <see cref="T:System.Net.Http.Formatting.MediaTypeFormatter"/>. | |
/// </returns> | |
/// <param name="type">The type to format.</param><param name="request">The request.</param><param name="mediaType">The media type.</param> | |
public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, System.Net.Http.HttpRequestMessage request, MediaTypeHeaderValue mediaType) | |
{ | |
var formatter = new RootFormatter() | |
{ | |
rootFieldName = GetRootFieldName(type) | |
}; | |
// You have to reapply any JSON.NET default serializer Customizations here | |
formatter.SerializerSettings.Converters.Add(new StringEnumConverter()); | |
formatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; | |
return formatter; | |
} | |
/// <summary> | |
/// Writes an object of the specified <paramref name="type"/> to the specified <paramref name="writeStream"/>. This method is called during serialization. | |
/// </summary> | |
/// <returns> | |
/// A <see cref="T:System.Threading.Tasks.Task"/> that will write the value to the writeStream. | |
/// </returns> | |
/// <param name="type">The type of object to write.</param><param name="value">The object to write.</param><param name="writeStream">The <see cref="T:System.IO.Stream"/> to which to write.</param> | |
/// <param name="writeStream"></param> | |
/// <param name="content">The <see cref="T:System.Net.Http.HttpContent"/> where the content is being written.</param><param name="transportContext">The <see cref="T:System.Net.TransportContext"/>.</param> | |
public override Task WriteToStreamAsync(Type type, object value, | |
Stream writeStream, | |
HttpContent content, | |
TransportContext transportContext) | |
{ | |
if (string.IsNullOrEmpty(rootFieldName)) | |
{ | |
Task task = base.WriteToStreamAsync(type, value, writeStream, content, transportContext); | |
return task; | |
} | |
StreamWriter writer = null; | |
// write the pre-amble | |
try | |
{ | |
writer = new StreamWriter(writeStream); | |
writer.Write("{\"" + rootFieldName + "\":"); | |
writer.Flush(); | |
} | |
catch (Exception ex) | |
{ | |
try | |
{ | |
if (writer != null) | |
writer.Dispose(); | |
} | |
catch { } | |
var tcs = new TaskCompletionSource<object>(); | |
tcs.SetException(ex); | |
return tcs.Task; | |
} | |
return base.WriteToStreamAsync(type, value, writeStream, content, transportContext) | |
.ContinueWith(innerTask => | |
{ | |
if (innerTask.Status == TaskStatus.RanToCompletion) | |
{ | |
writer.Write("}"); | |
writer.Flush(); | |
} | |
}, TaskContinuationOptions.ExecuteSynchronously) | |
.ContinueWith(innerTask => | |
{ | |
writer.Dispose(); | |
return innerTask; | |
}, TaskContinuationOptions.ExecuteSynchronously) | |
.Unwrap(); | |
} | |
/// <summary> | |
/// | |
/// </summary> | |
/// <param name="type"></param> | |
/// <returns></returns> | |
/// <exception cref="ArgumentNullException"></exception> | |
protected string GetRootFieldName(Type type) | |
{ | |
if (type == null) throw new ArgumentNullException(); | |
JsonCustomRootAttribute customRootAttribute; | |
if (type.IsGenericType && | |
type.GetGenericTypeDefinition() == typeof (IEnumerable<>)) | |
{ | |
customRootAttribute = GetSimpleTypeRootFieldName(type.GetGenericArguments()[0]); | |
if (customRootAttribute == null) | |
return null; | |
return customRootAttribute.CollectionTitle; | |
} | |
customRootAttribute = GetSimpleTypeRootFieldName(type); | |
if (customRootAttribute == null) | |
return null; | |
return customRootAttribute.Title; | |
} | |
/// <summary> | |
/// | |
/// </summary> | |
/// <param name="type"></param> | |
/// <returns></returns> | |
protected JsonCustomRootAttribute GetSimpleTypeRootFieldName(Type type){ | |
IEnumerable<JsonCustomRootAttribute> attributes = | |
from x in type.GetCustomAttributes(typeof(JsonCustomRootAttribute), true) | |
select x as JsonCustomRootAttribute; | |
if (attributes.Count() == 0) | |
{ | |
return null; | |
} | |
return attributes.First(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment