MVC 4スターター写真サイト

ボンジオッツォフォトサイト



誰かが自分の写真サイトを作成したい、または例としてASP.NET MVCに精通したい場合、そのようなサイトを作成する私の経験は役に立つかもしれず、ソースコードは私自身のプロジェクトの基礎を形成します。



議論される内容を明確にするために、サイトへのリンクはwww.bongiozzo.ruです。



そして今、実際には、それがどのように行われたか。



何が欲しかった?



タスクが設定されました、行きましょう...







開発環境とフレームワークを決定する


まず、Visual Studio 2012 RCを自由にダウンロードしてインストールしました。 WebフォームとMVCはWebサイト開発に使用できます-私の好きなものは完全にMVCの側にあります。 このパターンは、Webフォームが見えないときにPerlでサイトを作成するために使用されました:)。

MVCバージョンについても特別な考えはありませんでした。すべてが新しい(Windows 8上のVS 2012)ので、MVC 4の最新バージョンで開発します。



主なものはコンテンツです


私はすでにFlickrにプロアカウントを持っていますが 、これは絶対にオプションの条件です。 SmartSetrサービスを使用して、Flickrのアルバムによる写真の自動グループ化と並べ替えが既に構成されています。 したがって、私が最初にしたことはNuget Package Managerを開くことでした。Flickrを導入することで、Flickr.NETライブラリを使用するプロジェクトでFlickr APIのサポートを得ました。

おそらく、後でCMSを500pxに移植することを検討するか、誰かが私よりも速くそれを行うでしょう。



FlickrをCMSとして使用するというアイデアは簡単でした-説明にProjectキーワードを含む写真アルバムが私のサイトに表示されます(FlickrではPhotosetと呼ばれます)。 アルバム内の写真は、Flickrユーザーが決定した人気順にソートされます。



FlickrModelデータモデルの簡単なメソッドを次に示します。



public List<FlickrProject> GetProjects(string language) { PhotosetCollection flickrPhotosets = flickr.PhotosetsGetList(Properties.Settings.Default.FlickrUserId); Regex reg_Project = new Regex(@"^Project\s+([^\|].*)\s+\|\s+(.*)"); Match m; List<FlickrProject> returnProjects = new List<FlickrProject>(); foreach (Photoset item in flickrPhotosets) { m = reg_Project.Match(item.Description); if (m.Success) { FlickrProject prj = new FlickrProject(); prj.Description = getDescription(item.Description, language); prj.PhotosetId = item.PhotosetId; prj.Photos = GetPhotosetPhotos(item.PhotosetId, language); prj.PrimaryPhoto = prj.Photos.ToList().Find( delegate(Photo ph) { return ph.PhotoId == item.PrimaryPhotoId; }); returnProjects.Add(prj); } } return returnProjects; } public PhotosetPhotoCollection GetPhotosetPhotos(string photosetId, string language) { PhotosetPhotoCollection photos = flickr.PhotosetsGetPhotos(photosetId, PhotoSearchExtras.Description ); foreach (Photo item in photos) { item.Title = getTitle(item.Title, language); item.Description = getDescription(item.Description, language); } return photos; }
      
      







Kinopoiskの最新のTwitter投稿と映画評価のモデルは、 それほど複雑ではありません。



気付いた場合、メソッドは異なる言語で写真の名前と説明を返します。



自分の写真に名前を付けますか、それとも英語ですか?


少し前にそのような質問がありました。 名前をロシア語と英語で複製し、縦棒|で分割することにしました。 現在、このネーミングは、サイトで最適な方法で使用できるようになりました-訪問者がブラウザ設定でデフォルトでロシア語を使用している場合-彼のネイティブ名、そうでなければ英語を表示します。 私のサイトの写真ホスティングサイトとは異なり、これは分割棒なしで自然に見えます。



MVCには、すべてまたは個々の要求に適用されるフィルターメカニズムがあります。 このタスクのために、LocalizationAwareフィルターが実装されました。これは、サイトのメインページへのリクエストに対して機能し、ブラウザーの設定に応じて目的の言語カルチャを設定します。



  public class LocalizationAwareAttribute : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { var httpContext = filterContext.HttpContext; string language = "en"; HttpCookie langCookie = httpContext.Request.Cookies["lang"]; if (langCookie == null) { if (httpContext.Request.UserLanguages != null && httpContext.Request.UserLanguages[0].IndexOf("ru", StringComparison.OrdinalIgnoreCase) != -1) language = "ru"; httpContext.Response.AppendCookie(createCookie(language)); } else if (langCookie.Value == "ru") language = "ru"; Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(language); } public static HttpCookie createCookie(string language) { HttpCookie cookie = new HttpCookie("lang", language); cookie.Expires = DateTime.Now.AddYears(1); return cookie; } }
      
      







