We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date
close icon

Upload images in Razor Pages project without controller - Rich Text Editor

Hi,

what's the recommended way to use a specific upload directory in Razor Pages projects, when using RTE?
I've seen an exmple https://ej2.syncfusion.com/aspnetcore/documentation/rich-text-editor/image/?no-cache=1. But this one uses controllers which is more related to the MVC pattern.
Can SaveURL also be used with Razor Pages when the handler method is in code behind?

E.g:
index.cshtml
<ejs-richtexteditor id="questionEditor" name="question">
<e-richtexteditor-insertimagesettings saveUrl="WHATTOUSEHERE" path="/.images/"></e-richtexteditor-insertimagesettings>
<e-richtexteditor-toolbarsettings items="@ViewData["ToolbarOptions"]"></e-richtexteditor-toolbarsettings>
<e-content-template>
</e-content-template>
</ejs-richtexteditor>
index.cshtml.cs
public async Task<IActionResult> OnPostUpload(List<IFormFile> UploadFiles)
{
...
}
Without providing any directy upload seems to work, at leas I get an URL within the img src tag. But can't find the image after uploading, so I thought it might be better to handle this manually

11 Replies

PO Prince Oliver Syncfusion Team May 7, 2019 10:46 AM UTC

Hello Felix,  

Thank you for contacting us. 

Query 1: “What's the recommended way to use a specific upload directory in Razor Pages projects, when using RTE? Can SaveURL also be used with Razor Pages when the handler method is in code behind?” 
  
Yes. You can achieve upload using the saveUrl property and handler from code behind of Razor pages. But you need to add the below configurations to achieve it. 

  1. Add AntiForgery token in startup file or web.config file.
  
[Startup.cs] 
public void ConfigureServices(IServiceCollection services) // Add below code 
{ 
    services.AddMvc().AddJsonOptions(x => 
    { 
        x.SerializerSettings.ContractResolver = new DefaultContractResolver(); 
    }); 
    services.AddAntiforgery(o => o.HeaderName = "xsrf-token"); 
} 
  
  1. Setup AntiForgery token in uploading event of Rich Text Editor image uploader through object using toolbarClick event. We have added ValidateAntiForgeryToken attribute on the server-side method when Rich Text Editor image uploading event triggered.

[Index.cshtml] 
@model IndexModel 
@Html.AntiForgeryToken() 
  
<ejs-richtexteditor id="rte" toolbarClick="toolbarClick"> 
    <e-richtexteditor-insertimagesettings saveUrl="/Index?handler=Save" path="../"> 
    </e-richtexteditor-insertimagesettings> 
    <e-content-template> 
        <p> 
            Users can format their content using standard toolbar commands. 
        </p> 
    </e-content-template> 
</ejs-richtexteditor> 
<script> 
    function toolbarClick(e) { // Triggered when you click the toolbar 
        if (e.item.id == "rte_toolbar_Image") { // Checked if image toolbar is clicked 
            var element = document.getElementById('rte_upload') // Image uploader element 
            element.ej2_instances[0].uploading = function upload(args) { // Added updating event on image uploader 
                args.currentRequest.setRequestHeader('XSRF-TOKEN', document.getElementsByName('__RequestVerificationToken')[0].value); 
            } 
        } 
    } 
</script> 
 
[Index.cshtml.cs] 
private IHostingEnvironment hostingEnv; 
public IndexModel(IHostingEnvironment env) 
{ 
    this.hostingEnv = env; 
} 
  
