2012-08-07 19 views
112

私はmvc 4 web apiとasp.net webforms 4.0を使用して残りのAPIを作成しています。それは素晴らしいです:web apiでプロパティがシリアル化されないようにします

[HttpGet] 
public HttpResponseMessage Me(string hash) 
{ 
    HttpResponseMessage httpResponseMessage; 
    List<Something> somethings = ... 

    httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK, 
           new { result = true, somethings = somethings }); 

    return httpResponseMessage; 
} 

今私はいくつかのプロパティのシリアル化を防ぐ必要があります。私はリスト上でいくつかのlinqを使うことができ、私が必要とするプロパティだけを得ることができ、一般的には良いアプローチですが、現在のシナリオではsomethingオブジェクトが複雑すぎます。実行時に無視する各プロパティをマークする方が簡単です。

これを行う方法はありますか?

+0

プロパティにScriptIgnoreを追加できます。この質問を見るhttp://stackoverflow.com/questions/10169648/how-to-exclude-property-from-json-serialization – atbebtg

答えて

3

あなたはAutoMapperを使用して.Ignore()マッピングを使用して、マップされたオブジェクトに

CreateMap<Foo, Foo>().ForMember(x => x.Bar, opt => opt.Ignore()); 
138

ASP.NETのWeb APIを送信することができるかもしれませんが、デフォルトフォーマッタとしてJson.Netを使用していますので、あなたのアプリケーションは、ちょうどのみのデータとしてJSONを使用している場合

public class Foo 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    [JsonIgnore] 
    public List<Something> Somethings { get; set; } 
} 

をしかし、この方法は、XML形式をサポートしていません:フォーマット、あなたはシリアル化のためのプロパティを無視する[JsonIgnore]を使用することができます。だから、あなたのアプリケーションサポートXML形式により(または唯一のサポートXML)を有している場合には、代わりにJson.Netを使用しての、あなたが[DataContract]を使用する必要がありますJSONとXMLの両方をサポートしている:

[DataContract] 
public class Foo 
{ 
    [DataMember] 
    public int Id { get; set; } 
    [DataMember] 
    public string Name { get; set; } 

    //Ignore by default 
    public List<Something> Somethings { get; set; } 
} 

より理解するために、することができますofficial articleを読んでください。

+0

私は、jsonignoreを使って実行時に属性を追加したり削除したりする方法を見つけなければならないと思います。 – user1330271

+0

チャームのように働きました!感謝: –

+0

JsonIgnore属性がXML応答でサポートされていないのはなぜ悲しいですか? – Mukus

95

明示的にデフォルトのXMLシリアライザのためのJSONシリアライザまたは[IgnoreDataMember]ため[JsonIgnore]を使用することができますいずれかのプロパティにシリアル化を防ぐためのWeb APIドキュメントページJSON and XML Serialization in ASP.NET Web APIによります。

しかし、私は[IgnoreDataMember]がXMLとJsonの両方のリクエストのシリアル化を防ぐことに気が付いたので、複数の属性を持つプロパティをデコレートするのではなく、その使用をお勧めします。

+2

これは良い答えです。 1つの属性でXMLとJSONを扱います。 – Oliver

+15

悲しいことに、 '[IgnoreDataMember]'は遅延ロードされたEF 6プロキシオブジェクト(仮想プロパティ)で動作しないようです。しかし、 '[DataContract]'と '[DataMember]'は行います。 – Nick

21

のすべてをデフォルトでシリアル化する代わりに、「オプトイン」アプローチをとることができます。このシナリオでは、指定したプロパティのみがシリアル化されます。これはSystem.Runtime.Serialization名前空間にあるDataContractAttributeDataMemberAttributeで行います。

DataContactAttributeは、クラスに適用され、DataMemberAttributeはあなたがシリアライズしたい各メンバーに適用されます。

[DataContract] 
public class MyClass { 

    [DataMember] 
    public int Id { get; set;} // Serialized 

    [DataMember] 
    public string Name { get; set; } // Serialized 

    public string DontExposeMe { get; set; } // Will not be serialized 
} 

