ROMANCE DAWN for the new world

Microsoft Azure を中心とした技術情報を書いています。

ASP.NET MVC で JSON の一部として PartialView を返す方法

gooner.hateblo.jp

前回の記事では、Ajax 通信でページを部分更新する際の例外処理について記載しましたが、それに関連した内容です。

ASP.NET MVC 5 の Ajax 通信で PartialView を返す際に、JSON の一部として返したいケースがありました。例外処理と似たような感じで、Exception が発生した際にエラーページに遷移するのではなく、メッセージボックスで通知したいシナリオです。元ネタの実装とほとんど同じなのですが、自分なりに整理してみました。

ベースとなる抽象コントローラークラスを用意して、PartialView を含む JSON を返すヘルパーメソッドを実装します。部分ビュー名、バインドするモデル、エラーメッセージを受け取って、JsonResult を返します。

#MyBaseController.cs
public abstract class MyBaseController : Controller
{
    protected JsonResult PartialViewAsJson(string viewName)
    {
        return PartialViewAsJson(viewName, null, null);
    }
 
    protected JsonResult PartialViewAsJson(string viewName, string exceptionMessage)
    {
        return PartialViewAsJson(viewName, null, exceptionMessage);
    }
 
    protected JsonResult PartialViewAsJson(string viewName, object model)
    {
        return PartialViewAsJson(viewName, model, null);
    }
 
    protected JsonResult PartialViewAsJson(string viewName, object model, string exceptionMessage)
    {
        ViewData.Model = model;
        var viewAsString = "";
        using (var sw = new StringWriter())
        {
            var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
            var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
            viewResult.View.Render(viewContext, sw);
            viewAsString = sw.GetStringBuilder().ToString();
        }
        return Json(new { partialView = viewAsString, message = exceptionMessage });
    }
}

MyBaseController クラスを継承した HomeController クラスでは、PartialView ヘルパーメソッドではなく、上記で実装した PartialViewAsJson ヘルパーメソッドで ActionResult を返します。

#HomeController.cs
public class HomeController : MyBaseController
{
    [HttpPost]
    public ActionResult AjaxTest()
    {
        if (Request.IsAjaxRequest())
        {
            try
            {
                return PartialViewAsJson(viewName: "_AjaxResult");
            }
            catch (Exception ex)
            {
                return PartialViewAsJson(viewName: "_AjaxResult", exceptionMessage: ex.Message);
            }
        }
        return Content("Ajax 通信以外のアクセスはできません。");
    }
}

ビューでは、 Ajax 通信のレスポンスの JSON を受け取り、エラーメッセージがあれば alert を表示し、なければ部分ビューを表示します。

#Ajax.cshtml
@section Scripts
{
    @Scripts.Render("~/bundles/jqueryval")
    <script>
        $(function () {
            $('#test').click(function () {
                $.ajax({
                    type: 'POST',
                    url: 'AjaxTest'
                })
                .done(function (data, textStatus, jqXHR) {
                    if (data.message != null) {
                        alert(data.message);
                    }
                    else {
                        $('#ajax-result').html(data.partialView);
                    }
                })
                .fail(function (jqXHR, textStatus, errorThrown) {
                    if (jqXHR.status == 401) {
                        $(location).attr("href", "/Account/Login/");
                    }
                    else {
                        $(location).attr("href", "/Error/AjaxError/");
                    }
                });
            })
        })
    </script>
}

Ajax 通信のレスポンスでは、次のような JSON が返されていることが確認できます。

ajax03

まとめ

ASP.NET MVC で、デスクトップアプリケーションに似たデザインの UI を作るとなると、Ajax 通信でページを部分更新するケースは多くなります。その際に、JSON の一部として PartialView を返すことができると、意外と便利なケースがあるのではないかと思います。