[AcceptVerbs("Post")] 
public IActionResult OnPostSave(IList<IFormFile> UploadFiles) // Triggered when uploading image 
{ 
    try 
    { 
        foreach (var file in UploadFiles) 
        { 
            if (UploadFiles != null) 
            { 
                var filename = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"'); 
                filename = hostingEnv.WebRootPath + $@"\{filename}"; 
                if (!System.IO.File.Exists(filename)) 
                { 
                    using (FileStream fs = System.IO.File.Create(filename)) 
                    { 
                        file.CopyTo(fs); 
                        fs.Flush(); 
                    } 
                } 
                else 
                { 
                    Response.Clear(); 
                    Response.StatusCode = 204; 
                    Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "File already exists."; 
                } 
            } 
        } 
    } 
    catch (Exception e) 
    { 
        Response.Clear(); 
        Response.ContentType = "application/json; charset=utf-8"; 
        Response.StatusCode = 204; 
        Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "No Content"; 
        Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = e.Message; 
    } 
    return Content(""); 
} 

We have attached the example application for your reference, please find it in the following location: 
  
Query 2: “I've seen an example https://ej2.syncfusion.com/aspnetcore/documentation/rich-text-editor/image/?no-cache=1. But this one uses controllers which is more related to the MVC pattern.” 
                                                                                                         
Currently, we have used MVC pattern for server-side actions in ASP.NET Core UG documentation. 
  
Query 3: “Without providing any directly upload seems to work, at least I get an URL within the img src tag. But can't find the image after uploading, so I thought it might be better to handle this manually” 
  
If you want to upload image without insertimagesettings property, you can upload the image directly and render it in editor. Suppose if you are going to configure insertimagesettings property, you need to specify path property. The editor considers the path property to render the image in editor. The saveUrl represents the URL to an action result method to save the image, and the path represents the destination folder in which the image must be saved. 
  
Let us know if you need any further assistance on this. 

Regards, 
Prince 



FL Flavio replied to Prince Oliver May 21, 2019 08:56 PM UTC

Hello Felix,  

Thank you for contacting us. 

Query 1: “What's the recommended way to use a specific upload directory in Razor Pages projects, when using RTE? Can SaveURL also be used with Razor Pages when the handler method is in code behind?” 
  
Yes. You can achieve upload using the saveUrl property and handler from code behind of Razor pages. But you need to add the below configurations to achieve it. 

  1. Add AntiForgery token in startup file or web.config file.
  
[Startup.cs] 
public void ConfigureServices(IServiceCollection services) // Add below code 
{ 
    services.AddMvc().AddJsonOptions(x => 
    { 
        x.SerializerSettings.ContractResolver = new DefaultContractResolver(); 
    }); 
    services.AddAntiforgery(o => o.HeaderName = "xsrf-token"); 
} 
  
  1. Setup AntiForgery token in uploading event of Rich Text Editor image uploader through object using toolbarClick event. We have added ValidateAntiForgeryToken attribute on the server-side method when Rich Text Editor image uploading event triggered.

[Index.cshtml] 
@model IndexModel 
@Html.AntiForgeryToken() 
  
<ejs-richtexteditor id="rte" toolbarClick="toolbarClick"> 
    <e-richtexteditor-insertimagesettings saveUrl="/Index?handler=Save" path="../"> 
    </e-richtexteditor-insertimagesettings> 
    <e-content-template> 
        <p> 
            Users can format their content using standard toolbar commands. 
        </p> 
    </e-content-template> 
</ejs-richtexteditor> 
<script> 
    function toolbarClick(e) { // Triggered when you click the toolbar 
        if (e.item.id == "rte_toolbar_Image") { // Checked if image toolbar is clicked 
            var element = document.getElementById('rte_upload') // Image uploader element 
            element.ej2_instances[0].uploading = function upload(args) { // Added updating event on image uploader 
                args.currentRequest.setRequestHeader('XSRF-TOKEN', document.getElementsByName('__RequestVerificationToken')[0].value); 
            } 
        } 
    } 
</script> 
 
[Index.cshtml.cs] 
private IHostingEnvironment hostingEnv; 
public IndexModel(IHostingEnvironment env) 
{ 
    this.hostingEnv = env; 
} 
  
