Using Summernote In ASP.NET MVC (Saving Image Files Separately)

Introduction 

As mentioned in my last post, I ended up creating my own blog engine inspired by the work press for this site. So I thought, "Why not write my first blog about the main challenge I faced while developing that engine and how I solved it?" By now you might have understood why I choose to write my own blog engine, yes, to blog further about it!
 
So the main component of any blog engine. It is the blog writing screen, which is basically a WYSIWYG HTML editor. For those who live under a rock and don't know the full form of WYSIWYG it's "What You See Is What You Get." The term is pretty old from the days of FrontPage editor old. For writing this screen, I went through the code of many .N based open source blog engines like miniblog, Dasblog, etc. Somehow, I was not very much comfortable with anything used in them, until I read this article where ''the author'' compared all JavaScript WYSIWYG editors and declared Summernote as the clear winner, so I decided to go with it. However, when I implemented Summernote in my blog application, I found an issue with it. Summernote actually embeds the images uploaded as content in base64 format inside the content, which made the content very heavy and unmanageable (if the content has many images like this blog) especially when we have to store the content in the database.
 
On looking into Summernote documentation I found that we can solve this problem by capturing the '''' event in jquery and use ajax to upload the image separately to a folder on the server and change the base64 image source to a URL. In this blog, I will explain the step by step procedure to do this, so let's get started.
 
Step 1
 
Create a new ASP.NET MVC project in Visual studio ( yes it's still ASP.Net, not Core ) by following the steps mentioned in this article.
 
Step 2
 
Create the BlogPost Model as per the following code in the Models folder.
  1. public class BlogPost  
  2. {  
  3.     /// <summary>  
  4.     /// For Title of the Note  
  5.     /// </summary>  
  6.     public string Title { getset; }  
  7.     /// <summary>  
  8.     /// To Save content of the Note which can be anything.  
  9.     /// </summary>  
  10.     [AllowHtml]  
  11.     public string Content { getset; }  
  12. }  
Step 3
 
Add a new controller named SummerNoteEx and Change the Index method to BlogEntry like following code.
  1. using System;  
  2. using System.IO;  
  3. using System.Web;  
  4. using System.Web.Mvc;  
  5. using TrWebBlogEx.Models;  
  6.   
  7. namespace TrWebBlogEx.Controllers  
  8. {  
  9.     public class SummerNoteExController : Controller  
  10.     {  
  11.         // GET: SummerNoteEx  
  12.         public ActionResult BlogEntry()  
  13.         {  
  14.             return View();  
  15.         }  
  16.     }   
  17. }  
Step 4
 
Right-click on BlogEntry Action Method and Click on Add View Option as shown in the following screenshot.
 
Using Summernote In ASP.NET MVC (With Saving Image File Separately)
 
Step 5
 
Download Summernote from this URL by clicking on the Download compiled button as shown in the following screenshot.
 
Using Summernote In ASP.NET MVC (With Saving Image File Separately)
 
Step 6
 
Extract the downloaded zip file, Rename the dist folder to Summernote and copy it in Scripts folder as shown in below Image.
 
Using Summernote In ASP.NET MVC (With Saving Image File Separately)
 
Step 7
 
Update the View as per following code.
  1. @model TrWebBlogEx.Models.BlogPost  
  2. @{  
  3.     ViewBag.Title = "Blog Entry";  
  4. }  
  5.   
  6. <link href="~/Scripts/summernote/summernote.css" rel="stylesheet" />  
  7. <script src="~/Scripts/summernote/summernote.js"></script>  
  8. <h2>Index</h2>  
  9. <div class="panel panel-primary">  
  10.     <div class="panel-heading panel-head">Add Note</div>  
  11.     <div class="panel-body">  
  12.         @using (Html.BeginForm())  
  13.         {  
  14.             <div class="form-horizontal">  
  15.                 <div class="form-group">  
  16.                     @Html.LabelFor(model => model.Title, new { @class = "col-lg-2 control-label" })  
  17.                     <div class="col-lg-9">  
  18.                         @Html.TextBoxFor(model => model.Title, new { @class = "form-control" })  
  19.                     </div>  
  20.                 </div>  
  21.                 <div class="form-group">  
  22.                     @Html.LabelFor(model => model.Content, new { @class = "col-lg-2 control-label" })  
  23.                     <div class="col-lg-9">  
  24.                         @Html.TextAreaFor(model => model.Content, new { @class = "form-control", @row = 5 })  
  25.                     </div>  
  26.                 </div>  
  27.                 <div class="form-group">  
  28.                     <div class="col-lg-9"></div>  
  29.                     <div class="col-lg-3">  
  30.                         <button class="btn btn-success" id="btnSubmit" type="submit">  
  31.                             Submit  
  32.                         </button>  
  33.                     </div>  
  34.                 </div>  
  35.             </div>  
  36.         }  
  37.     </div>  
  38. </div>  
  39. <script>  
  40.   
  41.     $(''#Content'').summernote({  
  42.         height: 300,                 // set editor height  
  43.         minHeight: null,             // set minimum height of editor  
  44.         maxHeight: null,             // set maximum height of editor  
  45.         focus: true  
  46.         }  
  47.     });      
  48. </script>  
Step 7
 
Update the Controller with following code, this will show the content back on the page
  1. [HttpPost]  
  2. public ActionResult BlogEntry(BlogPost aBlogPost)  
  3. {  
  4.     return View("ShowBlog", aBlogPost);  
  5. }     
Step 8
 
Now execute the application, click on Picture button like Below Image
 
Using Summernote In ASP.NET MVC (With Saving Image File Separately)
 
Step 9
 
Once the Image is uploaded , click on Code button like Below,
 
Using Summernote In ASP.NET MVC (With Saving Image File Separately)
 
It will show the following screen. See the Base64 code highlighted as shown below:
 
Using Summernote In ASP.NET MVC (With Saving Image File Separately)
 
To solve this problem update the JavaScript section of to BlogEntry View with following code:
  1. <script>  
  2.   
  3.     $(''#Content'').summernote({  
  4.         height: 300,                 // set editor height  
  5.         minHeight: null,             // set minimum height of editor  
  6.         maxHeight: null,             // set maximum height of editor  
  7.         focus: true,                  // set focus to editable area after initializing summernote  
  8.         callbacks: {  
  9.             onImageUpload: function (files) {  
  10.                 for (let i = 0; i < files.length; i++) {  
  11.                     UploadImage(files[i]);  
  12.                 }  
  13.             }  
  14.         }  
  15.     });  
  16.   
  17.     function UploadImage(file) {  
  18.         var url = ''@Url.Action("UploadFile""SummerNoteEx")'';  
  19.   
  20.         formData = new FormData();  
  21.         formData.append("aUploadedFile", file);  
  22.         $.ajax({  
  23.             type: ''POST'',  
  24.             url: url,  
  25.             data: formData,  
  26.             cache: false,  
  27.             contentType: false,  
  28.             processData: false,  
  29.             success: function (FileUrl) {  
  30.                // alert(FileUrl);  
  31.                 var imgNode = document.createElement(''img'');  
  32.                 imgNode.src = FileUrl;  
  33.                 $(''#Content'').summernote(''insertNode'', imgNode);  
  34.             },  
  35.             error: function (data) {  
  36.                 alert(data.responseText);  
  37.             }  
  38.         });  
  39.     }  
  40. </script>  
In the above code we are capturing the onImageUpload event of Summernote, reading the uploaded file, saving that file on server by using the UploadFile ActionMethod of controller (Below Code), getting back its server path and updating the path in Summernote to save the image URL instead of base64 data.
  1. [AcceptVerbs(HttpVerbs.Post)]  
  2.     public JsonResult UploadFile(HttpPostedFileBase aUploadedFile)  
  3.     {  
  4.         var vReturnImagePath = string.Empty;  
  5.         if (aUploadedFile.ContentLength > 0)  
  6.         {  
  7.             var vFileName = Path.GetFileNameWithoutExtension(aUploadedFile.FileName);  
  8.             var vExtension = Path.GetExtension(aUploadedFile.FileName);  
  9.   
  10.             string sImageName = vFileName + DateTime.Now.ToString("YYYYMMDDHHMMSS");  
  11.   
  12.             var vImageSavePath = Server.MapPath("/UpImages/") + sImageName + vExtension;  
  13.              //sImageName = sImageName + vExtension;  
  14.              vReturnImagePath =  "/UpImages/" + sImageName + vExtension;  
  15.             ViewBag.Msg = vImageSavePath;  
  16.             var path = vImageSavePath;  
  17.   
  18.             // Saving Image in Original Mode  
  19.             aUploadedFile.SaveAs(path);  
  20.             var vImageLength = new FileInfo(path).Length;  
  21.             //here to add Image Path to You Database ,  
  22.             TempData["message"] = string.Format("Image was Added Successfully");  
  23.         }  
  24.         return Json(Convert.ToString(vReturnImagePath), JsonRequestBehavior.AllowGet);  
  25.     }  
Now, when we execute the application and follow the Steps 8 and 9 again to view the code, we will see the Image URL in the code instead of Base64 data like in the following.
 
Using Summernote In ASP.NET MVC (With Saving Image File Separately)
 
This way, I made my blog content smaller to save in the database and also increased the image re-usability. This was how I created a blog entry screen for my blog engine, the code for this blog and all web blogs (which I may write in future) are consolidated into a single web application code uploaded here at Github.
 
Thanks for reading and until next time, keep smiling and progressing!