웹 API에서 속성이 직렬화되는 것을 방지하다
저는 MVC 4 웹 API와 asp.net 웹 양식 4.0을 사용하여 Rest 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
오브젝트가 너무 복잡해서 다른 메서드로 다른 속성 세트가 필요하기 때문에 실행 시 무시되는 각 속성을 쉽게 표시할 수 있습니다.
그렇게 할 수 있는 방법이 있나요?
ASP.NET Web API는 기본 포맷으로 사용하기 때문에 응용 프로그램이 데이터 포맷으로만 JSON을 사용하는 경우[JsonIgnore]
'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE:
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]
을 모두 합니다.
[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의 Web API 문서 페이지 JSON 및 XML Serialization에 따르면사용할 수 있는 속성의 일련화를 명시적으로 방지하는 NET Web API[JsonIgnore]
또는 Json serializer의 [IgnoreDataMember]
「XML」입니다.
하지만 테스트에서 알아차린 것은[IgnoreDataMember]
는 XML 요구와 Json 요구 모두에 대해 시리얼화를 방지하므로 여러 속성을 사용하여 속성을 꾸미는 것보다 이 기능을 사용하는 것이 좋습니다.
디폴트로 모든 것을 시리얼화하는 것이 아니라, 「opt-in」의 어프로치를 채용할 수 있습니다.이 시나리오에서는 지정한 속성만 직렬화할 수 있습니다.이 작업은 시스템에 있는및 을 사용하여 수행합니다.런타임시리얼라이제이션네임스페이스
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 의 없는 는, XML 의 말아 .App_Start\WebApiConfig.cs
클라이언트가 json 대신 xml을 요구하면 API가 차단된 속성을 반환합니다.
//remove xml serialization
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
원하는 것을 실현하기 위한 2가지 방법을 소개합니다.
첫 번째 방법: 필드를 JsonProperty 속성으로 꾸미고 필드가 null일 경우 해당 필드의 시리얼화를 건너뜁니다.
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 표기법( 「Should Serialize」)을 사용하고, 특정의 로직에 의해서 그 필드의 시리얼화를 생략할 수 있습니다.
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 및 리플렉션을 사용하여 시리얼라이제이션이 이루어지기 때문에 (예를 들어) WhouseSerialize가 검출되었을 때FieldX() 메서드는 이름이 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; }
}
[ Ignore Data Member ]를 추가하는 것만으로 정상적으로 동작합니다.
propertyp 위에는 다음과 같은 것이 있습니다.
public class UserSettingsModel
{
public string UserName { get; set; }
[IgnoreDataMember]
public DateTime Created { get; set; }
}
이것은 ApiController에서 동작합니다.코드:
[Route("api/Context/UserSettings")]
[HttpGet, HttpPost]
public UserSettingsModel UserSettings()
{
return _contextService.GetUserSettings();
}
greatbear302의 답변과 거의 동일하지만 요청마다 Contract Resolver를 만듭니다.
1) 커스텀 Contract Resolver 작성
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>"),
}
}
});
}
편집:
기대했던 대로 작동하지 않았습니다(요청당 Isolate Resolver).익명의 오브젝트를 사용합니다.
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,
}),
}));
}
하여 Auto Mapper를 할 수 ..Ignore()
후 합니다.
CreateMap<Foo, Foo>().ForMember(x => x.Bar, opt => opt.Ignore());
.NET Core 3.0 이후의 경우:
ASP(JSON)의 Core is now NET Core( Core now NET Core(NET Core)
System.Text.Json
의 새로운 )NET Core 3.0 합니다.츠키노텍스트입니다.Json종속성이 하지 않습니다고성능으로 추가 라이브러리 의존이 필요하지 않습니다.
샘플(고맙습니다)
using System.Text.Json.Serialization;
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
[JsonIgnore]
public List<Something> Somethings { get; set; }
}
이미 가지고 계신 경우Newtonsoft.Json
기본적으로는 설치 후 대신 사용을 선택했습니다.[JsonIgnore]
예상대로 되지 않습니다.
웬일인지 그래.[IgnoreDataMember]
항상 나에게 효과가 있는 것은 아니다.그리고 나는 가끔 그것을 얻을 수 있다.StackOverflowException
(또는 유사).대신 (또는 추가로) 다음과 같은 패턴을 사용하기 시작했습니다.POST
에 스며드는.Objects
내 API로:
[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 문제로 변환합니다.
어떤 식으로든 나쁜 생각인 이유를 아는 사람이 있으면 알려주세요.
문제의 원인이 되는 것은 Entity Framework클래스 속성의 다음 코드입니다(2개의 클래스가 서로 참조하는 경우).
[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);
}
언급URL : https://stackoverflow.com/questions/11851207/prevent-property-from-being-serialized-in-web-api
'programing' 카테고리의 다른 글
ASP에서 favicon.ico를 서비스하고 있습니다.넷 MVC (0) | 2023.04.21 |
---|---|
ID 열이 하나만 있는 테이블에 행 삽입 (0) | 2023.04.21 |
설정 해제 vs. 변수를 비워 두도록 설정 (0) | 2023.04.21 |
"내선번호 설정으로 인해 요청하신 페이지를 제공할 수 없습니다." 오류 메시지 (0) | 2023.04.21 |
EPPlus의 컬럼 동결(Excel 분할 함수) (0) | 2023.04.21 |