2016-05-05 21 views
2

Ich versuche, ein Attribut zu erstellen, die Datenrückgabe aus einer Aktion andersWebAPI Vorübergehend außer Kraft setzen JsonFormatter von OnActionExecuted

public override void OnActionExecuted(HttpActionExecutedContext filterContext) 
{ 
    var content = (filterContext.Response.Content as ObjectContent); 

    if (content == null) 
    { 
     return; 
    } 

    if (content.ObjectType.IsGenericType 
     && content.ObjectType.GetGenericTypeDefinition() == typeof (Page<>)) 
    { 
     var pageObject = (content.Value as IPage); 
     var jsonFormatterRule = new JsonFormatterRule(); 
     var pageJson = JsonConvert.SerializeObject(pageObject.ItemsArray, 
               jsonFormatterRule.GetPascalCasedSettings()); 

     //How do I set the content that \/ doesn't compile? 
     //filterContext.Response.Content = pageJson; 
    } 
} 

Dies ist die JsonFormatterRules Incase jemand sie sehen wollte serialisiert werden.

public JsonSerializerSettings GetDefaultSettings() 
{ 
    var settings = new JsonSerializerSettings() 
    { 
     Formatting = Formatting.Indented, 
     ContractResolver = new CamelCasePropertyNamesContractResolver(), 
     DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind, 
    }; 

    settings.Converters.AddRange(defaultConfiguredConverters); 
    return settings; 
} 

public JsonSerializerSettings GetPascalCasedSettings() 
{ 
    var settings = this.GetDefaultSettings(); 
    settings.ContractResolver = new DefaultContractResolver(); 

    return settings; 
} 

Wie kann ich den Inhalt von aus ausgeführte Aktion festlegen? Ich kann den Standard-Serializer nicht global auf DefaultContract ändern, da dies Threading-Probleme verursachen kann.

Auch würde ich lieber keine neue Antwort erstellen und kopieren Sie die Header aus dem alten, die wie über töten scheint.

+0

Was möchten Sie genau machen? Haben Sie für einige Aktionen einen anderen Serializer? – dotctor

+0

@dotctor Ja Verschiedene Serializer von einigen Aktionen basierend auf einem Attribut –

Antwort

1

Eine Möglichkeit wäre, einen benutzerdefinierten Formatierer zu definieren.

Zunächst definieren Ihr Attribut:

[AttributeUsage(AttributeTargets.Class)] 
public sealed class SpecialSerializeAttribute : Attribute 
{ 
} 

nun einen Formatierer erstellen, die das Attribut finden:

public class SpecialSerializeFormatter : MediaTypeFormatter 
{ 
    public SpecialSerializeFormatter() 
    { 
     //You can add any other supported types here. 
     this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); 
    } 

    public override bool CanReadType(Type type) 
    { 
     //you can just return false if you don't want to read any differently than your default way 
     //if you return true here, you should override the ReadFromStreamAsync method to do custom deserialize 
     return type.IsDefined(typeof(SpecialSerializeAttribute), true)); 
    } 

    public override bool CanWriteType(Type type) 
    { 
     return type.IsDefined(typeof(SpecialSerializeAttribute), true)); 
    } 

    public override async Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, 
     TransportContext transportContext) 
    { 

     //value will be your object that you want to serialize 

     //add any custom serialize settings here 
     var json = JsonConvert.SerializeObject(value); 

     //Use the right encoding for your application here 
     var byteArray = Encoding.UTF8.GetBytes(json); 
     await writeStream.WriteAsync(byteArray, 0, byteArray.Length); 
    } 
} 

Registrieren Sie den Formatierer in Ihnen

Sie können auch bauen WebApiConfig.cs ein Formatierer für jeden Typ direkt und dann müssen Sie das Attribut nicht tun. Ändern Sie einfach Ihre CanRead- und CanWrite-Methoden. Ich finde, dass das Basieren dieser direkten Typen bessere Ergebnisse liefert, da es nicht so ein generischer Formatierer ist und Sie müssen möglicherweise benutzerdefinierte Logik basierend auf dem Typ anwenden, aber die obige Antwort sollte Sie bekommen, was Sie brauchen.

+0

Wow, ich wusste nicht einmal, dass Sie es so machen könnten. Ich werde es jetzt testen –

0

Wenn jemand sich gefragt hat, ist Response Content ein HTTPContent, der von ByteArrayContent erbt. Wenn Sie also bereits JSON serialisiert haben, müssen Sie es nur in ein Byte-Array einfügen.

filterContext.ActionContext.Response.Content = new ByteArrayContent(Encoding.ASCII.GetBytes(pageJson)); 
+1

Gut zu wissen. Stellen Sie sicher, dass ASCII das ist, was Sie wollen. Wenn Sie von Benutzern generierte Inhalte haben, die serialisiert werden, sollten Sie UTF8 verwenden, damit alle Sonderzeichen serialisiert werden können. – ManOVision