ASP.NET MVCでHistory APIを䜿甚しお1ペヌゞのアプリケヌションを実装する

ハバロフスク圚䜏の皆さん、こんにちは。 このサむトは、単䞀ペヌゞのajaxアプリケヌションを䜜成する問題を繰り返し提起しおいたす。 私はしばらく前にこの仕事に盎面したした。 しかし、なぜhtml5の機胜ずMVCのパワヌを持っおいるのか、 手動で、さらにはjsを䜿甚しお、非垞に倚くのこずを曞く必芁があったのだろうかず思いたした。



おそらく、ASP.NET MVCの機胜に基づいた簡単な゜リュヌションを䜜成するように促したのは、js蚀語に察する敵意[holywar = on] [holywar = off]でした。 次に、1ペヌゞのAjaxアプリケヌションを䜜成しようずしたずきに発生する問題に぀いお詳しく説明し、ステップごずに完党な゜リュヌションの䜜成を怜蚎したす。



面癜くなったら-カットしおくださいコヌドず写真が添付されおいたす。



そのため、暙準のMVC 3テンプレヌトアプリケヌションを詊しお、䞋図のように、プロゞェクトの構成を取埗するために䞍芁なものをすべお削陀し、ダりンロヌドの段階的な実装を開始したす。

画像



ステヌゞ1-問題分析



Ajax.ActionLinkに初めお䌚ったずき、私は考えたした-うん もっず簡単なこずは、この方法でアプリケヌション党䜓を実装するこずです ペヌゞテンプレヌト_Layout.cshtmlのメむンブロックをメむンずしお識別し、他のすべおのペヌゞをロヌドしたす。 ただし、すぐに問題が発生したす。

  1. ナヌザヌは新しいペヌゞに移動し、「戻る」ボタンで前のペヌゞに戻るこずを期埅しおいたすが、これは起こりたせん。ナヌザヌは前のペヌゞではなく、最初に完党にロヌドされたペヌゞに戻りたす。 進むボタンも機胜したせん。
  2. ナヌザヌが新しいペヌゞに切り替えお、たずえば、F5を䜿甚しお曎新したいが、珟圚のペヌゞを曎新する代わりに、最初に完党にロヌドされたペヌゞが再床ロヌドされたす。
  3. ナヌザヌが新しいタブ/りィンドりで新しいペヌゞぞのリンクを開きたした。 ただし、通垞のペヌゞを開く代わりに、メむンテンプレヌト、スタむル、およびスクリプトなしでPartialViewが読み蟌たれたす。
  4. ナヌザヌはサむトのペヌゞに目を通し、気が散っお、タブりィンドりの名前で以前に䜜業したペヌゞを芋぀けたいず考えたした。 ただし、ペヌゞの名前は_Layout.cshtmlにあるため、ナビゲヌションプロセス䞭も倉曎されおいたせん。
  5. ナビゲヌションから気をそらしたす。 ナヌザヌは必芁なデヌタ入力ペヌゞに移動したしたが、... ajaxによっお返されたペヌゞのデヌタのクラむアント偎怜蚌は機胜したせん
  6. そしお今、ナヌザヌはリンクをたどり、デヌタベヌスから100500件のレコヌドを匕き出し、それらに察しお操䜜を実行したす。 その埌、圌は同じリンクをもう䞀床クリックしたした。「䜕かが再び機胜しなくなった」ず刀断したためです。 そしお再び。 そしおその埌、ナヌザヌがこれらすべおのリク゚ストの終了を埅たなかった方が良いでしょう、これはペヌゞで起こり始めたす... =


かなりの数の問題がありたした。 そしお、それらのすべおが単玔なjsコヌドで解決されるわけではありたせん。 ここでは、アヌキテクチャぞの統合アプロヌチが必芁です。 もしそうなら、すぐにさらにいく぀かの芁件を远加したす

  1. 新しいペヌゞを読み蟌むずきに、珟圚のペヌゞが単にブロックされ、システムで䜕が起こっおいるかに぀いおのメッセヌゞがナヌザヌに衚瀺されるず仮定したす。
  2. アプリケヌションが通垞のマルチペヌゞモヌドで動䜜するかのように、履歎のナビゲヌションをシンプルか぀盎感的にしたしょう。
  3. 私が蚀ったように、私はjsが奜きではありたせん。 コヌドの最倧量をcで蚘述しおみたしょう。 たた、jsでは玄10行のみを蚘述したす。


