ساخت یک پروژه بلاگ با قابلیت شخصی سازی در MVC
جمعه 23 بهمن 1394در این مقاله به پیاده سازی یک پروژه ساده وبلاگ خواهیم پرداخت .در این پروژه از بانک برای نگه داری اطلاعات استفاده نخواهیم کرد بلکه برای ذخیره و تبادل اطلاعات از Json کمک خواهیم گرفت بنابراین در طول این مقاله با مفاهیم اصلی MVC و همچنین کار با Json به صورت عملی آشنا خواهید شد .
در این مقاله به پیاده سازی یک پروژه ساده وبلاگ خواهیم پرداخت .در این پروژه از بانک برای نگه داری اطلاعات استفاده نخواهیم کرد بلکه برای ذخیره و تبادل اطلاعات از Json کمک خواهیم گرفت بنابراین در طول این مقاله با مفاهیم اصلی MVC و همچنین کار با Json به صورت عملی آشنا خواهید شد .
همیشه قبل از شروع کار عملی کمی راجع به مفاهیم اولیه صحبت خواهیم کرد .همان طور که می دانید فرآیند تبدیل یک شی به رشته برای ذخیره کردن در حافظه را Serialization می گویند .همچنین عکس این عمل یعنی تبدیل رشته به شی را deserialize می گویند.
Json یک فرمت تبادل اطلاعات است که زبان جاوااسکریپت به صورت خودکار آن را می فهمد ولی برای سایر زبان ها نیاز داریم که فرم ورک هایی را به برنامه اضافه کنیم تا بتوانیم با این فرمت تبادل اطلاعات یعنی json کار کنیم .
برای کار با json رفرنس System.web.Extensions.dll را به برنامه اضافه می کنیم .سپس یک نمونه شی از JavaScriptSerializer ایجاد می کنیم .در داخل این کلاس دو متد مهم Serialize و deSerialize قرار دارد که با استفاده از این دو متد به deserialize و Serialize کردن اشیا می پردازیم .
همچنین به روش دیگری هم می توان با json کار کرد و آنهم این است که در کد زیر یک لیستی از اشیا (هر شی ایی فرقی نمی کند ) را به متد json داده ایم و همچنین در پارامتر دوم مشخص کرده ایم که json می تواند به داده ها دسترسی داشته باشد .
return Json(ObjEmp, JsonRequestBehavior.AllowGet);
این خط باعث می شود که داده هایی از نوع json را به سمت view ارسال کنیم اگر که قصد داشته باشیم از این داده ها در داخل viewخود استفاده کنیم و به همان صورت json نمایش داده نشود لازم است که در سمت view به صورت زیر عمل کنیم که ابتدا رفرنس jquery را به پروژه می دهیم سپس در داخل صفحه view و در اسکریپتی که می نویسیم با کد زیر
$.getJSON("Home/EmpDetails",
اطلاعاتی که اکشن ما به صورت json داده بود را گرفته و آن را به شیوه دلخواه نمایش می دهیم .مثلا می توان آنها را به صورت جداول و در داخل سطر هایی نشان داد به کد زیر توجه کنید .
<script> $(document).ready(function () { //Call EmpDetails jsonResult Method $.getJSON("Home/EmpDetails", function (json) { var tr; //Append each row to html table for (var i = 0; i < json.length; i++) { tr = $('<tr/>'); tr.append("<td>" + json[i].Id + "</td>"); tr.append("<td>" + json[i].Name + "</td>"); tr.append("<td>" + json[i].City + "</td>"); tr.append("<td>" + json[i].Address + "</td>"); $('table').append(tr); } }); }); </script> <table class="table table-bordered table-condensed table-hover table-striped"> <thead> <tr> <th>Id</th> <th>Name</th> <th>City</th> <th>Address</th> </tr> </thead> <tbody></tbody> </table>
حال که تا حدی با json آشنا شدید به پروژه عملی خود باز می گردیم . در این جا قصد داریم یک بلاگ ایجاد کنیم .همان طور که می دانید بلاگ مکانی است که در آن موضوعات مورد علاقه اخبار و تبلیغاتی را با افراد دیگر در اینترنت Share می کنیم .انواع مختلفی از بلاگ ها وجود دارند که از آن جمله می توان به Microblogs ، Personal blogs، Media blogs اشاره کرد .در واقع همان وب سایت است فقط شاید کمی جنبه تجاری و اداری آن کمتر باشد .
یک پروژه از نوع mvc و به صورت Empty ایجاد می کنیم . برای اینکه بتوان با json کار کرد کنابخانه آن را به پروژه خود اضافه می کنیم این کار توسط nuget به راحتی انجام می شود .در داخل tool=>nugget Package Manager=>Package Manager Consol رفته و دستور زیر را در آن تایپ و اینتر را بزنید
PM> Install-Package Newtonsoft.Json -Version 7.0.1
مدل
اگر تجربه ساخت پروژه با mvc را داشته باشید می دانید که بهتر است ابتدا مدل پروژه خود را تعیین کنید این کار به شما ایده ایجاد کنترلر و viewهای مربوط به آن را میدهد .مدلی که در اینجا به آن احتیاج داریم یک مدل برای Post است .ساختار این مدل در زیر آورده شده است
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.IO; using Newtonsoft.Json; namespace PersonalBlogTemplateWithServices.Models { public class BlogPostModel { // General properties public int ID { get; set; } public string Title { get; set; } public string Content { get; set; } public List<string> Tags { get; set; } // Time based properties public DateTime CreateTime { get; set; } // Other properties and settings may include UserID, RoleID etc. } // The class to manage the data-sources public class PostManager { // Define the members private static string PostsFile = HttpContext.Current.Server.MapPath("~/App_Data/Posts.json"); private static List<BlogPostModel> posts = new List<BlogPostModel>(); // The CRUD functions public static void Create(string postJson) { var obj = JsonConvert.DeserializeObject<BlogPostModel>(postJson); if(posts.Count > 0) { posts = (from post in posts orderby post.CreateTime select post).ToList(); obj.ID = posts.Last().ID + 1; } else { obj.ID = 1; } } posts.Add(obj); save(); } public static List<BlogPostModel> Read() { // Check if the file exists. if(!File.Exists(PostsFile)) { File.Create(PostsFile).Close(); File.WriteAllText(PostsFile, "[]"); // Create the file if it doesn't exist. } posts = JsonConvert.DeserializeObject<List<BlogPostModel>>(File.ReadAllText(PostsFile)); return posts; } public static void Update(int id, string postJson) { Delete(id); Create(postJson); save(); } public static void Delete(int id) { posts.Remove(posts.Find(x => x.ID == id)); save(); } // Output function private static void save() { File.WriteAllText(PostsFile, JsonConvert.SerializeObject(posts)); } }
در این مدل که آیتم های آن شامل id, title و .... است به تعریف کنترلرها و viewهای مربوطه خواهیم پرداخت .همان طور که دیدید در این مدل چهار عمل اصلی را هم پیاده سازی کرده ایم .حال نوبت این است که یک کنترلر ایجاد کنیم .این کنترلر حاوی اکشن هایی است که توسط آن دیتاهای خود که در اینجا فقط post است را دستکاری می کنیم .
مدل ما از دو کلاس تشکیل شده است یکی BlogPostModel است که در آن ساختار کلاس واشیا خود را مشخص کرده ایم و دیگری PostManager است که در آن چهار عمل اصلی را پیاده سازی کرده ایم .خود این کلاس از نوع public است اما متدهایی که در داخل آن تعریف شده اند به صورت Static هستند .
نام کنترلری که ایجاد کرده ایم Blog است .کد آن را در زیر می بینید
using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using PersonalBlogTemplateWithServices.Models; using Newtonsoft.Json; namespace PersonalBlogTemplateWithServices.Controllers { public class BlogController : Controller { // GET: Blog public ActionResult Index() { // Read the list var blogs = PostManager.Read(); if (blogs == null) { ViewBag.Empty = true; return View(); } else { // Just for sorting. blogs = (from blog in blogs orderby blog.CreateTime descending select blog).ToList(); ViewBag.Empty = false; return View(blogs); } } [Route("blog/read/{id}")] // Set the ID parameter public ActionResult Read(int id) { // Read one single blog var blogs = PostManager.Read(); BlogPostModel post = null; if(blogs != null && blogs.Count > 0) { post = blogs.Find(x => x.ID == id); } if(post == null) { ViewBag.PostFound = false; return View(); } else { ViewBag.PostFound = true; return View(post); } } public ActionResult Create() { if (Request.HttpMethod == "POST") { // Post request method var title = Request.Form["title"].ToString(); var tags = Request.Form["tags"].ToString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var content = Request.Form["content"].ToString(); // Save content var post = new BlogPostModel { Title = title, CreateTime = DateTime.Now, Content = content, Tags = tags.ToList() }; PostManager.Create(JsonConvert.SerializeObject(post)); // Redirect Response.Redirect("~/blog"); } return View(); } [Route("blog/edit/{id}")] public ActionResult Edit(int id) { if(Request.HttpMethod == "POST") { // Post request method var title = Request.Form["title"].ToString(); var tags = Request.Form["tags"].ToString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var content = Request.Form["content"].ToString(); // Save content var post = new BlogPostModel { Title = title, CreateTime = DateTime.Now, Content = content, Tags = tags.ToList() }; PostManager.Update(id, JsonConvert.SerializeObject(post)); // Redirect Response.Redirect("~/blog"); } else { // Find the required post. var post = PostManager.Read().Find(x => x.ID == id); if (post != null) { // Set the values ViewBag.Found = true; ViewBag.PostTitle = post.Title; ViewBag.Tags = post.Tags; ViewBag.Content = post.Content; } else { ViewBag.Found = false; } } // Finally return the view. return View(); } } }
در این کنترلر چهار اکشن وجود دارد .در داخل اکشن index ابتدا یک متغیر var به نام blogs تعریف کرده ایم .این متغیر را با post هایی که داریم پر می کنیم .یعنی با نوشتن PostManager.Read این متغیر را با لیستی از post های خود پر کرده ایم .
برای ساخت view مربوط به این اکشن از کدهای زیر استفاده می کنیم
@model List<Blog.Models.BlogPostModel> @{ ViewBag.Title = "My Blog"; Layout = "~/Views/Shared/_Layout.cshtml"; } @if(ViewBag.Message != null) { <h4>@ViewBag.Message</h4> } @if (Model == null || Model.Count == 0) { <div class="thumbnail"> <h4>Blog empty</h4> <p>Either under development, or author is busy. Visit back again later! :-)</p> <a href="~/blog/create">ایجاد پست جدید</a> </div> } else { <div class="panel panel-success"> <div class=" panel-heading" style="margin-top:20px"><h4>وبلاگ شخصی من</h4> </div> <div class="panel-body"> <p>پست های من که در زیر لیست شده اند را بخوانید </p> <br /> <div class="thumbnail"> <a href="~/blog/create">ایجاد پست جدید</a> @foreach (var post in Model) { int tagIndex = 1; <h4> <a href="~/blog/read/@post.ID">@post.Title</a> </h4> foreach (var tag in post.Tags) { if(tagIndex == post.Tags.Count) { <span class="tag"><a href="~/blog/tag/@tag">@tag</a></span> <hr /> } else { <span class="tag"><a href="~/blog/tag/@tag">@tag</a></span> } tagIndex++; } } </div> </div> </div> }
در این صفحه ابتدا چک کرده ایم که اگر لیست پست های ما خالی بود پیامی به کاربر نمایش داده شود .و در غیر این صورت به ازای هر پست در داخل مدل لینکی با محتوای همان پست ایجاد می کنیم .
اکشن Create
در داخل این اکشن Create ابتدا تعیین می کنیم که نوع درخواست ما از نوع post است .اگر بود وارد بلاک if می شویم در این بلاک تمام اطلاعات را از داخل فرم خوانده و یک شی BlogPostModel ایجاد می کنیم .سپس این شی را به متد create از کلاس PostManager می دهیم .البته توجه کنید که پارامتر این تابع از نوع string است .بنابراین توسط متد( JsonConvert.SerializeObject(post شی post را که ایجاد کرده بودیم به یک رشته تبدیل کرده و به این متد پاس می دهیم .
در داخل متد create دوباره این رشته را به شی از نوع BlogPostModel تبدیل می کنیم .بعد در داخل فولدر AppData خود یک فایل متنی به نام posts داریم این فایل حکم دیتابیس ما را دارد .در متد create چک کرده ایم که اگر این پوشه خالی بود یک شی BlogPostModel با id برابر یک برای ما ایجاد کند و در غیر این صورت با id یک به علاوه بزرگترین id موجود شی را برای ما ساخته و داخل posts ذخیره کند
view مربوط به create به صورت زیر است
@{ ViewBag.Title = "New Post"; } <h2>Create new blog post</h2> <form method="post"> <label>Title</label> <input type="text" name="title" class="form-control" placeholder="The headline goes here..." /><br /> <label>Tags</label> <input type="text" name="tags" class="form-control" placeholder="Separate each tag using a comma ','." /><br /> <label>Content</label> <textarea name="content" class="form-control" style="height: 300px;" placeholder="What would you like to write?"></textarea><br /> <input type="submit" style="width: auto; font-weight: 600;" value="Post" /><br /> </form>
اگر این viewرا اجرا کنیم شکل زیر را خواهیم دید .
بعد از اینکه پست جدید ایجاد کنید و دکمه post را بزنید به صفحه ایندکس هدایت خواهید شد
اکشن read به این صورت است که در آن به کلاس PostManager و بعد تابع read رفته و همه مطالب داخل posts را به صورت شی BlogPostModel ایجاد کرده و آن را به اکشن باز می گردانیم .
View مربوط به این اکشن به صورت زیر است
@model Blog.Models.BlogPostModel @{ ViewBag.Title = Model.Title; var tagIndex = 1; Layout = "~/Views/Shared/_Layout.cshtml"; } <div class="panel panel-success"> <div class=" panel-heading" style="margin-top:20px">متن پست مورد نظر شما</div> <div class="panel-body"> <h4 style="font-weight: bold;">@Model.Title</h4><p>@Html.Raw(Model.Content.Replace("\r", "\nbr />"))</p> </div> <div class="panel-footer"><p>پست شده توسط —برنامه نویسان — on @Model.CreateTime.ToString("MMMM dd, yyyy 'at' hh:mm tt")</p></div> </div> <p> Tagged under: @foreach (var tag in Model.Tags) { <span class="tag"><a href="~/blog/tag/@tag">@tag</a></span> if (tagIndex == Model.Tags.Count) { // In the end, write the edit hyperlink <br /> <span><a href="~/blog/edit/@Model.ID">Edit</a></span> } } </p>
همان طور که می بینید مدلی که به این ویو پاس داده ایم از نوع BlogPostModel است .و بعد آیتم های آن را به زیر نمایش داده ایم .
و در اخر متد Edit را پیاده سازی می کنیم .در این اکشن هم دوباره از داخل صفحه view خود اطلاعات را خوانده و یک شی از نوع BlogPostModel ایجاد می کنیم .بعد از این کار متد update از کلاس BlogManager را فراخوانی می کنیم .در داخل این متد متدهای دیگر کلاس BlogManager را به ترتیب ابتدا Delete(id); سپس Create(postJson); و نهایتا save(); را فراخوانی می کنیم .
صفحه view مربوط به این اکشن به صورت زیر است .
@{ ViewBag.Title = "Edit the post"; Layout = "~/Views/Shared/_Layout.cshtml"; var tags = string.Join(", ", ViewBag.Tags as List<string>); } <h2>Edit the post</h2> <form method="post"> <label>Title</label> <input type="text" name="title" class="form-control" value="@ViewBag.PostTitle" placeholder="The headline goes here..." /><br /> <label>Tags</label> <input type="text" name="tags" class="form-control" value="@tags" placeholder="Separate each tag using a comma ','." /><br /> <label>Content</label> <textarea name="content" class="form-control" style="height: 300px;" placeholder="What would you like to write?">@ViewBag.Content</textarea><br /> <input type="submit" style="width: auto; font-weight: 600;" value="Post" /><br /> </form>
اگر این ویو را اجرا کنیم شکل زیر را خواهیم دید
- ASP.net MVC
- 2k بازدید
- 8 تشکر