Skip to content

Instantly share code, notes, and snippets.

@gongdo
Last active August 29, 2015 14:28
Show Gist options
  • Save gongdo/5105e7cf959f9f5f3307 to your computer and use it in GitHub Desktop.
Save gongdo/5105e7cf959f9f5f3307 to your computer and use it in GitHub Desktop.
Poor-man's partial update & validation in ASP.NET 5
[HttpPut]
public async Task<MyResult> Put(string id)
{
// 일단 입력값(JSON)을 JObject로 읽기
JObject jobject;
using (var sr = new StreamReader(Request.Body))
{
jobject = JObject.Load(new JsonTextReader(sr));
}
// 업데이트 모델로 deserialize
var updateModel = jobject.ToObject<MyUpdateModel>();
// deserialize된 모델로 ValidationContext를 준비
var validationContext = new ValidationContext(updateModel);
// 입력된 JSON의 JProperty목록 뽑기
var properties = jobject.Properties().Where(p => true /*!커스텀!불필요한 필드 필터링*/).ToList();
var jpropertyAttribute = typeof(JsonPropertyAttribute);
// JProperty들중에서 업데이트 모델에 정의되어 있는 프로퍼티 목록만 매핑
var mapping = updateModel.GetType()
.GetProperties()
.Where(p => p.CanRead && p.CanWrite)
.Select(p =>
{
// JsonProperty 어트리뷰트를 존중하여 프로퍼티 이름 비교
var propertyName = p.GetCustomAttribute<JsonPropertyAttribute>(true)?.PropertyName ?? p.Name;
var jproperty = properties.FirstOrDefault(j => j.Name.Equals(propertyName, StringComparison.OrdinalIgnoreCase));
// 모델 새로 만들기 귀찮으니 Tuple로 때우기
return new Tuple<JProperty, PropertyInfo>(jproperty, p);
})
.Where(m => m.Item1 != null) // 매핑되지 않은 JProperty는 탈락
.ToDictionary(m => m.Item1, m => m.Item2);
// 씐나게 살아남은 프로퍼티를 validate
foreach (var item in mapping)
{
validationContext.MemberName = item.Value.Name; // 요놈이 컨텍스트내에서 지정한 멤버만 validate하는 핵심
var value = item.Value.GetValue(updateModel);
Validator.ValidateProperty(value, validationContext);
}
// 여기까지 왔다면 mapping에 남아있는 프로퍼티는 전부다 유효한 이름/값임.
// 아래는 사용하는 Repository나 DB에 따라 적절하게 partial update 로직을 구현.
// 여기에서는 역시 귀찮으니 유효한 프로퍼티들만 json으로 serialize하고 끝.
// JProperty를 기준으로 serialize하는게 간편하긴 함.
// 반대로 mapping.Values를 사용하면 모델의 프로퍼티를 이용한 처리가 가능.
var json = JsonConvert.SerializeObject(new JObject(mapping.Keys));
var result = UltimateMergeMachine.Merge(json);
return result;
}
@gongdo
Copy link
Author

gongdo commented Aug 25, 2015

이상하다 왜 indent가 8로 고정되지;
C# 코드 하일라이팅이 형편없군요!?

@gyuwon
Copy link

gyuwon commented Aug 25, 2015

공백문자가 아닌 탭을 사용해서 그런 것 같네요. 공백을 사용해 들여쓰기할 때에는 (당연히) 잘 나옵니다.

@gongdo
Copy link
Author

gongdo commented Aug 25, 2015

아... 깃헙 정도 되면 탭 간격도 조절 해줄거라고 생각했는데... 그렇군요.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment