How to use Tinymce image upload with asp.net core ?
Ok here's the situation:
I want to store my images on the server which is uploaded by the editor and I want to insert the images into the text smoothly. How to do it ?
For this we need an API endpoint at the server to handle the file upload, we need one more endpoint to get the file list. And we need to configure the tinymce to upload the files to the upload endpoint and use our file to populate the image list drop down
The Tinymce has an excellent documentation, so my work will be easy, just need to read the documentation and I can do my work based on that.
First let's create the file upload endpoint, this is a simple .net core endpoint, we will get the file from the request, and save it to a designated media folder. The return value is important, tinymce expect a Json object with location property, if you fill it properly, you will get the uploaded file immedietly at the image upload dialog. Tinymce docs
If your return value does not contains the proper JSON (location property), you will get this:
For the first try, the New FileStream was not in a using scope, and sometimes i got a zero length file after the upload, so this is why i put into the using, to properly close the filestream, another possibility is to use the fs.Close(), but the doc said, dispose it properly instead of close.
[HttpPost]
[Route("upload")]
public IActionResult Upload()
{
var fil = Request.Form.Files[0];
using (var fs = new FileStream(_hosting.WebRootPath + $"\\{blogMediaFolder}\\" + fil.FileName, FileMode.Create))
{
fil.CopyTo(fs);
}
return Ok(new { location = $"/{blogMediaFolder}/" + fil.FileName });
}
Another endpoint need for the "list of media files", tinymce will use that endpoint to prefill the dropdown image listbox with images availabe at the server:
This is another very simple endpoint, just get the folder contents, and return with the proper Json object, the return structure from the Tinymce documentation
[HttpGet]
[Route("filelist")]
public IActionResult Filelist()
{
var files = Directory.GetFiles(_hosting.WebRootPath + $"\\{blogMediaFolder}");
var res = new List();
foreach (var item in files)
{
res.Add(new Fileinf() { title = Path.GetFileName(item), value = $"/{blogMediaFolder}/" + Path.GetFileName(item) });
}
return Json(res);
}
Atfter the server side done, let's jump to configure the editor at the client side, there are many nice options, let's see what we need to get the best editor feeling. Here's final config
<script>
tinymce.init({
selector: '#content',
plugins: "lists,code,image,link",
toolbar: "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | table | fontsizeselect code image link",
max_height: 700,
max_width: 900,
min_height: 600,
min_width: 500,
entity_encoding: "raw",
file_picker_types: 'file image media',
images_upload_url: '/upload', // this is the upload target URL - our first endpoint
automatic_uploads: true,
image_list: '/filelist', // the list of the media files, our second endpoint
image_caption: true,
image_advtab: true,
image_title: true,
relative_urls: false, // no relative url, it will be full url, but the next option will remove the host part, so the final url will be: /images/picture.jpg
remove_script_host: true, // remove the protocol and host part from http://www.sitename.com , only if relative_urls: false
image_class_list: [
{ title: 'None', value: '' },
{ title: 'img-fluid rounded', value: 'img-fluid rounded' },
{ title: 'img-fluid', value: 'img-fluid' },
],
});
</script>
The key config items:
images_upload_url
Set the file upload target API Endpoint url here, this endpoint will get the uploaded file (look at my API endpoint 1)
image_list
Set the API Endpoint url here, this endpoint will give the editor the list of files (look at my API endpoint 2)
The relative_urls, and the remove_script_host option usefull to set the proper URL which is inserted into the html source, feel free to play with it, for me the relative url is not suitable, because the document viewat at two different URL (different deep), so one of them will fail because of the bad relative resolving like "../../Media/Image1.Jpg"