[AcceptVerbs("Post")] 
public IActionResult OnPostSave(IList<IFormFile> UploadFiles) // Triggered when uploading image 
{ 
    try 
    { 
        foreach (var file in UploadFiles) 
        { 
            if (UploadFiles != null) 
            { 
                var filename = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"'); 
                filename = hostingEnv.WebRootPath + $@"\{filename}"; 
                if (!System.IO.File.Exists(filename)) 
                { 
                    using (FileStream fs = System.IO.File.Create(filename)) 
                    { 
                        file.CopyTo(fs); 
                        fs.Flush(); 
                    } 
                } 
                else 
                { 
                    Response.Clear(); 
                    Response.StatusCode = 204; 
                    Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "File already exists."; 
                } 
            } 
        } 
    } 
    catch (Exception e) 
    { 
        Response.Clear(); 
        Response.ContentType = "application/json; charset=utf-8"; 
        Response.StatusCode = 204; 
        Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = "No Content"; 
        Response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = e.Message; 
    } 
    return Content(""); 
} 

We have attached the example application for your reference, please find it in the following location: 
  
Query 2: “I've seen an example https://ej2.syncfusion.com/aspnetcore/documentation/rich-text-editor/image/?no-cache=1. But this one uses controllers which is more related to the MVC pattern.” 
                                                                                                         
Currently, we have used MVC pattern for server-side actions in ASP.NET Core UG documentation. 
  
Query 3: “Without providing any directly upload seems to work, at least I get an URL within the img src tag. But can't find the image after uploading, so I thought it might be better to handle this manually” 
  
If you want to upload image without insertimagesettings property, you can upload the image directly and render it in editor. Suppose if you are going to configure insertimagesettings property, you need to specify path property. The editor considers the path property to render the image in editor. The saveUrl represents the URL to an action result method to save the image, and the path represents the destination folder in which the image must be saved. 
  
Let us know if you need any further assistance on this. 

Regards, 
Prince 


Hello Support,
Could you please provide an example using RAZOR pages (not MVC) using your Rich Text Editor? In the example that I read, it is using "ViewBag.value" to hold the content of the editor, however "ViewBag.value" is not possible to be used in RAZOR.

Can you please advise?
Thanks,
Flavio


PO Prince Oliver Syncfusion Team May 22, 2019 09:19 AM UTC

Hello Flavio, 

Thank you for the update. 

You can use Model binding to pass value to the Value property in the RTE Control for the Razor pages. Please refer to the following code. 

[Index.cshtml] 
@model IndexModel 
 
<ejs-richtexteditor id="rte" toolbarClick="toolbarClick" value="@Model.RteValue"> 
    <e-richtexteditor-insertimagesettings saveUrl="/Index?handler=Save" path="../"></e-richtexteditor-insertimagesettings> 
</ejs-richtexteditor> 

[Index.cshtml.cs] 
public string RteValue { get; set; } 
public void OnGet() 
{ 
    RteValue = "<p>This is <b>RTE</b> Content</p>"; 
 
} 

We have attached the modified sample for your reference, please find it in the following location: 

Let us know if you need any further assistance on this. 

Regards, 
Prince 



FL Flavio May 22, 2019 06:54 PM UTC

Hi Prince,
Thank you for your response. 

Using your example, I could not save the RteValue OnPost(). Could you please let me know how can I get and save the RTE content using the OnPost() method in Razor pages?

Thanks,
Flavio


PO Prince Oliver Syncfusion Team May 23, 2019 05:54 AM UTC

Hello Flavio, 

Good day to you. 

To get the value on the OnPost method, you need to bind the model to the ejs-for in RTE control. Then the model value can be accessed from the form data during the form post. Kindly refer to the following code. 

[Index.cshtml] 
<form method="post"> 
    <ejs-richtexteditor ejs-for="RteValue" id="rte" toolbarClick="toolbarClick" > 
        <e-richtexteditor-insertimagesettings saveUrl="/Index?handler=Save" path="../"></e-richtexteditor-insertimagesettings> 
    </ejs-richtexteditor> 
    <br /> 
    <input type="submit" /> 
</form> 

