AI OnAI Off
Hi,
Why don't you use PageController for POST requests as viewcomponents are mainly used for display purpose.
I can see in error logs that Razor view file is not found /Views/Shared/SecureEmailBlock.cshtml, where have you placed your view file ?
OK. Try to start with a simple method for debugging purpose.
In below code replace "Hardcoded value" with the Id of a block you want to fetch and see if you get the relevant block
using EPiServer;
using EPiServer.Core;
using EPiServer.DataAbstraction;
using EPiServer.Logging;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json.Linq;
using System.Net.Mail;
using EPiServer.Web.Mvc;
using XXX.Cryptography;
using XXX.EpiServer.Business.Attributes;
using XXX.EpiServer.Business.Messaging;
using XXX.EpiServer.Helpers;
using XXX.EpiServer.Models.Blocks;
using XXX.EpiServer.Models.ViewModels;
using XXX.EpiServer.SpecializedProperties;
namespace XXX.EpiServer.Controllers
{
public class SecureEmailBlockController : Controller
{
private readonly IMessageSender _messageSender;
private readonly IContentRepository _contentRepository;
private readonly IContentTypeRepository _contentTypeRepository;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IConfiguration _configuration;
private readonly IContentLoader _contentLoader;
private static readonly EPiServer.Logging.ILogger _logger = LogManager.GetLogger();
public SecureEmailBlockController(IMessageSender messageSender, IContentRepository contentRepository, IContentTypeRepository contentTypeRepository, IConfiguration configuration, IHttpContextAccessor httpContextAccessor, IContentLoader contentLoader)
{
_messageSender = messageSender;
_contentRepository = contentRepository;
_contentTypeRepository = contentTypeRepository;
_configuration = configuration;
_httpContextAccessor = httpContextAccessor;
_contentLoader = contentLoader;
}
[HttpPost]
[Route("/api/public/{controller}/{action}")]
[ValidateAntiForgeryToken]
public IActionResult Index(SecureEmailViewModel viewModel)
{
var messageAttachmentsAreValid = true;
Attachment[] messageAttachments = null;
int decryptedId = Convert.ToInt32(AesHmac.SimpleDecryptWithPassword(viewModel.EncryptedBlockId, _configuration["EncryptionPassword"]));
var contentLink = new ContentReference(decryptedId);
//var currentBlock = _contentRepository.Get<SecureEmailBlock>(contentLink);
// For testing purpose only
var currentBlock = _repo.Get<BlockData>(new ContentReference("Hardcoded value"));
var secureEmailViewModel = GetSecureEmailViewModel(currentBlock, _contentRepository, _contentTypeRepository, viewModel);
if (!ModelState.IsValid)
{
HttpContext.Response.StatusCode = 400;
return View("SecureEmailBlock", secureEmailViewModel);
}
var selectedEmailRecipient = secureEmailViewModel.EmailRecipients.FirstOrDefault(recipient => recipient.FullName.Equals(viewModel.Recipient));
if (selectedEmailRecipient == null)
{
HttpContext.Response.StatusCode = 400;
return View("SecureEmailBlock", secureEmailViewModel);
}
_messageSender.SendMessage(new[] { new MailAddress(selectedEmailRecipient.EmailAddress) }, new MailAddress(viewModel.SenderEmailAddress, ($"{viewModel.SenderName}")),
viewModel.Subject, false, viewModel.Body, messageAttachments);
ModelState.Clear();
return View("SecureEmailBlock", secureEmailViewModel);
}
private SecureEmailViewModel GetSecureEmailViewModel(SecureEmailBlock currentContent, IContentRepository contentRepository, IContentTypeRepository contentTypeRepository, SecureEmailViewModel viewModel)
{
var recipients = Enumerable.Empty<EmailRecipient>();
var blockContent = (IContent)currentContent;
var referenceInformation = contentRepository.GetReferencesToContent(blockContent.ContentLink, false).FirstOrDefault();
if (referenceInformation != null)
{
var owner = contentRepository.Get<IContent>(referenceInformation.OwnerID);
var ownerType = contentTypeRepository.Load(owner.ContentTypeID);
var emailRecipientContentAreaAttribute = Attribute.GetCustomAttribute(ownerType.ModelType, typeof(EmailRecipientContentAreaAttribute)) as EmailRecipientContentAreaAttribute;
if (emailRecipientContentAreaAttribute != null)
{
var contactSearchItemContentAreaValue = emailRecipientContentAreaAttribute.ContactSearchItemContentArea;
var contactSearchItemContentArea = owner.Property[contactSearchItemContentAreaValue].Value as ContentArea;
var contactSearchItems = ContentHelpers.GetContentAreaBlocks<ContactSearchItemBlock>(contactSearchItemContentArea);
recipients = contactSearchItems.Select(contactSearchItem => new EmailRecipient
{
FirstName = contactSearchItem.FirstName,
MiddleName = contactSearchItem.MiddleName,
LastName = contactSearchItem.LastName,
EmailAddress = contactSearchItem.EmailAddress
});
}
}
if (currentContent.Recipients != null)
{
recipients = recipients.Concat(currentContent.Recipients);
}
var fullNamedRecipients = recipients.Select(recipient =>
{
recipient.FullName = string.IsNullOrWhiteSpace(recipient.MiddleName) ? $"{recipient.FirstName} {recipient.LastName}" : $"{recipient.FirstName} {recipient.MiddleName} {recipient.LastName}";
return recipient;
});
var sortedRecipients = (currentContent.SortRecipientsBy == "first, last, middle"
? fullNamedRecipients.OrderBy(recipient => recipient.FirstName)
.ThenBy(recipient => recipient.LastName)
.ThenBy(recipient => recipient.MiddleName)
: fullNamedRecipients.OrderBy(recipient => recipient.LastName)
.ThenBy(recipient => recipient.FirstName)
.ThenBy(recipient => recipient.MiddleName));
return new SecureEmailViewModel()
{
Recipient = Request.Query["recipient"],
Body = viewModel == null ? "" : viewModel.Body,
SendButtonText = currentContent.SendButtonText,
ResetButtonText = currentContent.ResetButtonText,
FormHeading = currentContent.Heading,
SenderName = viewModel == null ? "" : viewModel.SenderName,
SenderEmailAddress = viewModel == null ? "" : viewModel.SenderEmailAddress,
Subject = viewModel == null ? "" : viewModel.Subject,
EmailRecipients = sortedRecipients.ToList(),
SiteKey = currentContent.SiteKey,
SecretKey = currentContent.SecretKey,
ReCaptchaScoreThreshold = currentContent.ReCaptchaScoreThreshold
};
}
}
}
Hi,
I’m seeking clarification on converting Controllers to Components with the CMS upgrade from version 11 to 12.
One aspect of this conversion involves changing BlockControllers to BlockComponents.
While the GET call for the Block Component works and the block loads as expected, the POST call does not work. My application has a few POST requests that is made via AJAX.
I understand that ViewComponents are primarily used for display purposes. However, I’m unsure how to handle post-back calls
with ViewComponents, as using IActionResult within ViewComponents does not seem to work. BlockControllers are no longer valid in Optimizely12 .As a result, I ended up using both ViewComponents for display and an MVC Controller for handling post-back calls.
Here are the issues I’ve encountered with this approach
1- When the AJAX call is fired, the block is null on the POST call.
2- Next, I switched to using just a ViewModel in the Controller instead of the block.
The ViewModel has a content ID that I fetch in the GET call and pass in the form data from AJAX.This ID i include in VIewModel which gives me the block on POST method call as below:
However, this approach results in the block instance being different, causing model validation failures and issues with returning the view (return View("SecureEmailBlock", viewModel);).
System.InvalidOperationException: The view 'SecureEmailBlock' was not found. The following locations were searched:
Views/ElementBlocks/SecureEmailBlock.cshtml
/CmsDefault/Views/ElementBlocks/SecureEmailBlock.cshtml
~/Views/Shared/ElementBlocks/SecureEmailBlock.cshtml
/CmsDefault/Views/Shared/ElementBlocks/SecureEmailBlock.cshtml
/FormsViews/Views/ElementBlocks/SecureEmailBlock.cshtml
/CmsDefault/FormsViews/Views/ElementBlocks/SecureEmailBlock.cshtml
/Views/SecureEmailBlock/SecureEmailBlock.cshtml
/CmsDefault/Views/SecureEmailBlock/SecureEmailBlock.cshtml
/Views/Shared/SecureEmailBlock.cshtml
/CmsDefault/Views/Shared/SecureEmailBlock.cshtml
/Pages/Shared/SecureEmailBlock.cshtml
/CmsDefault/Pages/Shared/SecureEmailBlock.cshtml
/Util
/CmsDefault/Util
~/Views/Shared/Blocks/SecureEmailBlock.cshtml
/CmsDefault/Views/Shared/Blocks/SecureEmailBlock.cshtml
~/Views/Shared/Media/SecureEmailBlock.cshtml
/CmsDefault/Views/Shared/Media/SecureEmailBlock.cshtml
~/Views/Shared/PagePartials/SecureEmailBlock.cshtml
/CmsDefault/Views/Shared/PagePartials/SecureEmailBlock.cshtml
Here's the Folder structure that i have where the Block is placed:
Additonal info on the Modal State from 11 vs 12
Any advice or suggestions on how to handle POST calls with ViewComponents or alternative approaches to resolve these issues would be greatly appreciated.
Regards,
Farhin