Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,57 +1,54 @@
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Web;

namespace Umbraco.Cms.Web.Common.ActionsResults
namespace Umbraco.Cms.Web.Common.ActionsResults;

/// <summary>
/// Returns the Umbraco not found result
/// </summary>
public class PublishedContentNotFoundResult : IActionResult
{
private readonly string? _message;
private readonly IUmbracoContext _umbracoContext;

/// <summary>
/// Returns the Umbraco not found result
/// Initializes a new instance of the <see cref="PublishedContentNotFoundResult" /> class.
/// </summary>
public class PublishedContentNotFoundResult : IActionResult
public PublishedContentNotFoundResult(IUmbracoContext umbracoContext, string? message = null)
{
_umbracoContext = umbracoContext;
_message = message;
}

/// <inheritdoc />
public async Task ExecuteResultAsync(ActionContext context)
{
private readonly IUmbracoContext _umbracoContext;
private readonly string? _message;
HttpResponse response = context.HttpContext.Response;

/// <summary>
/// Initializes a new instance of the <see cref="PublishedContentNotFoundResult"/> class.
/// </summary>
public PublishedContentNotFoundResult(IUmbracoContext umbracoContext, string? message = null)
response.Clear();

response.StatusCode = StatusCodes.Status404NotFound;

IPublishedRequest? frequest = _umbracoContext.PublishedRequest;
var reason = "Cannot render the page at URL '{0}'.";
if (frequest?.HasPublishedContent() == false)
{
_umbracoContext = umbracoContext;
_message = message;
reason = "No umbraco document matches the URL '{0}'.";
}

/// <inheritdoc/>
public async Task ExecuteResultAsync(ActionContext context)
else if (frequest?.HasTemplate() == false)
{
HttpResponse response = context.HttpContext.Response;

response.Clear();

response.StatusCode = StatusCodes.Status404NotFound;

IPublishedRequest? frequest = _umbracoContext.PublishedRequest;
var reason = "Cannot render the page at URL '{0}'.";
if (frequest?.HasPublishedContent() == false)
{
reason = "No umbraco document matches the URL '{0}'.";
}
else if (frequest?.HasTemplate() == false)
{
reason = "No template exists to render the document at URL '{0}'.";
}

var viewResult = new ViewResult
{
ViewName = "~/umbraco/UmbracoWebsite/NotFound.cshtml"
};
context.HttpContext.Items.Add("reason", string.Format(reason, WebUtility.HtmlEncode(_umbracoContext.OriginalRequestUrl.PathAndQuery)));
context.HttpContext.Items.Add("message", _message);

await viewResult.ExecuteResultAsync(context);
reason = "No template exists to render the document at URL '{0}'.";
}

var viewResult = new ViewResult { ViewName = "~/umbraco/UmbracoWebsite/NotFound.cshtml" };
context.HttpContext.Items.Add(
"reason",
string.Format(reason, WebUtility.HtmlEncode(_umbracoContext.OriginalRequestUrl.PathAndQuery)));
context.HttpContext.Items.Add("message", _message);

await viewResult.ExecuteResultAsync(context);
}
}
15 changes: 6 additions & 9 deletions src/Umbraco.Web.Common/ActionsResults/UmbracoProblemResult.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
using System.Net;
using Microsoft.AspNetCore.Mvc;

namespace Umbraco.Cms.Web.Common.ActionsResults
namespace Umbraco.Cms.Web.Common.ActionsResults;

// TODO: What is the purpose of this? Doesn't seem to add any benefit
public class UmbracoProblemResult : ObjectResult
{
// TODO: What is the purpose of this? Doesn't seem to add any benefit
public class UmbracoProblemResult : ObjectResult
{
public UmbracoProblemResult(string message, HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError) : base(new {Message = message})
{
StatusCode = (int) httpStatusCode;
}
}
public UmbracoProblemResult(string message, HttpStatusCode httpStatusCode = HttpStatusCode.InternalServerError)
: base(new { Message = message }) => StatusCode = (int)httpStatusCode;
}
99 changes: 48 additions & 51 deletions src/Umbraco.Web.Common/ActionsResults/ValidationErrorResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,64 +5,61 @@
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Extensions;

