using System; using System.Collections.Specialized; using Microsoft.AspNetCore.Http; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Logging; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Web.Common.Controllers; using Umbraco.Web.Routing; using Umbraco.Web.Website.ActionResults; namespace Umbraco.Web.Website.Controllers { /// /// Provides a base class for front-end add-in controllers. /// // TODO: Migrate MergeModelStateToChildAction and MergeParentContextViewData action filters // [MergeModelStateToChildAction] // [MergeParentContextViewData] public abstract class SurfaceController : PluginController { protected SurfaceController(IUmbracoContextAccessor umbracoContextAccessor, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IPublishedUrlProvider publishedUrlProvider) : base(umbracoContextAccessor, databaseFactory, services, appCaches, profilingLogger) { PublishedUrlProvider = publishedUrlProvider; } protected IPublishedUrlProvider PublishedUrlProvider { get; } /// /// Gets the current page. /// protected virtual IPublishedContent CurrentPage { get { var routeDefAttempt = TryGetRouteDefinitionFromAncestorViewContexts(); if (routeDefAttempt.Success == false) throw routeDefAttempt.Exception; var routeDef = routeDefAttempt.Result; return routeDef.PublishedRequest.PublishedContent; } } /// /// Redirects to the Umbraco page with the given id /// /// /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid contentKey) { return new RedirectToUmbracoPageResult(contentKey, PublishedUrlProvider, UmbracoContextAccessor); } /// /// Redirects to the Umbraco page with the given id and passes provided querystring /// /// /// /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(Guid contentKey, QueryString queryString) { return new RedirectToUmbracoPageResult(contentKey, queryString, PublishedUrlProvider, UmbracoContextAccessor); } /// /// Redirects to the Umbraco page with the given published content /// /// /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent) { return new RedirectToUmbracoPageResult(publishedContent, PublishedUrlProvider, UmbracoContextAccessor); } /// /// Redirects to the Umbraco page with the given published content and passes provided querystring /// /// /// /// protected RedirectToUmbracoPageResult RedirectToUmbracoPage(IPublishedContent publishedContent, QueryString queryString) { return new RedirectToUmbracoPageResult(publishedContent, queryString, PublishedUrlProvider, UmbracoContextAccessor); } /// /// Redirects to the currently rendered Umbraco page /// /// protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage() { return new RedirectToUmbracoPageResult(CurrentPage, PublishedUrlProvider, UmbracoContextAccessor); } /// /// Redirects to the currently rendered Umbraco page and passes provided querystring /// /// /// protected RedirectToUmbracoPageResult RedirectToCurrentUmbracoPage(QueryString queryString) { return new RedirectToUmbracoPageResult(CurrentPage, queryString, PublishedUrlProvider, UmbracoContextAccessor); } /// /// Redirects to the currently rendered Umbraco URL /// /// /// /// This is useful if you need to redirect /// to the current page but the current page is actually a rewritten URL normally done with something like /// Server.Transfer.* /// protected RedirectToUmbracoUrlResult RedirectToCurrentUmbracoUrl() { return new RedirectToUmbracoUrlResult(UmbracoContext); } /// /// Returns the currently rendered Umbraco page /// /// protected UmbracoPageResult CurrentUmbracoPage() { return new UmbracoPageResult(ProfilingLogger); } /// /// we need to recursively find the route definition based on the parent view context /// /// private Attempt TryGetRouteDefinitionFromAncestorViewContexts() { var currentContext = ControllerContext; while (!(currentContext is null)) { var currentRouteData = currentContext.RouteData; if (currentRouteData.DataTokens.ContainsKey(Core.Constants.Web.UmbracoRouteDefinitionDataToken)) return Attempt.Succeed((RouteDefinition)currentRouteData.DataTokens[Core.Constants.Web.UmbracoRouteDefinitionDataToken]); } return Attempt.Fail( new InvalidOperationException("Cannot find the Umbraco route definition in the route values, the request must be made in the context of an Umbraco request")); } } }