JSON이란?
JSON은 JavaScript Object Notation을 나타내며, 간결하게 데이터를 표기한다.
JavaScript eval 함수에 JSON string을 전달하여 object로 deserialize할 수 있다.
Ajax with JSON
Index action에서 sites list를 보여주고, sitename을 클릭 시, JSON format의 site detail을 반환하는 Detail Action으로 Ajax를 request하자.
Site.cs
public class Site
{
public int Id { get; set; }
public string Name { get; set; }
public string PictureUrl { get; set; }
public string Explanation { get; set; }
}
SitesController.cs
public class SitesController : Controller
{
private static List<Site> _sites = new List<Site>();
public SitesController() {
if (_sites.Count == 0)
{
_sites.Add(new Site { Id = 1, Name = "GitHub", PictureUrl = "https://github.githubassets.com/favicons/favicon.png", Explanation = "provider of Internet hosting for software development and version control using Git" });
_sites.Add(new Site { Id = 2, Name = "Google", PictureUrl = "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png", Explanation = " American multinational technology company that focuses on artificial intelligence,[10] search engine technology, online advertising, cloud computing, computer software, quantum computing, e-commerce, and consumer electronics" });
}
}
// GET: Speakers
public ActionResult Index()
{
return View(_sites);
}
public ActionResult Details(int id)
{
var site = _sites.Where(s => s.Id == id).FirstOrDefault();
return Json(site,
JsonRequestBehavior.AllowGet);
//JsonResult는 HTTP Post에서만 동작해야 하므로, GET request에 대한 response에서는 예외 옵션을 지정한다.
}
}
Details action은 id를 parameter로 받아서 해당 site object를 찾아, JSON format으로 serialize 해서 반환한다.
Index.cshtml
Client-side template은 server에서 전달받거나, JavaScript로 element를 구성하는 것 없이 markup을 생성하게 해준다.
Client-side templating library는 여러가지 있는데, 여기서는 jQuery-tmpl을 사용해보자.
하단에 jquery.tmpl.js파일을 포함시켰다.
Template은 text/x-jquery-tmpl type의 script element안에 정의한다. JSON object property는 ${}로 감싼다.
@model IEnumerable<AjaxExamples.Models.Site>
@{
ViewBag.Title = "Index";
}
<h2>Sites</h2>
<ul class="sites">
@foreach (var site in Model)
{
<li>
@Html.ActionLink(site.Name, "Details", new { id = site.Id })
</li>
}
</ul>
<div class="selected-site" style="display:none">
</div>
<br style="clear:both" />
<script id="siteTemplate" type="text/x-jquery-tmpl">
<img src="${PictureUrl}" alt="Speaker image" class="site-pic" />
<p class="site-explain">
${Explanation}
</p>
<br style="clear:both;" />
</script>
@section scripts{
<script src="~/Scripts/jquery.tmpl.js"></script>
<script type="text/javascript" src="@Url.Content("~/scripts/Sites.js")"></script>
}
Sites.js
$(document).ready(function () {
$("ul.sites a").click(function (e) {
e.preventDefault();
$(".selected-site").hide().html('');
var url = $(this).attr('href');
$.getJSON(url, null, function (site) {//url로 get request, 전달하는 데이터는 없으므로 null
//server에서 보내는 JSON string을 JavaScript object로 자동 serialize
$("#siteTemplate")
.tmpl(site)
.appendTo('.selected-site');
//template element를 찾은 후, template을 렌더링 하기 위해, tmpl 함수를 호출한다.
//tempate은 selected-site element에 append된다.
$('.selected-site').show();
});
});
});
JavaScript가 정상동작 하지 않으면, 아래와 같이 JSON file이 보여진다.
해당 이슈를 처리하기 위해, 아래와 같이 if를 추가한다.
public ActionResult Details(int id)
{
var site = _sites.Where(s => s.Id == id).FirstOrDefault();
if (Request.IsAjaxRequest())
{
return Json(site,
JsonRequestBehavior.AllowGet);
}
return View(site);
}
JSON file이 아닌, 오류 화면이 보여진다. (Details View 파일이 없으므로)
if문을 사용하는 대신, Ajax와 Non-Ajax를 구분하기 위한 action method selector를 사용할 수 있다.
CustomAttribute.cs
AcceptAjaxAttribute는 Ajax request일 때만 IsValidForRequest method를 통해 true를 반환한다.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AcceptAjaxAttribute : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(
ControllerContext controllerContext, MethodInfo methodInfo)
{
return controllerContext.HttpContext
.Request.IsAjaxRequest();
}
}
SitesController.cs
첫번째 action은 Ajax request일때만 실행된다.
두번째는 non-Ajax request일때만 실행된다. Action name은 동일하게 설정할 수 없으므로 다르게 처리하고, Details URL로 접근할 수 있도록 ActionName attribute를 사용한다.
[AcceptAjax]
public ActionResult Details(int id)
{
var site = _sites.Where(s => s.Id == id).FirstOrDefault();
return Json(site, JsonRequestBehavior.AllowGet);
}
[ActionName("Details")]
public ActionResult Details_NonAjax(int id)
{
var site = _sites.Where(s => s.Id == id).FirstOrDefault();
return View(site);
}
non-Ajax 버전의 view도 추가한다.
Details.cshtml
@model AjaxExamples.Models.Site
<h2>Site Details: @Model.Name</h2>
<p class="site">
<img src="@Model.PictureUrl"
alt="@Model.Name" />
<span class="site-explain">@Model.Explanation</span>
</p>
<br style="clear:both" />
@Html.ActionLink("Back to sites", "index")
'ASP.NET MVC' 카테고리의 다른 글
ASP.NET MVC] RenderPartial, Partial, RenderAction, Action (0) | 2022.07.15 |
---|---|
ASP.NET MVC] ChildActionOnlyAttribute, ActionMethodSelectorAttribute (0) | 2022.07.15 |
ASP.NET MVC] Ajax Submit - .post() (0) | 2022.07.12 |
ASP.NET MVC] Ajax Request - .load() (0) | 2022.07.12 |
ASP.NET MVC] View Model (0) | 2022.07.11 |
댓글