ASP.NET MVC에서 View Model을 JSON 객체로 변환하는 방법은 무엇입니까?


156

.NET을 처음 접하는 Java 개발자입니다. 위젯을 래핑하기 위해 부분적으로보기를 원하는 .NET MVC2 프로젝트에서 작업하고 있습니다. 각 JavaScript 위젯 오브젝트에는 모델 데이터로 채워지는 JSON 데이터 오브젝트가 있습니다. 그런 다음이 데이터를 업데이트하는 메소드는 데이터가 위젯에서 변경되거나 해당 데이터가 다른 위젯에서 변경되는 경우 이벤트에 바인딩됩니다.

코드는 다음과 같습니다.

MyController:

virtual public ActionResult DisplaySomeWidget(int id) {
  SomeModelView returnData = someDataMapper.getbyid(1);

  return View(myview, returnData);
}

myview.ascx:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SomeModelView>" %>

<script type="text/javascript">
  //creates base widget object;
  var thisWidgetName = new Widget();

  thisWidgetName.updateTable = function() {
    //  UpdatesData
  };
  $(document).ready(function () {
    thisWidgetName.data = <% converttoJSON(model) %>
    $(document).bind('DATA_CHANGED', thisWidgetName.updateTable());
  });
</script>

<div><%:model.name%></div>

내가 모르는 것은 데이터를 SomeModelView다음 으로 전송 한 다음 위젯을 채우고 JSON으로 변환하는 데 사용할 수있는 방법입니다. 나는 컨트롤러에서 그것을 할 수있는 실제 간단한 방법을 보았지만보기에는 없었습니다. 나는 이것이 기본적인 질문이라고 생각하지만 나는 이것을 매끄럽게 만들려고 몇 시간 동안 갔다.


1
나는 이것이 오래된 질문이라는 것을 안다. 그러나 오늘날에는 더 좋은 방법이 있습니다. JSON 인라인을 View 결과와 혼합하지 마십시오. JSON은 AJAX를 통해 쉽게 직렬화되며 객체처럼 취급 될 수 있습니다. JavaScript의 모든 것은 View와 분리되어야합니다. 컨트롤러를 통해 아무 노력없이 모델을 쉽게 반환 할 수 있습니다.
Piotr Kula 2016 년

답변:


346

면도기가 @Html.Raw(Json.Encode(object))있는 mvc3에서는 트릭을 수행하는 것 같습니다.


1
+1 Html.Raw를 사용했지만 Json.Encode를 찾지 못하고 JavaScriptSerializer를 사용하여 컨트롤러의 문자열을 뷰 모델에 추가했습니다
AaronLS

5
이 방법은 결과 JSON을 Javascript로 전달하려는 경우에도 작동합니다. @ Html.Raw (...) 코드를 <script> 태그 안에 함수 매개 변수로 넣으면 Razor가 녹색 얼룩으로 불평하지만 JSON은 실제로 호출되는 JS로 만듭니다. 매우 편리하고 매끈합니다. +1
Carl Heinrich Hancke

1
이것은 MVC3부터 수행하는 방법이며 컨트롤러에서 반환해야합니다. Viewson에 json을 포함시키지 마십시오. 대신 컨트롤러가 JSON을 개별적으로 처리하고 AJAX를 통해 JSON 요청을 수행하도록하십시오. 뷰에 JSON이 필요한 경우 뭔가 잘못한 것입니다. ViewModel 또는 다른 것을 사용하십시오.
Piotr Kula 2016 년

3
Json.Encode 는 내 2 차원 배열을 json의 1 차원 배열로 인코딩합니다. Newtonsoft.Json.JsonConvert.SerializeObject 는 2 차원을 json으로 올바르게 직렬화합니다. 따라서 후자를 사용하는 것이 좋습니다.
mono68

12
MVC 6 (아마도 5)을 사용 Json.Serialize하는 경우 Encode 대신 사용해야 합니다.
KoalaBear

31

이제 MVC를 사용하기 시작했고 첫 번째 주요 결함을 발견했습니다.

뷰에서 실제로 JSON으로 변환하고 싶지 않으며 컨트롤러에서 변환하지 않으려는 경우가 없습니다.이 두 위치 중 어느 것도 의미가 없습니다. 불행히도, 당신은이 상황에 갇혀 있습니다.

내가 찾은 가장 좋은 것은 JSON을 ViewModel의 뷰로 보내는 것입니다.

