title: Serializing a JSON.NET JObject while filtering out certain properties
body: <p>I have a large arbitrary JSON structure as a <code>JObject</code> reference in my code.</p>
  
  <p>I want to serialise this structure, except when I encounter a <code>JObject</code> containing a property called <code>type</code> with value <code>"encrypted"</code> then I want to remove the adjacent <code>data</code> property before writing the object. </p>
  
  <p>In other words, if I encounter this:</p>
  
  <pre><code>{
    type: "encrypted",
    name: "some-name",
    data: "&lt;base64-string&gt;"
  }
  </code></pre>
  
  <p>It will be serialized as this:</p>
  
  <pre><code>{
    type: "encrypted",
    name: "some-name"
  }
  </code></pre>
  
  <p>I can't mutate the structure, and cloning it before mutating would be too inefficient, so I tried using a <code>JsonConverter</code> as follows:</p>
  
  <pre><code>public class RemoveEncryptedDataSerializer : JsonConverter
  {
      public override bool CanConvert(Type objectType)
      {
          return objectType == typeof(JObject);
      }
  
      public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
      {
          throw new NotImplementedException();
      }
  
      public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
      {
          var o = (JObject)value;
          if (o.Value&lt;string&gt;("type") != "encrypted")
          {
              o.WriteTo(writer);
              return;
          }
  
          var copy = o.DeepClone();
          copy["data"]?.Parent.Remove();
          copy.WriteTo(writer);
      }
  }
  </code></pre>
  
  <p>However the <code>CanConvert</code> function only seems to be called with types not derived from <code>JToken</code>, so my <code>WriteJson</code> function is never called.</p>
  
  <p>Is there another way to achieve this?</p>
  
  <hr>
  
  <p>Edit: Here is some code you can use for testing:</p>
  
  <pre><code>[TestMethod]
  public void ItShouldExcludeEncryptedData()
  {
      var input = JObject.Parse(@"
      {
          a: {
              type: 'encrypted',
              name: 'some-name',
              data: 'some-data'
          }
      }");
  
      var expected = JObject.Parse(@"
      {
          a: {
              type: 'encrypted',
              name: 'some-name',
          }
      }");
  
      var output = input.ToString(Formatting.Indented, new RemoveEncryptedDataSerializer());
  
      Assert.AreEqual(
          expected.ToString(Formatting.Indented),
          output);
  }
  </code></pre>