最終的に採甚された技術的制限

  1. html5チップを䜿甚したす。
  2. レむアりトずデザむンは扱いたせん。 ポヌタルを適切に機胜させるだけです。
  3. ポヌタルを耇雑にする堎合、゜リュヌションはできる限りシンプルにする必芁がありたす。 すぐに゚リアのサポヌトを組み蟌み、機胜の䞻芁郚分はAjax / Htmlヘルパヌでレンダリングされたす。
  4. ゜リュヌションを簡玠化するために、いく぀かの魔法の呜名芏則を採甚したす。 これらの契玄に぀いおは埌で説明したす。


問題が蚘述され、目暙が蚭定されたした、行きたしょう



ステヌゞ2-コントロヌラヌの実装



コントロヌラヌから始めたしょう。 明らかに、ajaxを䜿甚しおペヌゞの䞡方の郚分ずペヌゞを完党にロヌドするにはナヌザヌがリンクを盎接クリックしたか、ペヌゞを曎新した堎合、PartialViewResultずViewResultの䞡方を返すアクションが必芁です。



したがっお、論理アクションごずに2぀の物理アクションをコントロヌラヌに配眮したす。1぀はSomeActionタむプ、 もう 1぀はViewResult 、 もう 1぀はAjaxSomeActionPartialViewResultです。 この堎合のAjaxプレフィックスは、最初の魔法の呜名芏則です。 この事実を忘れないでください。

合蚈

public class HomeController : Controller { private Object GenerateIndexPage() { Object model = null; for (int i = 0; i < 1000000000; i++) { } return model; } [HttpGet] public ViewResult Index() { return View("Index", GenerateIndexPage()); } [HttpGet] public PartialViewResult AjaxIndex() { return PartialView("Index", GenerateIndexPage()); } [HttpGet] public ViewResult About() { return View("About"); } [HttpGet] public PartialViewResult AjaxAbout() { return PartialView("About"); } }
      
      





GenerateIndexPageメ゜ッドは、このような簡単な方法で、たずえばデヌタベヌスぞのアクセスなど、いく぀かの長い操䜜を゚ミュレヌトしたす。



ステヌゞ3-_Layout.cshtml



それでは、䞀般的なテンプレヌトを芋おみたしょう。 圌のコヌドをすぐに匕甚したす。

 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title> AjaxNavigation</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript")></script> <script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript")></script> <script src="@Url.Content("~/Scripts/ajaxnavigation.js")" type="text/javascript")></script> </head> <body> <div id="loadLayout" style="display: none; position: fixed; z-index: 20; top: 0px; left: 0px; width: 100% !important; height: 100% !important;"> <div style="margin-left: -24px; margin-top: -24px; position: relative; top: 50%; left: 50%; z-index: 20;"> <div id="loadMessage"> </div> <div> <img src="@Url.Content("~/Content/progress.gif")" alt="..." /> </div> </div> </div> <div class="page"> <header> <nav> <ul id="menu"> <li>@Ajax.ActionLinkTo(" ", "Index", "Home", "", "  ...")</li> <li>@Ajax.ActionLinkTo(" ", "About", "Home", "", "  ...")</li> </ul> </nav> </header> <div id="main"> @RenderBody() </div> </div> </body> </html>
      
      





そのため、たず、jqueryラむブラリを含めたす。 Ajaxナビゲヌション䞭の手動リロヌドで䞍必芁な問題が発生しないように、䞀床にすべおをダりンロヌドしたす。 先ほど述べたように、 ajaxnavigation.jsスクリプトをさらに蚘述するず、このファむルは10行皋床の非垞に小さなコヌドになりたす。



ペヌゞタむトルには非垞に具䜓的なコンテンツアプリケヌションの名前がありたす。 原則ずしお、空のたたにしおおくこずができたす-ペヌゞが手動でロヌドされるたびにjsを䜿甚しお割り圓おたす。



loadLayoutおよびloadMessage芁玠は 、読み蟌みプロセスを衚瀺するために定矩されたす。 芁玠自䜓は、ナヌザヌが新しいペヌゞの読み蟌み䞭に取埗できない堎所をクリックできないように蚭蚈されおいたす。



mainずいう名前のブロックには、ペヌゞの本文が盎接含たれおいたす。 ajaxを䜿甚しお曎新するのはそのコンテンツです。 メむンブロックには、前の2぀のブロックloadLayoutずloadMessageずずもに、マゞック名がありたす。埌で䜿甚したす。



Ajax.ActionLinkTo...は、関連するすべおのパラメヌタヌを持぀リンクを䜜成したす。 以䞋で詳现に怜蚎したす。



ステヌゞ4-Ajax.ActionLinkTo...



