static void

WebAPI Formatting

Json formatting

See Json.net.

Full error stack in your json:

#if DEBUG
            GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.LocalOnly;
#endif

Circular references

If an object has reference properties (Order.Product) by default you'll get repeated nested objects. If there's a back-reference, you get a Newtonsoft.Json.JsonSerializationException: "Self referencing loop detected for property 'x' with type 'z'". To create proper json references ("$id" properties), use:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling =
    Newtonsoft.Json.PreserveReferencesHandling.All;

For xml [DataContract(IsReference=true)]

Content Negotiation

Using a urlPathExtension- add this to the routes: (NB- {id}.{ext} will make IIS look for a physical file and 404)

config.Routes.MapHttpRoute(
    name: "DefaultApi With Extensions",
    routeTemplate: "api/{controller}.{ext}/{id}",
    defaults: new { id = RouteParameter.Optional }
);
 
config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

And in Application_Start/ WebApiConfig.Register:

// GET /Category.json/1 returns json (*requires route with {ext})
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(
    new System.Net.Http.Formatting.UriPathExtensionMapping("json", "application/json")
);
// GET /Category/1?format=json returns json
GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add(
    new System.Net.Http.Formatting.QueryStringMapping("format", "json", "application/json")
);

A simple CSV formatter (does not recurse reference properties):

 
public class CsvFormatter : System.Net.Http.Formatting.BufferedMediaTypeFormatter
{
    public CsvFormatter()
    {
        SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/csv"));
    }
    /// <summary>
    /// <code>GlobalConfiguration.Configuration.Formatters.Add(new CsvFormatter(new QueryStringMapping("format", "csv", "text/csv")));</code>
    /// </summary>
    public CsvFormatter(System.Net.Http.Formatting.MediaTypeMapping mediaTypeMapping)
        : this()
    {
        MediaTypeMappings.Add(mediaTypeMapping);
    }
 
    public override bool CanReadType(Type type)
    {
        return false; //writer, not reader
    }
 
    public override bool CanWriteType(Type type)
    {
        return true;
        //specific generic type
        //if (type == typeof(T))
        //{
        //    return true;
        //}
        //else
        //{
        //    var enumerableType = typeof(IEnumerable<T>);
        //    return enumerableType.IsAssignableFrom(type);
        //}
    }
 
    public override void WriteToStream(Type type, object value, Stream writeStream, HttpContent content)
    {
        using (var writer = new StreamWriter(writeStream))
        {
            //simple type
            if (value is string || value.GetType().IsValueType)
            {
                WriteItem(value, writer);
            }
            else
            {
                //enumerable
                var items = value as IEnumerable;
                if (items != null)
                {
                    foreach (var item in items)
                    {
                        WriteItem(item, writer);
                    }
                }
                else
                {
                    //single item
                    var item = value;
                    WriteItem(item, writer);
                }
            }
        }
        writeStream.Close();
    }
 
    private void WriteItem(Object obj, TextWriter writer)
    {
        var type = obj.GetType();
        if (type.IsValueType || type == typeof(string))
        {
            writer.WriteLine(Escape(obj));
            return;
        }
        if (_properties == null)
        {
            _properties = type.GetProperties();
        }
        foreach (var propertyInfo in _properties)
        {
            var propertyValue = Escape(propertyInfo.GetValue(obj));
            writer.Write(propertyValue + ",");
        }
        writer.WriteLine();
    }
 
    static readonly char[] SpecialChars = { ',', '\n', '\r', '"' };
    private PropertyInfo[] _properties;
 
    private string Escape(object o)
    {
        if (o == null)
            return "";
        if (o is DateTime)
        {
            var date = (DateTime)o;
            return date.ToString("O"); //ISO 8601
        }
        var field = o.ToString();
        if (field.IndexOfAny(SpecialChars) != -1)
            return String.Format("\"{0}\"", field.Replace("\"", "\"\""));
        return field;
    }
}