[C#] 웹 API에서 속성이 직렬화되지 않도록 방지

나머지 API를 빌드하기 위해 MVC 4 웹 API 및 asp.net 웹 양식 4.0을 사용하고 있습니다. 잘 작동합니다.

[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객체가 너무 복잡하고 다른 방법으로 다른 속성 집합이 필요합니다. 런타임시 각 속성을 무시하도록 표시하기가 더 쉽습니다.

그렇게 할 방법이 있습니까?



답변

ASP.NET 웹 API는 Json.Net기본 포맷터로 사용 하므로 응용 프로그램에서 JSON 만 데이터 형식으로 사용 [JsonIgnore]하는 경우 직렬화 속성을 무시 하는 데 사용할 수 있습니다 .

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

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

그러나이 방법은 XML 형식을 지원하지 않습니다. 그래서, 경우에 귀하의 응용 프로그램 에이 사용하는 대신, 지원 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; }
}

자세한 내용은 공식 기사를 참조하십시오 .


답변

ASP.NET 웹 API 의 웹 API 문서 페이지 JSON 및 XML 직렬화에[JsonIgnore] 따르면 Json 직렬 변환기 또는 [IgnoreDataMember]기본 XML 직렬 변환기에 사용할 수있는 특성의 직렬화를 명시 적으로 방지 할 수 있습니다 .

그러나 테스트에서 [IgnoreDataMember]XML과 Json 요청 모두의 직렬화를 방지 한다는 것을 알았 으므로 여러 속성으로 속성을 장식하는 대신 사용하는 것이 좋습니다.


답변

기본적으로 모든 것이 직렬화 되도록 하는 대신 “선택”접근 방식을 사용할 수 있습니다. 이 시나리오에서는 지정한 속성 만 직렬화 할 수 있습니다. 당신은이 작업을 수행 DataContractAttribute하고 DataMemberAttribute에서 발견 들은 System.Runtime.Serialization의 네임 스페이스.

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에 의존하지 않고 모델 클래스가 프로젝트에 살 수 있습니다.


답변

이것은 나를 위해 일했습니다 : 문자열 배열 유형의 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);


답변

나는 당신이 원하는 것을 성취하는 두 가지 방법을 보여줄 것입니다 :

첫 번째 방법 : 필드가 null 인 경우 해당 필드의 직렬화를 건너 뛰려면 JsonProperty 속성으로 필드를 장식하십시오.

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

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

두 번째 방법 : 복잡한 시나리오와 협상하는 경우 특정 논리에 따라 해당 필드의 직렬화를 건너 뛰기 위해 웹 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을 사용하고 직렬화에 반영을 사용하므로, 예를 들어 ShouldSerializeFieldX () 메소드를 감지하면 이름이 FieldX 인 필드가 직렬화되지 않습니다.


답변

나는 게임에 늦었지만 익명의 물건이 트릭을 할 것입니다.

[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;
}


답변

IgnoreDataMember속성을 사용해보십시오

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