[Index.cshtml.cs] 
public void OnPost(string RteValue) 
{ 
    var value = RteValue; 
 
} 


Let us know if you need any further assistance on this. 

Regards, 
Prince 



FE Felix May 27, 2019 05:59 PM UTC

Hi Prince,

it should also work with two instances on one site, right?
I've tried following but it's just working for the second RTE, the answer. My post method is pretty much the same as your's. But uploading an image in the first editor is not getting into the post method, seconds seems to work fine.
In Chrome I can see following error:

<div class="row">
<div class="col-lg-12">
<form method="post" asp-page-handler="post">
<div class="form-group">
<label asp-for="LearnContent.Question" class="control-label" ></label>
<ejs-richtexteditor id="questEditor" name="quest" toolbarClick="toolbarClickQuestion">
<e-richtexteditor-insertimagesettings saveUrl="Edit?handler=Save" path="../uploadedImages/"></e-richtexteditor-insertimagesettings>
<e-richtexteditor-toolbarsettings items="@ViewData["ToolbarOptions"]"></e-richtexteditor-toolbarsettings>
<e-content-template>
@Model.LearnContent.Question
</e-content-template>
</ejs-richtexteditor>
<script>
function toolbarClickQuestion(e) {
if (e.item.id == "questEditor_toolbar_Image") {
var element = document.getElementById('questEditor_upload')
element.ej2_instances[0].uploading = function upload(args) {
args.currentRequest.setRequestHeader('XSRF-TOKEN', document.getElementsByName('__RequestVerificationToken')[0].value);
}
}
}
</script>
</div>
<div class="form-group">
<label asp-for="LearnContent.Answer" class="control-label" ></label>
<ejs-richtexteditor id="answerEditor" name="answer" toolbarClick="toolbarClickAnswer">
<e-richtexteditor-insertimagesettings saveUrl="Edit?handler=Save" path="../uploadedImages/"></e-richtexteditor-insertimagesettings>
<e-richtexteditor-toolbarsettings items="@ViewData["ToolbarOptions"]"></e-richtexteditor-toolbarsettings>
<e-content-template>
@Model.LearnContent.Answer
</e-content-template>
</ejs-richtexteditor>
<script>
function toolbarClickAnswer(e) {
if (e.item.id == "answerEditor_toolbar_Image") {
var element = document.getElementById('answerEditor_upload')
element.ej2_instances[0].uploading = function upload(args) {
args.currentRequest.setRequestHeader('XSRF-TOKEN', document.getElementsByName('__RequestVerificationToken')[0].value);
}
}
}
</script>
</div>
<input type="hidden" asp-for="@Model.LearnContent.Id" name="id"/>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-default"/>
</div>
</form>
</div>
</div>


CI Christopher Issac Sunder K Syncfusion Team May 28, 2019 01:02 PM UTC

Hi Felix, 

We have checked customer reported query on onPost method. We have created two ejs-for RTE component and triggered on the onPost method when submit the button. The RTE value is got properly on the server side. You can get the uploader object on ‘this.imageModule.uploadObj’ instead of getting elements using toolbarClick event. Please find the below code. 
  
<form method="post"> 
    <div class="form-group"> 
        <ejs-richtexteditor ejs-for="RteValue" id="rte" toolbarClick="toolbarClick"> 
            <e-richtexteditor-insertimagesettings saveUrl="/Index?handler=Save" path="../"></e-richtexteditor-insertimagesettings> 
        </ejs-richtexteditor> 
    </div> 
    <div class="form-group"> 
        <ejs-richtexteditor ejs-for="RteValue1" id="rte1" toolbarClick="toolbarClick1"> 
            <e-richtexteditor-insertimagesettings saveUrl="/Index?handler=Save" path="../"></e-richtexteditor-insertimagesettings> 
        </ejs-richtexteditor> 
    </div> 
    <br /> 
    <input type="submit" /> 
