Hi @JohanReitsma ,
I did a quick Umbraco 17 setup to see how this can be done. I was able to do few things which might help you in some bits, Please adjust the code as per your needs:
This is the controller which we need. The code is getting the GUID of content node, compares the visitor’s IP again the config which we have. If don’t match, it blocks them. It hits the Umbraco cache using GetById(true, key). The true parameter is the trick—it forces Umbraco to ignore the live site and grab the unpublished draft. It wraps that draft data into a standard ContentModel and hands it off to the Home.cshtml. This makes the draft render exactly like the real page without breaking the views. :
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Web;
namespace MyUmbracoProjectTest1.Controllers
{
[Route("share-preview")]
public class SharePreviewController : Controller
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IConfiguration _configuration;
public SharePreviewController(IUmbracoContextAccessor umbracoContextAccessor, IConfiguration configuration)
{
_umbracoContextAccessor = umbracoContextAccessor;
_configuration = configuration;
}
// Changed to expect a GUID in the URL
[HttpGet("{key:guid}")]
public IActionResult Index(Guid key)
{
var userIp = HttpContext.Connection.RemoteIpAddress?.ToString();
var allowedIp = _configuration["SharePreview:AllowedIp"];
if (string.IsNullOrEmpty(allowedIp) || userIp != allowedIp)
{
return Unauthorized("IP address not authorized for preview.");
}
if (_umbracoContextAccessor.TryGetUmbracoContext(out var context))
{
// Pass 'true' (for preview) and the GUID Key
var draftContent = context.Content?.GetById(true, key);
if (draftContent != null && draftContent.TemplateId > 0)
{
// Wrap the IPublishedContent so ModelsBuilder views don't break
return View(draftContent.GetTemplateAlias(), new ContentModel(draftContent));
}
}
return NotFound("Content not found or no template assigned.");
}
}
}
This is the view code for Home doc type:
@using Umbraco.Cms.Web.Common.PublishedModels;
@inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage<ContentModels.Home>
@using ContentModels = Umbraco.Cms.Web.Common.PublishedModels;
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Preview Test - @Model.Name</title>
</head>
<body style="font-family: sans-serif; padding: 40px;">
<h1>Node Name: @Model.Name</h1>
<div style="border: 2px dashed red; padding: 20px; margin-top: 20px;">
<h3 style="margin-top: 0;">Output from 'test' property:</h3>
@* This renders your Rich Text Editor content safely *@
@Html.Raw(Model.Value("test"))
</div>
</body>
</html>
And a small block on the appsettings to allow the IPs:
{
"$schema": "appsettings-schema.json",
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information",
"System": "Warning"
}
}
},
"Umbraco": {
"CMS": {
"Global": {
"Id": "12df46b9-8ad9-4f36-b3ee-d157fe3c1a12"
},
"Content": {
"AllowEditInvariantFromNonDefault": true,
"ContentVersionCleanupPolicy": {
"EnableCleanup": true
}
},
"Unattended": {
"UpgradeUnattended": true
},
"Security": {
"AllowConcurrentLogins": false
},
"Imaging": {
"HMACSecretKey": "iDj1Z7dWWqQv9wv0poMFOq5dABDd6zCLUgZE/TMdkO4ReCwEBNUHpVH9TADozMv87kDQxanQvAy646Hpir2Tbg=="
}
}
},
"ConnectionStrings": {
"umbracoDbDSN": "Data Source=|DataDirectory|/Umbraco.sqlite.db;Cache=Shared;Foreign Keys=True;Pooling=True",
"umbracoDbDSN_ProviderName": "Microsoft.Data.Sqlite"
},
"SharePreview": {
"AllowedIp": "::1"
}
}
Created a small doc type with just a RTE:
Added this first and do a save and publish:
Which gave me this. This is the published version:
After that added this and only saved it (No publish):
Now tried the SharePreview to see the draft preview on the incognito mode. Got this as my IP address is not in the appsettings:
Then added my IP and tried again and got this:
Hope it helps!