var data = somedata;
var viewModel = new ViewModel();
var serializer = new JavaScriptSerializer();
viewModel.JsonData = serializer.Serialize(data);

return View("viewname", viewModel);

그런 다음 사용

<%= Model.JsonData %>

당신의 관점에서. 표준 .NET JavaScriptSerializer는 매우 쓸모가 없습니다.

컨트롤러에서 그것을 수행하는 것은 적어도 테스트 가능하게 만듭니다 (위와 정확히 같지는 않지만-ISerializer를 종속성으로 사용하여 그것을 조롱 할 수 있습니다)

업데이트 또한, 자바 스크립트에 대한, 당신이 지금과 같은 위의 모든 위젯 JS를 포장하는 좋은 방법이 될 것입니다 :

(
    // all js here
)();

이 방법으로 한 페이지에 여러 위젯을 배치하면 충돌이 발생하지 않습니다 (페이지의 다른 곳에서 메소드에 액세스해야하는 경우가 아니라면 어쨌든 일부 위젯 프레임 워크로 위젯을 등록해야 함). 지금은 문제가되지 않지만 앞으로 요구 사항이 될 때 많은 노력을 절약하기 위해 지금 대괄호를 추가하는 것이 좋습니다. 또한 기능을 캡슐화하는 것이 좋습니다.


1
이것은 흥미로워 보인다. 데이터를 json으로 복사하여 viewData로 전달하려고했지만이 방법이 더 흥미로워 보입니다. 나는 이것을 가지고 놀 것이다. BTW 이것은 stackoverflow에 대한 질문을 게시 한 첫 번째이며 좋은 응답을 얻는 데 5 분이 걸렸습니다.
크리스 스티븐스

