Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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.Web;
using System.Net.Http;
using Newtonsoft.Json.Converters;
using System.Web.Http;
// based on http://www.west-wind.com/weblog/posts/2012/Apr/02/Creating-a-JSONP-Formatter-for-ASPNET-Web-API
namespace FooService
{
public class RootFormatter: JsonMediaTypeFormatter
{
private string RootFieldName = null;
public RootFormatter()
{
SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json"));
// SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));
}
public override bool CanWriteType(Type type)
{
return true;
}
public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, System.Net.Http.HttpRequestMessage request, MediaTypeHeaderValue mediaType)
{
var formatter = new RootFormatter()
{
RootFieldName = GetRootFieldName(type)
};
// this doesn't work unfortunately
//formatter.SerializerSettings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
// 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;
}
public override Task WriteToStreamAsync(Type type, object value,
Stream stream,
HttpContent content,
TransportContext transportContext)
{
if (string.IsNullOrEmpty(RootFieldName))
return base.WriteToStreamAsync(type, value, stream, content, transportContext);
StreamWriter writer = null;
// write the pre-amble
try
{
writer = new StreamWriter(stream);
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, stream, content, transportContext)
.ContinueWith(innerTask =>
{
if (innerTask.Status == TaskStatus.RanToCompletion)
{
writer.Write("}");
writer.Flush();
}
}, TaskContinuationOptions.ExecuteSynchronously)
.ContinueWith(innerTask =>
{
writer.Dispose();
return innerTask;
}, TaskContinuationOptions.ExecuteSynchronously)
.Unwrap();
}
protected string GetRootFieldName(Type type)
{
var attrs =
from x in type.CustomAttributes
where x.AttributeType == typeof(Newtonsoft.Json.JsonObjectAttribute)
select x;
if (attrs.Count() < 1)
{
return null;
} // if
var titles =
from arg in attrs.First().NamedArguments
where arg.MemberName == "Title"
select arg.TypedValue.Value.ToString();
if (titles.Count() < 1)
{
return null;
} // if
return titles.First();
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace FooService
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
GlobalConfiguration.Configuration.Formatters.Insert(0, new RootFormatter());
}
}
}
@goyaweb

This comment has been minimized.

Copy link

commented Oct 16, 2013

Getting this error:
Error 10 'System.Type' does not contain a definition for 'CustomAttributes' and no extension method 'CustomAttributes' accepting a first argument of type 'System.Type' could be found (are you missing a using directive or an assembly reference?)

@sephwrath

This comment has been minimized.

Copy link

commented Jan 17, 2014

If you update the GetRootFieldName function as follows it will handle generic lists as well.

    protected string GetRootFieldName(Type type)
    {
        if (type.IsGenericType)
        {
            Type[] args = type.GetGenericArguments();
            if (args.Length > 0) type = args[0];
        }
        var attrs =
            from x in type.CustomAttributes
            where x.AttributeType == typeof(Newtonsoft.Json.JsonObjectAttribute)
            select x;
        if (attrs.Count() < 1)
        {
            return null;
        } // if

        var titles =
            from arg in attrs.First().NamedArguments
            where arg.MemberName == "Title"
            select arg.TypedValue.Value.ToString();
        if (titles.Count() < 1)
        {
            return null;
        } // if
        return titles.First();
    }
@jbalajkpm

This comment has been minimized.

Copy link

commented Apr 3, 2014

Getting error:
Error 10 'System.Type' does not contain a definition for 'CustomAttributes' and no extension method 'CustomAttributes' accepting a first argument of type 'System.Type' could be found (are you missing a using directive or an assembly reference?)

Can someone please help?

@eibrahim

This comment has been minimized.

Copy link

commented Apr 9, 2014

thanks for your help, i have tweaked a little more at https://gist.github.com/eibrahim/10286724 to be more dynamic and handle arrays/enumerables and generics.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.