もちろん、デフォルトの選択が適切でない場合は、言語を変更することができます。



  public ActionResult setLanguage(string id) { id = id == "ru" ? "ru" : "en"; Response.AppendCookie(LocalizationAwareAttribute.createCookie(id)); return Redirect("/"); }
      
      







写真の名前に加えて、すべてのページ要素(ヘッダーとテキスト)も、公開された言語文化とプロジェクト内の2つのリソースファイル(Resources.resxとResources.ru.resx)の存在により、選択した言語に自動的に切り替わります。 このためにエンコードするために余分なものは必要ありませんでした-この機能は組み込みです。



パフォーマンスとキャッシュ


ネットワークサービスの利点は明らかですが、特にピーク負荷時に応答が遅い場合、これらの利点は無効になります。 明らかに、Flickr、Twitter、およびその他のシステムからの応答をキャッシュする必要があります。



簡単にするには、メソッドの前にOutputCache属性を指定して適切なフィルターを接続するだけです。

ページを作成するには、いくつかのアクション(メインリクエスト(たとえば、インデックス))と、さまざまな外部システムからの応答を含むページの一部をレンダリングするためのいくつかのChildActionsを使用します。 コンテンツのタイプごとに、変更のダイナミクスに応じて、独自のキャッシュ期間を使用できます。



  [LocalizationAware] [OutputCache(Duration = 20 * 60, Location = System.Web.UI.OutputCacheLocation.Server, VaryByCustom = "lang")] public ActionResult Index() { return View(bag); } [ChildActionOnly] [OutputCache(Duration = 10*60*60)] public ActionResult GetProjects(string language) { HomeViewBag bag = new HomeViewBag(); FlickrContext flickr = new FlickrContext(); bag.FlickrProjects = flickr.GetProjects(language); return View(bag); } [ChildActionOnly] [OutputCache(Duration = 60 * 60)] public ActionResult GetLastPhotos(string language) { HomeViewBag bag = new HomeViewBag(); FlickrContext flickr = new FlickrContext(); bag.LastPhotos = flickr.GetLastPhotos(5, language, 1).ToList(); return View(bag); }
      
      







ASP.NET MVC自体は、入力パラメーターの値に応じて、結果のキャッシュされたコピーを分割します。 ChildActionsの場合、言語形式の入力パラメーターは明示的に定義されますが、基本的なクエリの場合、セッション言語に応じてキャッシュを分割する必要があり、このパラメーターはパラメーターに存在しません。 これは、VaryByCustom =“ lang”属性と特別なGetVaryByCustomStringメソッドを使用して実装されます。 これで、キャッシュにオーバーレイが表示されなくなります。



  public override string GetVaryByCustomString(HttpContext context, string arg) { if (arg.ToLower() == "lang") { string langParam = context.Request.QueryString["lang"]; HttpCookie langCookie = context.Request.Cookies["lang"]; if (langParam != null) return langParam == "ru" ? "ru" : "en"; else if (langCookie != null) return langCookie.Value == "ru" ? "ru" : "en"; return ""; } return base.GetVaryByCustomString(context, arg); }
      
      







デザインとフォトギャラリー


なぜなら タスクはもともと自分でサイトを作成するように設定されていましたが、私自身はデザイナーではありません。サイトをできる限りシンプルにし、CSS3とHTML5の表現力に制限することにすぐに決めました。 さらに、フォトサイトの主な焦点は、写真とそのプレゼンテーションにあるべきです。



そのため、使用可能なギャラリーを探して、スタイリッシュなガレリアソリューションに決めました。 ギャラリーはjQueryで記述され、独自のAPIを備えています。拡張に十分な基本エディションは無料で使用できます。 必要なもの。



微調整に加えて、彼はギャラリーの初期化モジュールに独自のナビゲーション要素とソーシャルネットワークとの統合を追加しました。



  this.append({ 'stage': ['closeBG', 'socialBG'] }); this.$('socialBG').html('<div id="div-fblike"></div><div id="div-twitter"></div>'); this.$('closeBG').bind("click", function (e) { window.location = "/"; });
      
      