의 속삭임 잘못 이 서식 사용자 지정 값을 원하는 경우에, 그 그냥 사용자 정의, 당신은 기본적으로 모두에게 문자열을 만드는 손 전에해야 할 :(이 날짜가 가장 눈에 띄는 것입니다. 내가 쉽게 해결이 알고 있지만 야해 필요한!
앤드류 불락

@Update 고유 한 객체 이름을 생성하기 위해 해당 위젯의 .net 정적 카운터를 사용하는 방법에 대해 살펴 보았습니다. 그러나 당신이 쓴 것은 같은 일을 성취하고 더 매끄럽게하는 것처럼 보입니다. 또한 위젯 "new_widget_event"작성을 페이지 레벨 오브젝트에 바인딩하여이를 추적하기위한 원래 이유는 OBE가되었으므로 나중에 다시 방문 할 수 있습니다. 게시 할 모든 도움말에 감사드립니다. 당신이 제안한 것의 수정 된 버전이지만 내가 왜 더 좋아하는지 설명하십시오
Chris Stephens

2
나는 나의 이전 진술을 "그것에 아무 문제가 없다"고 철회한다. 모든 것이 잘못되었습니다.
Andrew Bullock

컨트롤러에서 JSON을 반환 할 수 없다고 말하는 이유는 무엇입니까? 그렇게해야합니다. 사용 JavaScriptSerializer또는 Return Json(object)모두 동일한 시리얼 라이저를 사용합니다. 또한 동일한 JSON을 컨트롤러에 다시 게시하면 올바른 모델을 정의하는 한 객체가 다시 작성됩니다. 어쩌면 MVC2 중에는 큰 결점이 있었지만 오늘은 산들 바람과 매우 편리합니다. 이를 반영하여 답변을 업데이트해야합니다.
Piotr Kula 2016 년

18

나는 이것을 이렇게하는 것이 꽤 좋은 것을 알았습니다 (보기에서 사용법).

    @Html.HiddenJsonFor(m => m.TrackingTypes)

다음은 도우미 메소드 확장 클래스입니다.

public static class DataHelpers
{
    public static MvcHtmlString HiddenJsonFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        return HiddenJsonFor(htmlHelper, expression, (IDictionary<string, object>) null);
    }

    public static MvcHtmlString HiddenJsonFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        return HiddenJsonFor(htmlHelper, expression, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static MvcHtmlString HiddenJsonFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
    {
        var name = ExpressionHelper.GetExpressionText(expression);
        var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        var tagBuilder = new TagBuilder("input");
        tagBuilder.MergeAttributes(htmlAttributes);
        tagBuilder.MergeAttribute("name", name);
        tagBuilder.MergeAttribute("type", "hidden");

        var json = JsonConvert.SerializeObject(metadata.Model);

        tagBuilder.MergeAttribute("value", json);

        return MvcHtmlString.Create(tagBuilder.ToString());
    }
}

그것은 초현실적이지는 않지만 그것을 어디에 두어야하는지의 문제를 해결합니다 (컨트롤러 또는보기에서?)


이것은 제 의견으로는 훌륭하고 깨끗했으며 재사용 가능한 도우미로 마무리되었습니다. 건배, J
John

6

당신이 사용할 수있는 Json액션에서 직접 .

당신의 행동은 다음과 같습니다.

virtual public JsonResult DisplaySomeWidget(int id)
{
    SomeModelView returnData = someDataMapper.getbyid(id);
    return Json(returnData);
}

편집하다

방금 이것이 Model뷰의 것으로 가정 하여 위의 내용이 정확하지 않다면 Ajax컨트롤러 메소드를 호출해야합니다.ascx 그런 다음 모델 자체가 없어야합니다. 내 코드를 남겨 두겠습니다. 당신에게 유용하고 전화를 수정할 수있는 경우를 대비하여

편집 2 코드에 ID를 넣습니다.


1
그러나 그는 이것을 뷰로 표현할 수 없었습니다. 그는 두 번째 아약스 호출을해야했습니다
Andrew Bullock

고마워, 원래 jQuery get json 호출을 사용 하여이 작업을 수행하고 HTML 요소를 json에서 직접 채울 계획이었습니다. 그러나 지금 우리가 따르고있는 패턴은 뷰가 modelView를 반환해야한다는 것이며 테이블과 같은 기본 HTML 요소를 채우는 가장 쉬운 방법입니다. ViewData와 동일한 형식으로 JSON 형식으로 데이터를 전송할 수는 있지만 낭비되는 것처럼 보입니다.
크리스 스티븐스

2
뷰 결과와 함께 JSON을 포함해서는 안됩니다. OP는 표준 MVC 실습에 충실하고 모델 또는 뷰 모델을 반환하거나 AJAX를 수행해야합니다. JSON을 뷰에 포함시킬 이유는 전혀 없습니다. 그것은 매우 더러운 코드입니다. 이 답변은 Microsoft Practices의 올바른 방법이며 권장되는 방법입니다. 공감대는 불필요했습니다. 이것이 정답입니다. 우리는 나쁜 코딩 관행을 장려해서는 안됩니다. AJAX를 통한 JSON 또는 뷰를 통한 모델 혼합 마크 업이있는 스파게티 코드를 좋아하는 사람은 없습니다!
Piotr Kula 2016 년

이 솔루션은 다음과 같은 문제가 발생합니다 : stackoverflow.com/questions/10543953/...
제니 오라일리


1

Dave 의 훌륭한 답변 확장 . 간단한 HtmlHelper를 만들 수 있습니다 .

public static IHtmlString RenderAsJson(this HtmlHelper helper, object model)
{
    return helper.Raw(Json.Encode(model));
}

그리고 당신의 관점에서 :

@Html.RenderAsJson(Model)

이런 식으로 나중에 논리를 변경하려는 경우 JSON을 만들기 위해 논리를 중앙 집중화 할 수 있습니다.



0

앤드류는 큰 반응을 보였지만 나는 그것을 조금 주저하고 싶었다. 이것이 다른 방법은 ModelViews에 오버 헤드 데이터가 없도록하는 것입니다. 객체의 데이터 만. ViewData는 오버 헤드 데이터에 대한 청구서에 맞는 것처럼 보이지만 물론 나는 이것에 익숙하지 않습니다. 나는 이런 식으로하는 것이 좋습니다.

제어 장치

virtual public ActionResult DisplaySomeWidget(int id)
{
    SomeModelView returnData = someDataMapper.getbyid(1);
    var serializer = new JavaScriptSerializer();
    ViewData["JSON"] = serializer.Serialize(returnData);
    return View(myview, returnData);
}

전망

//create base js object;
var myWidget= new Widget(); //Widget is a class with a public member variable called data.
myWidget.data= <%= ViewData["JSON"] %>;

이것이 당신을 위해하는 일은 JSON에 ModelView와 동일한 데이터를 제공하므로 JSON을 컨트롤러로 다시 되돌릴 수 있으며 모든 부분을 갖을 수 있습니다. 이것은 JSONRequest를 통해 요청하는 것과 비슷하지만 호출이 덜 필요하므로 오버 헤드가 절약됩니다. BTW 이것은 Dates에 펑키하지만 다른 스레드처럼 보입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.