は、私はそれがおよそ明示的な意思決定を行うためにあなたを強制するので、これはより良いアプローチですあえて言いますシリアライゼーションを通じて何を作るかしないか。また、JSON.netでシリアライズしている他の場所でJSON.netに依存することなく、モデルクラスを自分でプロジェクトに生かすこともできます。

+1

継承されたメンバーを非表示にするために.Net Coreを使用していた唯一のアプローチ。 XMLとJsonの両方のシリアル化に対応しています。 Kudos – Piou

+0

同じ機能が必要ですが、どのapiメソッドが呼び出されたか、api呼び出しごとに異なるデータが必要かによって、プロパティが含まれるか除外されるかが決まります。任意の提案 –

18

これは私のために働いた:文字列配列型のAllowListと呼ばれるパブリックプロパティを持つカスタムコントラクトリゾルバを作成します。アクションでは、アクションが返す必要のあるものに応じて、そのプロパティを変更します。

1。カスタム契約リゾルバを作成します。アクションで

public class PublicDomainJsonContractResolverOptIn : DefaultContractResolver 
{ 
    public string[] AllowList { get; set; } 

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
    { 
     IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization); 

     properties = properties.Where(p => AllowList.Contains(p.PropertyName)).ToList(); 
     return properties; 
    } 
} 

2.使用カスタム契約リゾルバをこのアプローチは、私が許可/クラス定義を変更するのではなく、特定の要求のために禁止することができ

[HttpGet] 
public BinaryImage Single(int key) 
{ 
    //limit properties that are sent on wire for this request specifically 
    var contractResolver = Configuration.Formatters.JsonFormatter.SerializerSettings.ContractResolver as PublicDomainJsonContractResolverOptIn; 
    if (contractResolver != null) 
     contractResolver.AllowList = new string[] { "Id", "Bytes", "MimeType", "Width", "Height" }; 

    BinaryImage image = new BinaryImage { Id = 1 }; 
    //etc. etc. 
    return image; 
} 

。 XMLシリアル化が必要ない場合は、App_Start\WebApiConfig.csでXMLシリアル化をオフにすることを忘れないでください。そうでないと、クライアントがjsonの代わりにxmlを要求すると、APIはブロックされたプロパティを返します。

私はゲーム後半だけど、匿名オブジェクトは、トリックを行うだろう
//remove xml serialization 
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml"); 
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType); 
+0

新しいバージョンで何かが変更されているはずですが、これを動作させることができませんでした。私はリゾルバを変更するときに 'as'の代わりに 'new'を実行することで、動作させることができました。何らかの理由でJsonContractResolver型が互換性がありません。新しいことの問題は、それがただのものの代わりにすべてのものを上書きするということです。 –

+0

私はこのように、MediaTypeFormatterを受けRequest.CreateResponse()メソッドを使用して、この作業を取得するために管理: するvar jsonMediaTypeFormatter =新しいJsonMediaTypeFormatter { SerializerSettings =新しいJsonSerializerSettings { ContractResolver =新しいPublicDomainJsonContractResolverOptIn {AllowList =新しい文字列[ ] {"Id"、 "Bytes"、 "MimeType"、 "Width"、 "Height"}} } }; 戻り値Request.CreateResponse(HttpStatusCode.OK、image、jsonMediaTypeFormatter); – Paul

+0

ブロックされたプロパティをXMLレスポンスで無視したい場合はどうすればよいですか? –

12

[HttpGet] 
public HttpResponseMessage Me(string hash) 
{ 
    HttpResponseMessage httpResponseMessage; 
    List<Something> somethings = ... 

    var returnObjects = somethings.Select(x => new { 
     Id = x.Id, 
     OtherField = x.OtherField 
    }); 

    httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK, 
           new { result = true, somethings = returnObjects }); 

    return httpResponseMessage; 
} 
6

IgnoreDataMemberプロパティ

public class Foo 
    { 
     [IgnoreDataMember] 
     public int Id { get; set; } 
     public string Name { get; set; } 
    } 
10

を使用してみてください、私はあなたを達成するために2つの方法が表示されますあなたが望むもの:

最初の方法:JsonProであなたのフィールドを飾るそのフィールドのシリアル化をスキップするためにperty属性を返します。