ギャラリーを写真で埋めるのは、FlickrModelから取得したデータでJSON形式の配列を埋めるようなものです。



コントローラーでのJSON生成:



  private string getJSON(List<Photo> list, string p) { List<PhotoJSON> json = new List<PhotoJSON>(); foreach (Photo pht in list) json.Add(new PhotoJSON { thumb = pht.ThumbnailUrl, image = pht.LargeUrl, title = pht.Title, description = pht.Description, link = pht.WebUrl, url = Settings.Default.SiteURL + Url.Action("Gallery", new { controller = "Home", id = pht.PhotoId, photoset = p }) }); JavaScriptSerializer serializer = new JavaScriptSerializer(); return serializer.Serialize(json); }
      
      







ビューアーのJavaScript:



  var data = @Html.Raw(Model.PhotosJSON); Galleria.loadTheme('/galleria/themes/bongiozzo/galleria.bongiozzo.js'); Galleria.run('#galleria', { show: @Model.IndexOfCurrentPhoto, transition: 'slide', initialTransition: 'fade', dataSource: data });
      
      







ツイートやいいねを投稿します


ギャラリーで写真を切り替えるイベントでは、FacebookおよびTwitterボタンの更新を終了します。



  this.bind("image", function (e) { document.title = galleria.getData().title; $('#div-fblike').html('<fb:like href="' + data[galleria.getIndex()].url + '" layout="button_count" send="false" show_faces="false" colorscheme="dark" />'); $('#div-twitter').html('<a href="https://twitter.com/share" class="twitter-share-button" data-url="' + data[galleria.getIndex()].url + '" data-text="' + galleria.getData().title + '">Tweet</a>'); try { FB.XFBML.parse(document.getElementById('div-fblike')); twttr.widgets.load(); } catch(ex) {} });
      
      







また、Facebookやその他のOG互換システムで正しく表示するには、OpenGraphタグを入力することを忘れないでください。



  <meta property="fb:app_id" content="@Model.fb_app_id"/> <meta property="og:title" content="@ViewBag.Title" /> <meta property="og:site_name" content="@Resources.Resources.Title" /> <meta property="og:type" content="website" /> <meta property="og:url" content="@Model.SiteUrl@Url.Action("Gallery", new { controller = "Home", id = Model.GalleryPhotos[Model.IndexOfCurrentPhoto].PhotoId, photoset = Model.PhotosetId})" /> <meta property="og:image" content="@Model.GalleryPhotos[Model.IndexOfCurrentPhoto].SquareThumbnailUrl" /> <meta property="og:description" content="@Html.Raw(Model.GalleryPhotos[Model.IndexOfCurrentPhoto].Description.Replace("\n","<br/>"))" />
      
      







プロジェクトをホストする場所は?


ちなみに、写真サイトが立ち上げられる頃には、10個の無料の共有サイト備えたWindows Azureクラウドホスティングが利用可能になりました。 ただし、データベースがなく、写真自体がFlickrに保存されているため、データベースとトラフィックには別のコストがかかります。したがって、トラフィックはありません。ホスティングはほぼ無料です。 同時に、Azureの場合、重要なサービスの品質と可用性に関する質問はありません。 サービスの管理は明確でシンプルです。Azureが登場する前は、他のプロバイダーからのホスティングを検討していましたが、これはサポートサービスとの紛らわしいインターフェイス、通信、電話通信の対比で特に印象的でした。



残念ながら、1つしかありません-ドメイン名をこの共有サイトにバインドすることはできません。 本当に自分のドメイン名を必要とせず、bongiozzo.azurewebsites.netのようなURLに満足している人にとって、これは本当に最良の選択肢です。

ただし、これが共有サイトの時間制限であることを期待しています。 したがって、サイトを予約モードにすると、そのようなバインディングを行うことができます。 いずれにせよ、90日間の試用版はまだ実行中であり、特定の数のAzureサービスのプリペイド額をオンにしたMSDNサブスクリプションを持っています。



Azure Webサイトの次のバージョンがリリースされます-最小限のホスティングInfobox.ruParking.ruなど、またはクラウドサービスのXSインスタンスに移行するかもしれませんが、今のところ動作しますが、お金はかかりません。



結論として





All Articles