Using Summernote in ASP.Net MVC (with Saving image file separately)

As mentioned in my last post, I have created my own blog engine inspired from 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 smile yes to blog further about it wink

So the main component of any blog engine 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. So for writing this screen I went through the code of  many .Net based open source blog engines like miniblog , Dasblog etc but somehow I was not very much comfortable with any one 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 which is 

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) specially when we have to store the content in database.

On looking into summernote documentation I found that we can solved this problem by capturing the '''' event in jquery and use ajax to upload the image speratly to a folder on server and change the base64 image source to 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 following code in Models folder.

    public class BlogPost
    {
        /// <summary>
        /// For Title of the Note
        /// </summary>
        public string Title { get; set; }
        /// <summary>
        /// To Save content of the Note which can be anything.
        /// </summary>
        [AllowHtml]
        public string Content { get; set; }
    }

Step-3: Add a new controller named SummerNoteEx and Change the Index method to BlogEntry like following code.

using System;
using System.IO;
using System.Web;
using System.Web.Mvc;
using TrWebBlogEx.Models;

namespace TrWebBlogEx.Controllers
{
    public class SummerNoteExController : Controller
    {
        // GET: SummerNoteEx
        public ActionResult BlogEntry()
        {
            return View();
        }
    } 
}

Step-4: Right click on BlogEntry Action Method and Click on Add View Option as shown in following screenshot.

Step-5: Download summernote from this URL by clicking on Download compiled button as shown in following screenshot.

Step-6: Extract the downloaded zip file, Rename the dist folder to summernote and copy it in Scripts folder as shown in below Image.

Step-7: Update the View as per following code.

@model TrWebBlogEx.Models.BlogPost
@{
    ViewBag.Title = "Blog Entry";
}

<link href="~/Scripts/summernote/summernote.css" rel="stylesheet" />
<script src="~/Scripts/summernote/summernote.js"></script>
<h2>Index</h2>
<div class="panel panel-primary">
    <div class="panel-heading panel-head">Add Note</div>
    <div class="panel-body">
        @using (Html.BeginForm())
        {
            <div class="form-horizontal">
                <div class="form-group">
                    @Html.LabelFor(model => model.Title, new { @class = "col-lg-2 control-label" })
                    <div class="col-lg-9">
                        @Html.TextBoxFor(model => model.Title, new { @class = "form-control" })
                    </div>
                </div>
                <div class="form-group">
                    @Html.LabelFor(model => model.Content, new { @class = "col-lg-2 control-label" })
                    <div class="col-lg-9">
                        @Html.TextAreaFor(model => model.Content, new { @class = "form-control", @row = 5 })
                    </div>
                </div>
                <div class="form-group">
                    <div class="col-lg-9"></div>
                    <div class="col-lg-3">
                        <button class="btn btn-success" id="btnSubmit" type="submit">
                            Submit
                        </button>
                    </div>
                </div>
            </div>
        }
    </div>
</div>
<script>


    $(''#Content'').summernote({
        height: 300,                 // set editor height
        minHeight: null,             // set minimum height of editor
        maxHeight: null,             // set maximum height of editor
        focus: true
        }
    });    
</script>

Step-7: Update the Controller with following code, this will show the content back on the page

        [HttpPost]
        public ActionResult BlogEntry(BlogPost aBlogPost)
        {
            return View("ShowBlog", aBlogPost);
        }       

Step-8: Now execute the application, click on Picture button like Below Image

Step-9: Once the Image is uploaded , click on Code button like Below

It will show following screen see the Base64 code highlighted as shown below

To solve this problem update the JavaScript section of to BlogEntry View with following code:

<script>


    $(''#Content'').summernote({
        height: 300,                 // set editor height
        minHeight: null,             // set minimum height of editor
        maxHeight: null,             // set maximum height of editor
        focus: true,                  // set focus to editable area after initializing summernote
        callbacks: {
            onImageUpload: function (files) {
                for (let i = 0; i < files.length; i++) {
                    UploadImage(files[i]);
                }
            }
        }
    });

    function UploadImage(file) {
        var url = ''@Url.Action("UploadFile", "SummerNoteEx")'';

        formData = new FormData();
        formData.append("aUploadedFile", file);
        $.ajax({
            type: ''POST'',
            url: url,
            data: formData,
            cache: false,
            contentType: false,
            processData: false,
            success: function (FileUrl) {
               // alert(FileUrl);
                var imgNode = document.createElement(''img'');
                imgNode.src = FileUrl;
                $(''#Content'').summernote(''insertNode'', imgNode);
            },
            error: function (data) {
                alert(data.responseText);
            }
        });
    }
</script>

In 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 it''s server path and updating the path in summernote to save the image URL instead of base64 data.

        [AcceptVerbs(HttpVerbs.Post)]
        public JsonResult UploadFile(HttpPostedFileBase aUploadedFile)
        {
            var vReturnImagePath = string.Empty;
            if (aUploadedFile.ContentLength > 0)
            {
                var vFileName = Path.GetFileNameWithoutExtension(aUploadedFile.FileName);
                var vExtension = Path.GetExtension(aUploadedFile.FileName);

                string sImageName = vFileName + DateTime.Now.ToString("YYYYMMDDHHMMSS");

                var vImageSavePath = Server.MapPath("/UpImages/") + sImageName + vExtension;
                 //sImageName = sImageName + vExtension;
                 vReturnImagePath =  "/UpImages/" + sImageName + vExtension;
                ViewBag.Msg = vImageSavePath;
                var path = vImageSavePath;

                // Saving Image in Original Mode
                aUploadedFile.SaveAs(path);
                var vImageLength = new FileInfo(path).Length;
                //here to add Image Path to You Database ,
                TempData["message"] = string.Format("Image was Added Successfully");
            }
            return Json(Convert.ToString(vReturnImagePath), JsonRequestBehavior.AllowGet);
        }

Now when we execute the application and follow the Steps 8 & 9 again to view the code,  we will see the Image URL in the code instead of Base64 data like following.

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 blog entry screen for my blog engine, the code for this blog and all web blogs (which I may write in future) is consolidated into a single web application code uploaded here at Github.

 

Thanks for reading and until next time, Keep Smiling and Progressing

S Ravi Kumar

Ravi is an experienced IT professional with over 15 years of IT services experience using Microsoft technologies including like ASP.Net, C#, .Net Core, Xamarin.Forms, Azure etc.

Add a new comment

 

Comments