</form> 
<script> 
 
    function toolbarClick(e) { 
        if (e.item.id == "rte_toolbar_Image") { 
            this.imageModule.uploadObj.uploading = function upload(args) { 
                args.currentRequest.setRequestHeader('XSRF-TOKEN', document.getElementsByName('__RequestVerificationToken')[0].value); 
            } 
        } 
    } 
    function toolbarClick1(e) { 
        if (e.item.id == "rte1_toolbar_Image") { 
            this.imageModule.uploadObj.uploading = function upload(args) { 
                ….. 
            } 
        } 
    } 
</script> 
  
  
Please get back to us if you require any further assistance. 

Thanks,
Christo 



FE Felix May 29, 2019 04:28 PM UTC

perfect, works like a charm!

Just two questions regarding RTE in Asp.Net Core left :
When I'm changing the filename in the OnPostSave method before saving the file, it gets proper stored. But the "callback" to the rte element will have the original file name.

And how to use it within a table/loop?

I've changed it from foreach loop to a for loop to ensure very RTE will have an unique Id and name. But that didn't the trick.
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.LearnContentList[0].Picture)
th>
<th>
@Html.DisplayNameFor(model => model.LearnContentList[0].Question)
th>
<th>
@Html.DisplayNameFor(model => model.LearnContentList[0].Answer)
th>
<th>th>
tr>
thead>
<tbody>
@for (int i = 0; i < Model.LearnContentList.Count; i++){
<tr>
<td>
@Html.DisplayFor(modelItem => modelItem.LearnContentList[i].Question)
td>
<td>
<ejs-richtexteditor id="@i" name="@i + editor" value="@Model.LearnContentList[i].Answer" >
<e-richtexteditor-insertimagesettings path="../uploadedImages/">e-richtexteditor-insertimagesettings>
<e-content-template>e-content-template>
ejs-richtexteditor>
td>
<td>
<a asp-page="./Edit" asp-route-id="@Model.LearnContentList[i].Id">Edita> |
<a asp-page="./Details" asp-route-id="@Model.LearnContentList[i].Id">Detailsa> |
<a asp-page="./Delete" asp-route-id="@Model.LearnContentList[i].Id">Deletea>
td>
tr>
}
}
tbody>
table>


PO Prince Oliver Syncfusion Team June 3, 2019 06:26 AM UTC

Hi Felix, 

Good day to you 

We checked the reported problem with getting the original file name in the callback function. Once you have renamed server end files, please update the renamed filename via response header.  You can get the Response header on the Success event header of RTE. Using event arguments, you can now update the renamed file name and insert image to RTE. Please refer to the following example 

[cshtml] 
 

[CS] 
 

We have attached the sample for your reference, please find it in the following location 

Let us know if you need any further assistance on this. 

Regards, 
Prince 



FE Felix June 5, 2019 05:42 PM UTC

Thx Prince,

very helpful.. as always. Have I missed this in the documentation? I'm still not able to find it there. Or is it so obvious that I'm the only one asking this? If so, sorry :).
Also, I found the issue regarding RTE within a loop. The id is does not allow to use a numeric only. Or it is used by another object already (can't find one but might be)
I'll changed it from
                <ejs-richtexteditor id="@i" name="@i + editor" value="@Model.LearnContentList[i].Answer" >
to
                <ejs-richtexteditor id="test+@i" value="@Model.LearnContentList[i].Answer" >
and had the same issue
but with:
                <ejs-richtexteditor id="test_@i" value="@Model.LearnContentList[i].Answer" >
it works perfectly.


PO Prince Oliver Syncfusion Team June 6, 2019 10:08 AM UTC

Hi Felix, 

Good day to you. 

This is not yet documented, so we have considered to document this in our end and will be updated in our upcoming future releases. According to the current html behavior of the html element, the id value must begin with a letter ([A-Za-z]) and can be followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_"). Please find the below stack overflow link on your reference. 

Hence, we suggest using id that contains at least one character. Let us know if you need any further assistance on this. 

Regards, 
Prince 


Loader.
Live Chat Icon For mobile
Up arrow icon