Featured

Insert images into Tiny MCE editor using Asp.Net Web Api 2.2

Introduction

TinyMce is a nice WYSIWYG rich text editor for use in web applications and websites. It is small and very easy to setup. All you need to do is just download the javascript from the Tiny MCE downloads page and include in your project and you are ready to go. Basic setup and usage can be found on www.tinymce.com/documentation.

On one of our projects, which has a blog type of interface where users come in and post content on the platform, we decided to use Tiny-Mce as a rich text editor of choice. Our decision was motivated by the fact that all the text formatting and other options worked as we wanted. But when it comes to image handling , we encountered problems with the built in image plugin. It only works for images that already available on the web with a known location url. It does not allow you to upload your own images by default unless you set the editor to encode them as base64.

I literally spent hours going through the tiny-mce documentation just trying to figure out how to do this but without any success. If there is anyone who has successfully implemented this functionality in a different way, you can share it by posting your solution in the comments section below.

Basically in many of these scenarios, you would want your users to click the insert image button in the toolbar, browse to the image, in the pop up that shows, upload the image to a server and then insert the image into the content being edited. From there onward users can then use the image tools plugin to resize the image, crop the image and so on.

The solution I am putting forward here, is more like a hack than a conventional way of doing things. There are other universally accepted options you can use like Roxy Fileman, Plupload etc to achieve the same goal. But if you do not want the extra stuff (junk) that comes with these others, please continue reading. Below are steps you can follow to implement this functionality using Asp.Net Web Api for the server side uploading of images.

Server side setup

Start by creating a new Web Api project in Visual Studio, call the project tinymce-imageupload with no authentication as shown in the images below.

New Project
New Porject
Web Api Project
Web Api Project

Create web api controller

Once you are finished creating the web api project, add an empty Images web api controller and call it ImagesController.

Add web api controller
Add web api controller

In your images controller, add an action call it UploadImage() with a route attribute to api/images/upload and with the following code as the body. See code listing below.



      [Route("api/images/upload")]
        public async Task<IHttpActionResult> UploadImage()
        {
            var workingFolder = HttpContext.Current.Server.MapPath("~/images/" + DateTime.Today.ToString("ddMMyyyy"));
            if (!Directory.Exists(workingFolder))
            {
                Directory.CreateDirectory(workingFolder);
            }
            // Check if the request contains multipart/form-data.
            if (!Request.Content.IsMimeMultipartContent("form-data"))
            {
                return BadRequest("Unsupported media type");
            }
            try
            {
                var provider = new CustomMultipartFormDataStreamProvider(workingFolder);
                await Request.Content.ReadAsMultipartAsync(provider);

                var file = provider.FileData.First();
                var fileInfo = new FileInfo(file.LocalFileName);

                return Ok(new {location = $"/images/{DateTime.Today.ToString("ddMMyyyy")}/{fileInfo.Name}"});
            }
            catch (Exception ex)
            {
                return BadRequest(ex.GetBaseException().Message);
            }
        }

For the workingFolder, you can choose whatever location you want to use as your destination for the uploaded images. Here I am using a folder named with today’s date inside the images folder. This is merely an example on how you can structure a similar setup.

The first step in the action, checks whether the incoming request is from multi-part form, and if so, the section below it does most of the uploading work asynchronously using a MultipartFormDataStreamProvider, a custom one in this case.

Once the image is uploaded the action returns an Ok result with the location of the uploaded image. We will use this location value in the next section when we configure the client.

Client side setup

Since this is just a demo project, we will use the Index.cshtml view of the home controller for all our setup. Find the Index.cshtml view, in the View/Home folder and replace all the razor html in there with the following.


<h2>TinyMCE Image Upload with Asp.net Web Api</h2>

<div class="edit-container">
    <textarea id="tinymceContent" class="use-tinymce"></textarea>
    <button class="btn btn-success save">Save</button>
</div>

<input name="image" type="file" id="upload" onchange="" style="display: none;">

Basically we have a div with a textarea with id tinymceContent and a save button. We use the tinymceContent textarea as a our target for Tiny-Mce via the selector option. The save button does not do anything, it is just for display. Just below the div, there is a hidden file input control, which we will use for selecting files for upload.

Now to set up the tiny-mce editor, add a reference to the tiny mce javascript file and add the initial setup code below from the tiny-mce website as shown below.


@section scripts
{
    <script src="~/Scripts/tinymce/tinymce.js"></script>
    <script type="text/javascript">
        tinymce.init({
            selector: '#tinymceContent',
       
            plugins: [
                'advlist autolink lists link image charmap print preview anchor',
                'searchreplace visualblocks code fullscreen',
                'insertdatetime media table contextmenu paste code'
            ],
            toolbar:
                'insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image',
            resize: true,
            statusbar: true,
            extended_valid_elements: "span[!class]",
            visualblocks_default_state: true,
            file_picker_callback: function(callback, value, meta) {
                // Provide image and alt text for the image dialog
                if (meta.filetype === 'image') {
                    $('#upload').trigger('click');
                    $('#upload')
                        .on('change',
                            function() {
                                var file = this.files[0];
                                if (file) {
                                    var data = new FormData();
                                    data.append('file', file);
                                    $.ajax({
                                            url: '/api/images/upload',
                                            data: data,
                                            processData: false,
                                            contentType: false,
                                            async: false,
                                            type: 'POST'
                                        })
                                        .done(function(response) {
                                            callback(response.location);
                                        })
                                        .fail(function(jqXhr, textStatus) {
                                            console.log("Request failed: " + jqXhr.responseText + " --- " + textStatus);
                                            alert("Request failed: " + jqXhr.responseText + " --- " + textStatus);
                                        });
                                }
                            });
                }
            },
            file_picker_types: 'image',
            image_title: true
        });
    </script>
}

In this scripts section we add a reference to the Tiny-Mce library and below it we add the code to wire tiny-mce with the html. We provides basic options to the tiny-mce init function to get it up and running. All these options are standard except for the file_picker_callback callback function. This is where we do our magic.

We check if the incoming file type is an image and then we trigger a click event on our file input using JQuery. When the user selects a file, we upload the file to the server, via ajax, using a JQuery post method. Once the upload is finished and returns a response, we pass the response’s location value to our callback function. The callback function then sets value of the opened modal, source text box, to be this returned location value.

When the user clicks Ok on the opened modal/popup, the Tiny-Mce infrastructure will take over and then inserts the image into our content. This finishes the setup process and you can test it by inserting your own images into the editor and see if it works. If not download this demo project from Github and test again to make sure you understand the logic.

You can view the html generated by the editor, by going to the Tools toolbar button click it and then click view source.

Conclusion

In this article we have explored another way you can insert images into a tiny-mce WYSIWYG editor using Asp.net Web Api on the server side. You can also implement same type of functionality for other file types like videos (mp4, mpg, etc) and documents (pdfs, docs, etc). Code for the project can be found on Github