namespace Umbraco.Cms.Web.Common.ActionsResults
{
// TODO: This should probably follow the same conventions as in aspnet core and use ProblemDetails
// and ProblemDetails factory. See https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/ControllerBase.cs#L1977
// ProblemDetails is explicitly checked for in the application model.
// In our base class UmbracoAuthorizedApiController the logic is there to create a ProblemDetails.
// However, to do this will require changing how angular deals with errors since the response will
// probably be different. Would just be better to follow the aspnet patterns.
namespace Umbraco.Cms.Web.Common.ActionsResults;

/// <summary>
/// Custom result to return a validation error message with required headers
/// </summary>
/// <remarks>
/// The default status code is a 400 http response
/// </remarks>
public class ValidationErrorResult : ObjectResult
// TODO: This should probably follow the same conventions as in aspnet core and use ProblemDetails
// and ProblemDetails factory. See https://github.com/dotnet/aspnetcore/blob/main/src/Mvc/Mvc.Core/src/ControllerBase.cs#L1977
// ProblemDetails is explicitly checked for in the application model.
// In our base class UmbracoAuthorizedApiController the logic is there to create a ProblemDetails.
// However, to do this will require changing how angular deals with errors since the response will
// probably be different. Would just be better to follow the aspnet patterns.

/// <summary>
/// Custom result to return a validation error message with required headers
/// </summary>
/// <remarks>
/// The default status code is a 400 http response
/// </remarks>
public class ValidationErrorResult : ObjectResult
{
public ValidationErrorResult(ModelStateDictionary modelState)
: this(new SimpleValidationModel(modelState.ToErrorDictionary()))
{
/// <summary>
/// Typically this should not be used and just use the ValidationProblem method on the base controller class.
/// </summary>
/// <param name="errorMessage"></param>
/// <returns></returns>
public static ValidationErrorResult CreateNotificationValidationErrorResult(string errorMessage)
{
var notificationModel = new SimpleNotificationModel
{
Message = errorMessage
};
notificationModel.AddErrorNotification(errorMessage, string.Empty);
return new ValidationErrorResult(notificationModel);
}
}

public ValidationErrorResult(ModelStateDictionary modelState)
: this(new SimpleValidationModel(modelState.ToErrorDictionary())) { }
public ValidationErrorResult(object? value, int statusCode)
: base(value) => StatusCode = statusCode;

public ValidationErrorResult(object? value, int statusCode) : base(value)
{
StatusCode = statusCode;
}
public ValidationErrorResult(object? value)
: this(value, StatusCodes.Status400BadRequest)
{
}

public ValidationErrorResult(object? value) : this(value, StatusCodes.Status400BadRequest)
{
}
// TODO: Like here, shouldn't we use ProblemDetails?
public ValidationErrorResult(string errorMessage, int statusCode)
: base(new { Message = errorMessage }) =>
StatusCode = statusCode;

// TODO: Like here, shouldn't we use ProblemDetails?
public ValidationErrorResult(string errorMessage, int statusCode) : base(new { Message = errorMessage })
{
StatusCode = statusCode;
}
public ValidationErrorResult(string errorMessage)
: this(errorMessage, StatusCodes.Status400BadRequest)
{
}

public ValidationErrorResult(string errorMessage) : this(errorMessage, StatusCodes.Status400BadRequest)
{
}
/// <summary>
/// Typically this should not be used and just use the ValidationProblem method on the base controller class.
/// </summary>
/// <param name="errorMessage"></param>
/// <returns></returns>
public static ValidationErrorResult CreateNotificationValidationErrorResult(string errorMessage)
{
var notificationModel = new SimpleNotificationModel { Message = errorMessage };
notificationModel.AddErrorNotification(errorMessage, string.Empty);
return new ValidationErrorResult(notificationModel);
}

public override void OnFormatting(ActionContext context)
{
base.OnFormatting(context);
context.HttpContext.Response.Headers["X-Status-Reason"] = "Validation failed";
}
public override void OnFormatting(ActionContext context)
{
base.OnFormatting(context);
context.HttpContext.Response.Headers["X-Status-Reason"] = "Validation failed";
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
using System;
namespace Umbraco.Cms.Web.Common.ApplicationBuilder;

namespace Umbraco.Cms.Web.Common.ApplicationBuilder
public interface IUmbracoApplicationBuilder
{
public interface IUmbracoApplicationBuilder
{
/// <summary>
/// EXPERT call to replace the middlewares that Umbraco installs by default with a completely custom pipeline.
/// </summary>
/// <param name="configureUmbracoMiddleware"></param>
/// <returns></returns>
IUmbracoEndpointBuilder WithCustomMiddleware(Action<IUmbracoApplicationBuilderContext> configureUmbracoMiddleware);
/// <summary>
/// EXPERT call to replace the middlewares that Umbraco installs by default with a completely custom pipeline.
/// </summary>
/// <param name="configureUmbracoMiddleware"></param>
/// <returns></returns>
IUmbracoEndpointBuilder WithCustomMiddleware(Action<IUmbracoApplicationBuilderContext> configureUmbracoMiddleware);

/// <summary>
/// Called to include default middleware to run umbraco.
/// </summary>
/// <param name="configureUmbracoMiddleware"></param>
/// <returns></returns>
IUmbracoEndpointBuilder WithMiddleware(Action<IUmbracoApplicationBuilderContext> configureUmbracoMiddleware);
}
/// <summary>
/// Called to include default middleware to run umbraco.
/// </summary>
/// <param name="configureUmbracoMiddleware"></param>
/// <returns></returns>
IUmbracoEndpointBuilder WithMiddleware(Action<IUmbracoApplicationBuilderContext> configureUmbracoMiddleware);
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
using System;
namespace Umbraco.Cms.Web.Common.ApplicationBuilder;

namespace Umbraco.Cms.Web.Common.ApplicationBuilder
/// <summary>
/// The context object used during
/// </summary>
public interface IUmbracoApplicationBuilderContext : IUmbracoApplicationBuilderServices
{
/// <summary>
/// The context object used during
/// Called to include the core umbraco middleware.
/// </summary>
public interface IUmbracoApplicationBuilderContext : IUmbracoApplicationBuilderServices
{
/// <summary>
/// Called to include the core umbraco middleware.
/// </summary>
void UseUmbracoCoreMiddleware();
void UseUmbracoCoreMiddleware();

/// <summary>
/// Manually runs the <see cref="IUmbracoPipelineFilter"/> pre pipeline filters
/// </summary>
void RunPrePipeline();
/// <summary>
/// Manually runs the <see cref="IUmbracoPipelineFilter" /> pre pipeline filters
/// </summary>
void RunPrePipeline();

/// <summary>
/// Manually runs the <see cref="IUmbracoPipelineFilter "/> post pipeline filters
/// </summary>
void RunPostPipeline();
/// <summary>
/// Manually runs the <see cref="IUmbracoPipelineFilter " /> post pipeline filters
/// </summary>
void RunPostPipeline();

/// <summary>
/// Called to include all of the default umbraco required middleware.
/// </summary>
/// <remarks>
/// If using this method, there is no need to use <see cref="UseUmbracoCoreMiddleware"/>
/// </remarks>
void RegisterDefaultRequiredMiddleware();
}
/// <summary>
/// Called to include all of the default umbraco required middleware.
/// </summary>
/// <remarks>
/// If using this method, there is no need to use <see cref="UseUmbracoCoreMiddleware" />
/// </remarks>
void RegisterDefaultRequiredMiddleware();
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
using System;
using Microsoft.AspNetCore.Builder;
using Umbraco.Cms.Core.Services;

namespace Umbraco.Cms.Web.Common.ApplicationBuilder
namespace Umbraco.Cms.Web.Common.ApplicationBuilder;

/// <summary>
/// Services used during the Umbraco building phase.
/// </summary>
public interface IUmbracoApplicationBuilderServices
{
/// <summary>
/// Services used during the Umbraco building phase.
/// </summary>
public interface IUmbracoApplicationBuilderServices
{
IApplicationBuilder AppBuilder { get; }
IServiceProvider ApplicationServices { get; }
IRuntimeState RuntimeState { get; }
}
IApplicationBuilder AppBuilder { get; }

IServiceProvider ApplicationServices { get; }

IRuntimeState RuntimeState { get; }
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
using System;
namespace Umbraco.Cms.Web.Common.ApplicationBuilder;

namespace Umbraco.Cms.Web.Common.ApplicationBuilder
public interface IUmbracoEndpointBuilder
{
public interface IUmbracoEndpointBuilder
{
/// <summary>
/// Final call during app building to configure endpoints
/// </summary>
/// <param name="configureUmbraco"></param>
void WithEndpoints(Action<IUmbracoEndpointBuilderContext> configureUmbraco);
}
/// <summary>
/// Final call during app building to configure endpoints
/// </summary>
/// <param name="configureUmbraco"></param>
void WithEndpoints(Action<IUmbracoEndpointBuilderContext> configureUmbraco);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
using Microsoft.AspNetCore.Routing;

namespace Umbraco.Cms.Web.Common.ApplicationBuilder
{
namespace Umbraco.Cms.Web.Common.ApplicationBuilder;

/// <summary>
/// A builder to allow encapsulating the enabled routing features in Umbraco
/// </summary>
public interface IUmbracoEndpointBuilderContext : IUmbracoApplicationBuilderServices
{
IEndpointRouteBuilder EndpointRouteBuilder { get; }
}
/// <summary>
/// A builder to allow encapsulating the enabled routing features in Umbraco
/// </summary>
public interface IUmbracoEndpointBuilderContext : IUmbracoApplicationBuilderServices
{
IEndpointRouteBuilder EndpointRouteBuilder { get; }
}
Loading