public class Foo 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 
    public List<Something> Somethings { get; set; } 
} 

第二の方法:あなたには、いくつかの複雑なシナリオと交渉しているなら、あなたは、いくつかの特定のロジックに依存し、そのフィールドの直列化をスキップするためにWeb APIを規則(「ShouldSerialize」)を使用することができます。

public class Foo 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public List<Something> Somethings { get; set; } 

    public bool ShouldSerializeSomethings() { 
     var resultOfSomeLogic = false; 
     return resultOfSomeLogic; 
    } 
} 

WEBAPIはJSON.Netを使用し、それは(例えば)名前FieldX持つフィールドがシリアライズされないShouldSerializeFieldX()メソッドを検出した場合にはそうシリアライズにリフレクションを使用します。

+0

これはweb apiでは行われていませんが、web apiはデフォルトでJson.NETを使用してシリアル化します。このプロセスは、Web APIではなくJson.NETによって行われます。 – dotctor

0

何らかの理由で[IgnoreDataMember]が私のために常に機能するとは限らず、時々StackOverflowException(またはそれに類するもの)を取得します。だからではなく(あるいは加えて)私はPOSTは私のAPIにObjectsにする際に、このような何かを探していたパターンを使用して開始しました:

[Route("api/myroute")] 
[AcceptVerbs("POST")] 
public IHttpActionResult PostMyObject(JObject myObject) 
{ 
    MyObject myObjectConverted = myObject.ToObject<MyObject>(); 

    //Do some stuff with the object 

    return Ok(myObjectConverted); 
} 

だから基本的に私はJObjectに渡し、それが受け取っされた後にそれを変換します組み込みのシリアライザによって発生するaviodの問題は、オブジェクトの解析中に無限ループを引き起こすことがあります。

これは決して悪い考えである理由が分かっている場合は、教えてください。

それはそれは(2つのクラスがそれぞれ、他を参照している場合)に問題が発生しEntityFrameworkクラスプロパティに次のコードであることは注目に値することがありますgreatbear302の答えとして

[Serializable] 
public partial class MyObject 
{ 
    [IgnoreDataMember] 
    public MyOtherObject MyOtherObject => MyOtherObject.GetById(MyOtherObjectId); 
} 

[Serializable] 
public partial class MyOtherObject 
{ 
    [IgnoreDataMember] 
    public List<MyObject> MyObjects => MyObject.GetByMyOtherObjectId(Id); 
} 
4

ほぼ同じですが、私は、リクエストごとにContractResolverを作成します。

1))のカスタムContractResolver

public class MyJsonContractResolver : DefaultContractResolver 
{ 
    public List<Tuple<string, string>> ExcludeProperties { get; set; } 

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) 
    { 
     JsonProperty property = base.CreateProperty(member, memberSerialization); 

     if (ExcludeProperties?.FirstOrDefault(
      s => s.Item2 == member.Name && s.Item1 == member.DeclaringType.Name) != null) 
     { 
      property.ShouldSerialize = instance => { return false; }; 
     } 

     return property; 
    } 
} 

2を作成し、アクションでカスタム契約リゾルバを使用し

public async Task<IActionResult> Sites() 
{ 
    var items = await db.Sites.GetManyAsync(); 

    return Json(items.ToList(), new JsonSerializerSettings 
    { 
     ContractResolver = new MyJsonContractResolver() 
     { 
      ExcludeProperties = new List<Tuple<string, string>> 
      { 
       Tuple.Create("Site", "Name"), 
       Tuple.Create("<TypeName>", "<MemberName>"), 
      } 
     } 
    }); 
} 

編集:リゾルバを隔離(予想通りそれは動作しませんでした

リクエストごとに)。匿名のオブジェクトを使用します。

public async Task<IActionResult> Sites() 
{ 
    var items = await db.Sites.GetManyAsync(); 

    return Json(items.Select(s => new 
    { 
     s.ID, 
     s.DisplayName, 
     s.Url, 
     UrlAlias = s.Url, 
     NestedItems = s.NestedItems.Select(ni => new 
     { 
      ni.Name, 
      ni.OrdeIndex, 
      ni.Enabled, 
     }), 
    })); 
} 
関連する問題