Don't miss out Virtual Happy Hour this Friday (April 26).

Try our conversational search powered by Generative AI!

Problem with preview for custom content provider media

Vote:
 

Hi,

So I have a custom content provider that serves media of various kinds. This content provider is read only so its capabilities are "None". I have registered a custom content route like so:

    public class AssetContentRouteRegistration : IContentRouteRegister
    {
        private readonly ContentRootService _contentRootService;

        public AssetContentRouteRegistration(ContentRootService contentRootService)
        {
            _contentRootService = contentRootService;
        }

        public ContentRouteDefinition ContentRouteDefintion => new() {
            Name = "AssetContent",
            RouteRootResolver = _ => _contentRootService.Get(AssetContentProvider.PROVIDER_NAME),
            ContextMode = RouteContextMode.All,
            SupportMultiLanguage = false,
            SupportContentAssetUrl = true,
            StaticSegments = new[] { AssetContentProvider.PROVIDER_KEY },
        };
    }

Next I have a controller for the view of the file like so:

    [TemplateDescriptor(TemplateTypeCategory = TemplateTypeCategories.MvcPartialComponent, Inherited = true)]
    public class AssetContentController : AsyncPartialContentComponent<Models.Content.AssetContent>
    {
        protected override async Task<IViewComponentResult> InvokeComponentAsync(Models.Content.AssetContent currentContent)
        {
            return await Task.FromResult(View($"~/Views/xxxxx/AssetContent.cshtml", currentContent));
        }
    }

These above things work just fine, I can render my content as I want to using content areas and whatnot. If i enter the url of an asset it also get downloaded like it should, great!

Now, for the problem: I want to have a custom edit mode preview for this content, where it shows editors some metadata I have on the content. If I do nothing, I get a "preview is not available...", and I can donwload the file if I open the options menu and click "Download this file".

Now, I do as suggested and add a preview controller for this content type like so:

[TemplateDescriptor(
        Inherited = true,
        TemplateTypeCategory = TemplateTypeCategories.MvcController, //Required as controllers for blocks are registered as MvcPartialController by default
        Tags = new[] { RenderingTags.Preview, RenderingTags.Edit },
        AvailableWithoutTag = false)]
    public class AssetContentPreviewController : ActionControllerBase, IRenderTemplate<Models.Content.AssetContent>
    {
        public override void OnActionExecuting(ActionExecutingContext context)
        {
            base.OnActionExecuting(context);
        }

        public IActionResult Index(IContent currentContent)
        {
            var viewModel = new AssetContentPreviewViewModel(currentContent as Models.Content.AssetContent);
            return View($"~/Views/xxx/AssetContentPreview.cshtml", viewModel);
        }

        public IActionResult Preview(IContent currentContent)
        {
            var viewModel = new AssetContentPreviewViewModel(currentContent as Models.Content.AssetContent);
            return View($"~/Views/xxx/AssetContentPreview.cshtml", viewModel);
        }

        public IActionResult Edit(IContent currentContent)
        {
            var viewModel = new AssetContentPreviewViewModel(currentContent as Models.Content.AssetContent);
            return View($"~/Views/xxx/AssetContentPreview.cshtml", viewModel);
        }

        public IActionResult RenderContent(IContent currentContent)
        {
            var viewModel = new AssetContentPreviewViewModel(currentContent as Models.Content.AssetContent);
            return View($"~/Views/xxx/AssetContentPreview.cshtml", viewModel);
        }
    }

When I add the above controller, and click the "view" option from the asset pane hamburger menu for my content, I get a 404 for the content, also the "download this file" link stops working as it also 404s. I have tried various action methods as can be seen above, but If I attach a debugger, not even the "OnActionExecuting" method gets called. So simply adding the above controller will break the /EPiServer/CMS/Content/... URL for my content. I assume any call to my content with contextmode set to "edit" will break. Note: The "view" mode things still work just fine as before.

In my cms 11 project, there was this route registered, which worked (built before my time so cant say anything else about it), but the routing extensions is not avialable in CMS 12 anymore:

            RouteTable.Routes.MapContentRoute(
                "AssetContentEdit",
                GetCmsHomePath() + AssetContentProvider.PROVIDER_KEY + "/{language}/{medianodeedit}/{partial}/{action}",
                new { action = "index" },
                s => rootFolder.ContentLink);

I am suspecting that something is trying to route to the controller and fails to find the method it needs, but I dont know how to find out what method signature I need to add.

Any ideas?

#299211
Edited, Mar 29, 2023 18:07
Vote:
 

You can create a new IEndpointRoutingExtension and then regsiter in Statup

internal class ContentApiEndpointRoutingExtension : IEndpointRoutingExtension
    {
        private readonly Action<IEndpointConventionBuilder> _policyBuilder;

        public ContentApiEndpointRoutingExtension(Action<IEndpointConventionBuilder> policyBuilder = null)
        {
            _policyBuilder = policyBuilder;
        }

        public void MapEndpoints(IEndpointRouteBuilder endpointRouteBuilder)
        {
            var conventionBuilder = endpointRouteBuilder.MapControllers();
            _policyBuilder?.Invoke(conventionBuilder);
        }
    }
services.AddEndpointRoutingExtension<ContentApiEndpointRoutingExtension>();
#299215
Mar 29, 2023 18:54
Vote:
 

Thanks for the attempt, but that did no difference at all.

Do anyone else have any idea why the CMS fails to map a route from my content item to my controller with a TemplateDescriptor for it?

#299253
Mar 30, 2023 6:50
Vote:
 

I managed to work around it somewhat, and it actually made understanding how my content was routed much easier then all these archaic interface implementations, attributes, and mysterious extension methods:

I found talks about this interface in another thread: EPiServer.Core.Routing.IContentUrlGeneratorEvents 

I attached to this in my app startup class like so:

app.ApplicationServices.GetInstance<IContentUrlGeneratorEvents>().GeneratedUrl += GenerateAssetPreviewUrl;

Then my method that modifies the URL looks like so:

private static void GenerateAssetPreviewUrl(object sender, UrlGeneratorEventArgs e)
{
    if((e.Context.ContextMode == ContextMode.Preview || e.Context.ContextMode == ContextMode.Edit) && AssetContentMapping.IsAsset(e.Context.ContentLink)) {
        e.Context.Url = new EPiServer.UrlBuilder("/assets/preview/" + e.Context.ContentLink);
    }
}

Now my asset preview/edit links in epi all look like so: /assets/preview/[contentlink]/?epieditmode=True, and all I need is a controller with attributes [Route("asset")] and an action method with [Route("preview/{assetLink}")] and [Authorize(Roles = "CmsEditors,CmsAdmins")] to prevent anonymous access.

Only thing thats not working is the download link from the options dropdown in the edit interface, but I can live without that. The URL it generates is the correct view mode url, but I suspect there is a header added with ContextMode.Edit when clicking that link that causes it to 404.

#299257
Edited, Mar 30, 2023 8:30
This topic was created over six months ago and has been resolved. If you have a similar question, please create a new topic and refer to this one.
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.