mirror of https://github.com/Squidex/squidex.git
7 changed files with 187 additions and 51 deletions
@ -0,0 +1,37 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Orleans; |
|||
|
|||
namespace Squidex.Infrastructure.Orleans |
|||
{ |
|||
public sealed class ExceptionWrapperFilter : IIncomingGrainCallFilter |
|||
{ |
|||
public async Task Invoke(IIncomingGrainCallContext context) |
|||
{ |
|||
try |
|||
{ |
|||
await context.Invoke(); |
|||
} |
|||
catch (Exception ex) |
|||
{ |
|||
var type = ex.GetType(); |
|||
|
|||
if (!type.IsSerializable) |
|||
{ |
|||
throw new OrleansWrapperException(ex, type); |
|||
} |
|||
else |
|||
{ |
|||
throw; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,50 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Runtime.Serialization; |
|||
using System.Text; |
|||
|
|||
namespace Squidex.Infrastructure.Orleans |
|||
{ |
|||
[Serializable] |
|||
public class OrleansWrapperException : Exception |
|||
{ |
|||
public Type ExceptionType { get; } |
|||
|
|||
public OrleansWrapperException(Exception wrapped, Type exceptionType) |
|||
: base(FormatMessage(wrapped, exceptionType)) |
|||
{ |
|||
ExceptionType = exceptionType; |
|||
} |
|||
|
|||
protected OrleansWrapperException(SerializationInfo info, StreamingContext context) |
|||
: base(info, context) |
|||
{ |
|||
ExceptionType = Type.GetType(info.GetString(nameof(ExceptionType))!)!; |
|||
} |
|||
|
|||
public override void GetObjectData(SerializationInfo info, StreamingContext context) |
|||
{ |
|||
info.AddValue(nameof(ExceptionType), ExceptionType.AssemblyQualifiedName); |
|||
|
|||
base.GetObjectData(info, context); |
|||
} |
|||
|
|||
private static string FormatMessage(Exception wrapped, Type exceptionType) |
|||
{ |
|||
var sb = new StringBuilder(); |
|||
|
|||
sb.AppendLine($"Wrapping exception of type {exceptionType}, because original exception is not serialized."); |
|||
sb.AppendLine(); |
|||
sb.AppendLine("Original exception:"); |
|||
sb.AppendLine(wrapped.ToString()); |
|||
|
|||
return sb.ToString(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
// ==========================================================================
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
|||
// All rights reserved. Licensed under the MIT license.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using FakeItEasy; |
|||
using Orleans; |
|||
using Squidex.Infrastructure.TestHelpers; |
|||
using Xunit; |
|||
|
|||
namespace Squidex.Infrastructure.Orleans |
|||
{ |
|||
public class ExceptionWrapperFilterTests |
|||
{ |
|||
private readonly IIncomingGrainCallContext context = A.Fake<IIncomingGrainCallContext>(); |
|||
private readonly ExceptionWrapperFilter sut; |
|||
|
|||
private sealed class InvalidException : Exception |
|||
{ |
|||
public InvalidException(string message) |
|||
: base(message) |
|||
{ |
|||
} |
|||
} |
|||
|
|||
public ExceptionWrapperFilterTests() |
|||
{ |
|||
sut = new ExceptionWrapperFilter(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_just_forward_serializable_exception() |
|||
{ |
|||
var original = new InvalidOperationException(); |
|||
|
|||
A.CallTo(() => context.Invoke()) |
|||
.Throws(original); |
|||
|
|||
var ex = await Assert.ThrowsAnyAsync<Exception>(() => sut.Invoke(context)); |
|||
|
|||
Assert.Same(ex, original); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_wrap_non_serializable_exception() |
|||
{ |
|||
var original = new InvalidException("My Message"); |
|||
|
|||
A.CallTo(() => context.Invoke()) |
|||
.Throws(original); |
|||
|
|||
var ex = await Assert.ThrowsAnyAsync<OrleansWrapperException>(() => sut.Invoke(context)); |
|||
|
|||
Assert.Equal(original.GetType(), ex.ExceptionType); |
|||
Assert.Contains(original.Message, ex.Message); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Should_serialize_and_deserialize() |
|||
{ |
|||
var original = new InvalidException("My Message"); |
|||
|
|||
var source = new OrleansWrapperException(original, original.GetType()); |
|||
var result = source.SerializeAndDeserializeBinary(); |
|||
|
|||
Assert.Equal(result.ExceptionType, source.ExceptionType); |
|||
|
|||
Assert.Equal(result.Message, source.Message); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue