.NET Core WebApi 에서 다 중 데이터 바 인 딩 인 스 턴 스 코드 를 어떻게 실현 합 니까?
2014 년 Xamarin 과 마이크로소프트 가.NET 재단 을 시작 하면 서 마이크로소프트 는 2014 년 11 월.NET 프레임 워 크 소스 코드 를 개방 했다.닷 넷 오픈 소스 재단 의 통합 기획 으로 닷 넷 코어 가 탄생 했다.즉.NET Core Framework 는.NET Framework 를 참고 하여 재 개발 한.NET 실현 이 고,모 노 는.NET Framework 의 개 원 된 크로스 플랫폼 의 실현 이다.
본 고 는 주로.NET Core WebApi 다 중 데이터 바 인 딩 에 관 한 내용 을 소개 하 였 으 며,공유 하여 여러분 께 참고 학습 을 제공 하 였 습 니 다.다음은 더 이상 말씀 드 리 지 않 겠 습 니 다.상세 한 소 개 를 해 보 겠 습 니 다.
무엇이 다 중 데이터 바 인 딩 입 니까?
ASP.NET Core WebApi 에서 데이터 바 인 딩 메커니즘(Data Binding)이 바 인 딩 요청 파 라 메 터 를 담당 하 는 것 을 잘 알 고 있 습 니 다.보통 대부분의 데이터 바 인 딩 은 기본 데이터 바 인 딩 기(Binder)에서 정상적으로 진행 되 지만 지원 되 지 않 는 경우 도 있 습 니 다.예 를 들 어 다 중 데이터 바 인 딩 등 입 니 다.다 중 데이터 바 인 딩(polymorphic data binding)이란 요청 매개 변 수 는 하위 클래스 대상 의 JSon 문자열 이 고 action 에 서 는 부모 클래스 형식의 변 수 를 정의 합 니 다.기본 적 인 상황 에서 ASP.NET Core WebApi 는 다 중 데이터 바 인 딩 을 지원 하지 않 아 데 이 터 를 잃 어 버 릴 수 있 습 니 다.
아래 그림 을 예 로 들다
Person 류 는 아버지 류 이 고 Doctor 류 와 Student 류 는 Person 류 의 파생 류 이다.Doctor 클래스 에 있 는 HospitalName 속성,Student 에 있 는 SchoolName 속성 입 니 다.
허난 성
PeopleController 에 Add api 를 추가 하고 효 과 를 볼 수 있 도록 요청 데 이 터 를 직접 되 돌려 줍 니 다.
[Route("api/people")]
public class PeopleController : Controller
{
[HttpPost]
[Route("")]
public List<Person> Add([FromBody]List<Person> people)
{
return people;
}
}
여기 서 우 리 는 Postman 을 사용 하여 이 api 를 요청 합 니 다.요청 한 Content-Type 은 application/json 입 니 다.요청 한 Body 내용 은 다음 과 같 습 니 다.
[{
firstName: 'Mike',
lastName: 'Li'
}, {
firstName: 'Stephie',
lastName: 'Wang',
schoolName: 'No.15 Middle School'
}, {
firstName: 'Jacky',
lastName: 'Chen',
hospitalName: 'Center Hospital'
}]
요청 한 반환 내용
[
{
"FirstName": "Mike",
"LastName": "Li"
},
{
"FirstName": "Stephie",
"LastName": "Wang"
},
{
"FirstName": "Jacky",
"LastName": "Chen"
}
]
반환 결 과 는 우리 가 원 하 는 결과 와 다 릅 니 다.Student 가 가지 고 있 는 SchoolName 속성 과 Doctor 가 가지 고 있 는 HospitalName 속성 을 모두 잃 어 버 렸 습 니 다.현재 프로젝트 디 버 깅 모드 를 시작 합 니 다.Postman 을 다시 사용 하여 요청 한 결 과 는 다음 과 같 습 니 다.
People 집합 에 3 개의 People 유형 을 저장 하 는 대상 은 우리 가 원 하 는 Student 유형 대상 과 Doctor 유형 대상 이 나타 나 지 않 았 습 니 다.이 는.NET Core WebApi 는 기본적으로 다 중 데이터 바 인 딩 을 지원 하지 않 습 니 다.부모 유형 변 수 를 사용 하여 데 이 터 를 받 으 면 Data Binding 은 파생 대상 이 아 닌 부모 유형 대상 만 사례 화하 여 속성 을 잃 게 됩 니 다.
사용자 정의 JSonConverter 로 다 중 데이터 바 인 딩 실현
JSonConverter 는 JSon.NET 의 한 종류 로 주로 JSon 대상 의 서열 화 와 반 서열 화 를 책임 진다.
먼저,우 리 는 일반적인 유형의 JSonCreationConverter 를 만 들 고 JSonConverter 류 를 계승 하 였 습 니 다.코드 는 다음 과 같 습 니 다.
public abstract class JsonCreationConverter<T> : JsonConverter
{
public override bool CanWrite
{
get
{
return false;
}
}
protected abstract T Create(Type objectType, JObject jObject);
public override bool CanConvert(Type objectType)
{
return typeof(T).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader == null) throw new ArgumentNullException("reader");
if (serializer == null) throw new ArgumentNullException("serializer");
if (reader.TokenType == JsonToken.Null)
return null;
JObject jObject = JObject.Load(reader);
T target = Create(objectType, jObject);
serializer.Populate(jObject.CreateReader(), target);
return target;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException();
}
}
그 중에서 우 리 는 추상 적 인 방법 Create 를 추 가 했 습 니 다.이 방법 은 JSon 문자열 의 내용 에 따라 범 형 대상 을 되 돌려 줍 니 다.여 기 는 현재 범 형 유형의 대상 도 되 돌려 줄 수 있 고 현재 범 형 유형의 파생 대상 도 되 돌려 줄 수 있 습 니 다.JObject 는 JSon.NET 의 JSon 문자열 리더 로 JSon 문자열 의 속성 값 을 읽 습 니 다.또한 저 희 는 ReadJSon 방법 도 복 사 했 습 니 다.ReadJSon 에서 저 희 는 Create 방법 으로 현재 범 형 대상 이나 현재 범 형 류 의 파생 대상 을 가 져 옵 니 다(JSon.NET 에서 기본 적 인 KeyValuePair Converter 는 현재 매개 변수 유형 대상 을 직접 예화 합 니 다.이것 은 기본 적 으로 다 중 데이터 바 인 딩 을 지원 하지 않 는 주요 원인 입 니 다).serializer.Popluate 방법의 역할 은 JSon 문자열 의 내용 을 대상(현재 범 형 대상 또는 현재 범 형 클래스 의 파생 대상)에 비 추 는 대응 속성 입 니 다.
여 기 는 우리 가 JSon 만 읽 어야 하기 때문에 Write JSon 의 방법 을 우 리 는 실현 할 필요 가 없습니다.CanWrite 속성 은 우리 도 강제로 False 로 돌 아 왔 습 니 다.
두 번 째 단 계 는 PersonJSonConverter 클래스 를 만 들 었 습 니 다.JSonCreationConverter
public class PersonJsonConverter : JsonCreationConverter<Person>
{
protected override Person Create(Type objectType, JObject jObject)
{
if (jObject == null) throw new ArgumentNullException("jObject");
if (jObject["schoolName"] != null)
{
return new Student();
}
else if (jObject["hospitalName"] != null)
{
return new Doctor();
}
else
{
return new Person();
}
}
}
이 클래스 에서 Create 방법 을 복 사 했 습 니 다.JObject 를 사용 하여 JSon 문자열 에 있 는 속성 을 가 져 옵 니 다.
[JsonConverter(typeof(PersonJsonConverter))]
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
현재 디 버 깅 모드 로 프로그램 을 시작 한 다음 Postman 을 사용 하여 현재 api 를 요청 합 니 다.people 집합 에 올 바 르 게 연 결 된 파생 자 유형 대상 을 발견 할 수 있 습 니 다.최종 Postman 에서 우 리 는 다음 과 같은 응답 결 과 를 얻 었 습 니 다.
[
{
"FirstName": "Mike",
"LastName": "Li"
},
{
"SchoolName": "No.15 Middle School",
"FirstName": "Stephie",
"LastName": "Wang"
},
{
"HospitalName": "Center Hospital",
"FirstName": "Jacky",
"LastName": "Chen"
}
]
이로써 다 중 데이터 바 인 딩 에 성공 하 였 습 니 다.미주 알 고 주 알 캐묻다
왜 PersonJSonConverter 류 를 추가 하여 다 중 바 인 딩 이 이 루어 졌 습 니까?
MVC 코어 와 제 이 슨 닷 넷 의 코드 를 검토 해 봅 시다.
일단 MvcCoreMvcOptionsSetup 코드 를 볼 게 요.
public class MvcCoreMvcOptionsSetup : IConfigureOptions<MvcOptions>
{
private readonly IHttpRequestStreamReaderFactory _readerFactory;
private readonly ILoggerFactory _loggerFactory;
......
public void Configure(MvcOptions options)
{
options.ModelBinderProviders.Add(new BinderTypeModelBinderProvider());
options.ModelBinderProviders.Add(new ServicesModelBinderProvider());
options.ModelBinderProviders.Add(new BodyModelBinderProvider(options.InputFormatters, _readerFactory, _loggerFactory, options));
......
}
......
}
MvcCoreMvcOptionsSetup 클래스 의 Configure 방법 은 기본 데이터 바 인 딩 사용 Provider 목록 을 설정 합 니 다.api 매개 변수 가[FromBody]로 표 시 될 때 Body ModelBinder Provider 는 Body ModelBinder 대상 을 예화 하여 이 매개 변 수 를 처리 하고 데이터 바 인 딩 을 시도 합 니 다.
Body Model Binder 클래스 에는 Bind Model Async 방법 이 있 습 니 다.이름 의 글자 그대로 우 리 는 이 방법 이 데 이 터 를 연결 하 는 데 쓰 인 다 는 것 을 잘 알 고 있 습 니 다.
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null)
{
throw new ArgumentNullException(nameof(bindingContext));
}
….
var formatter = (IInputFormatter)null;
for (var i = 0; i < _formatters.Count; i++)
{
if (_formatters[i].CanRead(formatterContext))
{
formatter = _formatters[i];
_logger?.InputFormatterSelected(formatter, formatterContext);
break;
}
else
{
logger?.InputFormatterRejected(_formatters[i], formatterContext);
}
}
……
try
{
var result = await formatter.ReadAsync(formatterContext);
……
}
catch (Exception exception) when (exception is InputFormatterException || ShouldHandleException(formatter))
{
bindingContext.ModelState.AddModelError(modelBindingKey, exception, bindingContext.ModelMetadata);
}
}
이 방법 에 서 는 IInputFormatter 대상 을 찾 아 데 이 터 를 연결 하려 고 합 니 다.이때 요청 한 Content-Type 은 application/json 이기 때문에 JSonInputFormatter 대상 을 사용 하여 데이터 바 인 딩 을 합 니 다.다음은 JSONInputFormatter 류 의 핵심 코드 를 살 펴 보 겠 습 니 다.
public override async Task<InputFormatterResult> ReadRequestBodyAsync(
InputFormatterContext context,
Encoding encoding)
{
......
using (var streamReader = context.ReaderFactory(request.Body, encoding))
{
using (var jsonReader = new JsonTextReader(streamReader))
{
…
object model;
try
{
model = jsonSerializer.Deserialize(jsonReader, type);
}
finally
{
jsonSerializer.Error -= ErrorHandler;
ReleaseJsonSerializer(jsonSerializer);
}
…
}
}
}
JSonInputFormatter 클래스 의 ReadRequestBody Async 방법 은 데이터 바 인 딩 을 담당 하 며,이 방법 에 서 는 JSon.NET 의 JSonSerializer 류 Deserialize 방법 을 사용 하여 역 직렬 화 를 진행 하 였 으 며,이 는 Mvc Core 의 바 텀 이 JSon.NET 을 직접 사용 하여 JSon 을 조작 한 다 는 것 을 의미한다.JSonSerializer 클래스 의 일부 핵심 코드
public object Deserialize(JsonReader reader, Type objectType)
{
return DeserializeInternal(reader, objectType);
}
internal virtual object DeserializeInternal(JsonReader reader, Type objectType)
{
……
JsonSerializerInternalReader serializerReader = new JsonSerializerInternalReader(this);
object value = serializerReader.Deserialize(traceJsonReader ?? reader, objectType, CheckAdditionalContent);
……
return value;
}
JSonSerializer 는 JSonSerializer Internal Reader 류 의 Deserialize 방법 으로 JSon 문자열 의 내용 을 역 정렬 합 니 다.마지막 으로 JSonSerializer Internal Reader 의 일부 핵심 코드 를 살 펴 보 겠 습 니 다.
public object Deserialize(JsonReader reader, Type objectType, bool checkAdditionalContent)
{
…
JsonConverter converter = GetConverter(contract, null, null, null);
if (reader.TokenType == JsonToken.None && !reader.ReadForType(contract, converter != null))
{
......
object deserializedValue;
if (converter != null && converter.CanRead)
{
deserializedValue = DeserializeConvertable(converter, reader, objectType, null);
}
else
{
deserializedValue = CreateValueInternal(reader, objectType, contract, null, null, null, null);
}
}
}
JSonSerializer Internal Reader 클래스 의 Deserialize 방법 은 현재 요청 한 매개 변수의 유형 에 따라 적합 한 JSonConverter 를 찾 아 예화 하려 고 시도 합 니 다.일치 하 는 컨버터 를 찾 으 면 이 컨버터 를 사용 하여 실제 반 직렬 화 데이터 바 인 딩 작업 을 합 니 다.현재 예 에서 api 의 매개 변수 유형 은 Person 이기 때문에 PersonJSonConverter 와 일치 합 니 다.이것 이 바로 우리 가 PersonJSonConverter 를 추가 함으로써 다 중 데이터 바 인 딩 기능 을 완성 한 이유 입 니 다.소스 코드
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
IdentityServer에서 토큰 검색, 사용 및 유효성 검사📮 문의하기 🇧🇷 🇺🇸 🇫🇷 이것은 클라이언트 응용 프로그램이 Identity Server에서 토큰을 검색하고 이를 WebApi에서 사용하여 끝점을 사용하는 방법의 예입니다. 이 예제는 을 기반으로 작성되었습니다. ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.