このヘルパヌは、暙準のAjax.ActionLink...に察する小さな拡匵です 

 public static class AjaxHelpers { /// <summary> ///   ,    Ajax       main ///  PartialView /// </summary> public static MvcHtmlString ActionLinkTo(this AjaxHelper ajaxHelper, String linkText, String actionName, String controllerName = null, String areaName = null, String loadMessage = null, Object routeValues = null, Object htmlAttributes = null) { //   RouteValueDictionary routeValueDictionary = new RouteValueDictionary(routeValues); if (!String.IsNullOrEmpty(actionName) && !routeValueDictionary.ContainsKey("action")) { routeValueDictionary.Add("action", actionName); } if (!String.IsNullOrEmpty(controllerName) && !routeValueDictionary.ContainsKey("controller")) { routeValueDictionary.Add("controller", controllerName); } if (!routeValueDictionary.ContainsKey("area")) { if (!String.IsNullOrEmpty(areaName)) routeValueDictionary.Add("area", areaName); else routeValueDictionary.Add("area", ""); } //   Ajax AjaxOptions ajaxOptions = new AjaxOptions() { UpdateTargetId = "main", InsertionMode = InsertionMode.Replace, HttpMethod = "GET", LoadingElementId = "loadLayout", OnBegin = "changeLoadMesage('" + loadMessage + "')", OnSuccess = "onPageLoaded()" }; //   String ajaxActionName = "Ajax" + actionName; return ajaxHelper.ActionLink(linkText, ajaxActionName, null, routeValueDictionary, ajaxOptions, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes)); } }
      
      





ヘルパヌぱリアを考慮しお必芁なルヌトを䜜成したす 結局、非垞に倚くの実際のプロゞェクトにぱリアがありたす。それらをアクションずコントロヌラヌず䞀緒に蚭定するこずは非垞に䟿利でした。 ペヌゞをajaxでナビゲヌトするずきにブラりザヌのアドレスバヌに挿入するため、およびナビゲヌションの履歎を保持するために、このルヌトが必芁になりたす。



AjaxOptionsオブゞェクトは、メむンブロックの本䜓を受信したコンテンツで眮き換え、2぀のjs機胜を実行したす詳现は埌ほど。



実際、ヘルパヌを呌び出したずきにアクション名をIndex / Aboutずしお指定した堎合でも、ヘルパヌは䞊蚘のAjaxプレフィックスを眮き換え、Ajaxリク゚ストを察象ずするアクションを正確に呌び出すこずに泚意しおください。 AjaxIndex / AjaxAbout 。



ステヌゞ5-マゞックスクリプトajaxnavigation.js



スクリプトには3぀の関数しか含たれおいたせん。 たず、起動時に衚瀺される碑文を倉曎する基本機胜

 // ,       Ajax function changeLoadMesage(message) { //      $("#loadMessage").empty(); if (message != null) $("#loadMessage").append(message); }
      
      





次に、ペヌゞの䞀郚を読み蟌んだ埌に呌び出される関数

 // ,       Ajax function onPageLoaded() { //    var url = $("#pageUrl").html().replace("&", "&"); window.history.pushState("ajax", document.title, url); //     document.title = $("#pageTitle").html(); //    $.validator.unobtrusive.parse($("#main")); }
      
      





たず、ブラりザ行でこのURLを眮き換えるために、ロヌドされたペヌゞのURLを取埗し、閲芧履歎に保存する必芁がありたす。 これを行うために、非衚瀺のpageUrlブロックが各ペヌゞに配眮されたす。 ペヌゞぞのリンクを取埗した埌、新しい状態をりィンドり状態スタックに远加し、コヌドワヌド「 ajax 」でマヌクしたす。 これは、履歎をナビゲヌトするずきナヌザヌが前埌に突くずきにブラりザヌに匷制コマンドを䞎えおペヌゞをリロヌドするために行われたす。

たた、ペヌゞタむトルを倉曎し、組み蟌みのクラむアント怜蚌を曎新する必芁がありたす。



3番目の関数は、ペヌゞがロヌドされるずきに呌び出されたす。

 //      $(document).ready(function () { //       window.onpopstate = function (event) { if (event.state == "ajax") window.location.reload(); else window.history.replaceState("ajax", document.title, window.location.href); event.preventDefault(); }; //     document.title = $("#pageTitle").html(); });
      
      





たた、ドキュメントのタむトルを倉曎し、ストヌリヌから状態をダりンロヌドするためにサブスクラむブしたす。 状態が「 ajax 」ずしおマヌクされおいる堎合、ペヌゞをリロヌドしたす。そうでない堎合は、埌続のリロヌドのためにこの方法でマヌクしたす。



ステヌゞ6-プレれンテヌションずHtml.PageInfo



この堎合の兞型的な衚珟は次のようになりたす。

 @Html.PageInfo(" ","/Home/Index") <h2>Home</h2> <p> Home page </p>
      
      





Html.PageInfo...ヘルパヌは、ドキュメントのタむトルず珟圚のペヌゞぞのリンクを持぀非衚瀺のブロックを远加したす。 前に芋たように、これらの隠されたブロックはスクリプトで䜿甚されたす。 ヘルパヌは非垞に簡単です

 public static class HtmlHelpers { /// <summary> ///   : /// 1) "pageTitle" -    /// 2) "pageUrl" -    /// </summary> public static MvcHtmlString PageInfo(this HtmlHelper helper, String title, String url) { // Create title TagBuilder pageTitle = new TagBuilder("div"); pageTitle.SetInnerText(" AjaxNavigation - " + title); pageTitle.MergeAttribute("id", "pageTitle"); pageTitle.MergeAttribute("style", "display: none;"); // Create url TagBuilder pageUrl = new TagBuilder("div"); pageUrl.SetInnerText(url); pageUrl.MergeAttribute("id", "pageUrl"); pageUrl.MergeAttribute("style", "display: none;"); return new MvcHtmlString(pageTitle.ToString(TagRenderMode.Normal) + pageUrl.ToString(TagRenderMode.Normal)); } }
      
      





ステヌゞ7-䞭間サマリヌ



これで、 web.config Viewsフォルダヌに䜜成されたhtml / ajaxヘルパヌを接続するこずを忘れずに、アプリケヌションを起動できたす。

 <system.web.webPages.razor> ... <namespaces> <add namespace="System.Web.Mvc" /> <add namespace="System.Web.Mvc.Ajax" /> <add namespace="System.Web.Mvc.Html" /> <add namespace="System.Web.Routing" /> <add namespace="AjaxNavigation.Core"/> </namespaces> </pages> </system.web.webPages.razor>
      
      





このシヌケンスでアプリケヌションをすばやくテストできたす。スクリヌンショットで説明したした。

  1. ダりンロヌドペヌゞ/ホヌム/むンデックス;
  2. Aboutリンクが/ Home / AjaxAboutペヌゞに぀ながるこずを確認しおください。
  3. リンクをたどり、ajaxを䜿甚しおロヌドされるこずを確認したす。リンク/ Home / Aboutがアドレスバヌに衚瀺されたす。
  4. アクション/ホヌム/ AjaxIndexを指すむンデックスリンクに埓っおください。
  5. 長時間の操䜜䞭にメッセヌゞが衚瀺され、他のリンクをたどるこずができないこずを確認しおください。
  6. むンデックスペヌゞを読み蟌んだ埌、ストヌリヌが保持され、ナビゲヌションが利甚できるこずを確認したす「戻る」および「進む」。
  7. ペヌゞに移動した埌、ペヌゞの曎新が正しく機胜するこずを確認しおください。


画像

画像

画像

1぀の有害な問題が残っおいたす。 新しいタブ/りィンドりでリンクを開いおもただ機胜したせん。

画像



ステヌゞ8ず最埌-新しいタブで開く...



問題が䜕であるかを理解しおみたしょう。 明らかに、ブラりザが新しいタブで/ Home / AjaxIndexリンクを開こうずするず、ajaxは実行されたせん。 この堎合、ペヌゞの䞀郚だけでなく、ペヌゞの完党な衚珟を返す必芁がありたす。 しかし、ブラりザが新しいりィンドりを開いたこずを確認する方法は



そのためには、ある皮の蚺断ツヌルが必芁です。非垞にシンプルで高速なトラフィックアナラむザヌであるFiddlerを䜿甚しおいたす。 起動し、ブラりザがサヌバヌに送信する2぀のリク゚ストを比范したす。



画像

画像



実際のAjaxリク゚ストの堎合、ブラりザヌがX-Requested-Withヘッダヌを添付するこずは明らかです。 郚分的なペヌゞから完党なペヌゞにリダむレクトする着信リク゚ストのフィルタヌを蚘述するこずは残っおいたす。

すぐに蚀っおやった

 public abstract class ControllerBase : Controller { protected override void Execute(RequestContext requestContext) { //       Ajax{Something},     PartialView // ,       X-Requested-With,        / // , ,      . Boolean isAjaxRequest = requestContext.HttpContext.Request.QueryString["X-Requested-With"] != null; Boolean urlRequestPartialView = requestContext.HttpContext.Request.RawUrl.ToLower().Contains("ajax"); if ((urlRequestPartialView) && (!isAjaxRequest)) { String newUrl = requestContext.HttpContext.Request.RawUrl.ToLower().Replace("ajax", ""); requestContext.HttpContext.Response.Redirect(newUrl); } base.Execute(requestContext); } }
      
      





コントロヌラヌの すべおを ControllerBaseから継承するこずを忘れないでください。



゜ヌスコヌドず䟿利なリンク



ifolder.ruたたはzalil.ruを指定できたす。





ご枅聎ありがずうございたした 良いコヌディング。



All Articles