@@ -1,66 +0,0 @@ | |||
// Copyright (c) .NET Core Community. All rights reserved. | |||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||
using System; | |||
using DotNetCore.CAP.Messages; | |||
namespace DotNetCore.CAP.Abstractions | |||
{ | |||
/// <summary> | |||
/// Message content serializer. | |||
/// <para> | |||
/// By default, CAP will use Json as a serializer, and you can customize this interface to achieve serialization of | |||
/// other methods. | |||
/// </para> | |||
/// </summary> | |||
public interface IContentSerializer | |||
{ | |||
/// <summary> | |||
/// Serializes the specified object to a string. | |||
/// </summary> | |||
/// <typeparam name="T"> The type of the value being serialized.</typeparam> | |||
/// <param name="value">The object to serialize.</param> | |||
/// <returns>A string representation of the object.</returns> | |||
string Serialize<T>(T value); | |||
/// <summary> | |||
/// Deserializes the string to the specified .NET type. | |||
/// </summary> | |||
/// <typeparam name="T">The type of the object to deserialize to.</typeparam> | |||
/// <param name="value">The content string to deserialize.</param> | |||
/// <returns>The deserialized object from the string.</returns> | |||
T DeSerialize<T>(string value); | |||
/// <summary> | |||
/// Deserializes the string to the specified .NET type. | |||
/// </summary> | |||
/// <param name="value">The string to deserialize.</param> | |||
/// <param name="type">The type of the object to deserialize to.</param> | |||
/// <returns>The deserialized object from the string.</returns> | |||
object DeSerialize(string value, Type type); | |||
} | |||
/// <summary> | |||
/// CAP message content wapper. | |||
/// <para>You can customize the message body filed name of the wrapper or add fields that you interested.</para> | |||
/// </summary> | |||
/// <remarks> | |||
/// We use the wrapper to provide some additional information for the message content,which is important for CAP。 | |||
/// Typically, we may need to customize the field display name of the message, | |||
/// which includes interacting with other message components, which can be adapted in this manner | |||
/// </remarks> | |||
public interface IMessagePacker | |||
{ | |||
/// <summary> | |||
/// Package a message object | |||
/// </summary> | |||
/// <param name="obj">The obj message to be packed.</param> | |||
string Pack(CapMessage obj); | |||
/// <summary> | |||
/// Unpack a message strings to <see cref="CapMessage" /> object. | |||
/// </summary> | |||
/// <param name="packingMessage">The string of packed message.</param> | |||
CapMessage UnPack(string packingMessage); | |||
} | |||
} |
@@ -1,82 +0,0 @@ | |||
// Copyright (c) .NET Core Community. All rights reserved. | |||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||
using System; | |||
using DotNetCore.CAP; | |||
using Microsoft.Extensions.DependencyInjection; | |||
// ReSharper disable once CheckNamespace | |||
namespace Microsoft.AspNetCore.Builder | |||
{ | |||
/// <summary> | |||
/// app extensions for <see cref="IApplicationBuilder" /> | |||
/// </summary> | |||
internal static class AppBuilderExtensions | |||
{ | |||
/// <summary> | |||
/// Enables cap for the current application | |||
/// </summary> | |||
/// <param name="app">The <see cref="IApplicationBuilder" /> instance this method extends.</param> | |||
/// <returns>The <see cref="IApplicationBuilder" /> instance this method extends.</returns> | |||
//public static IApplicationBuilder UseCapDashboard(this IApplicationBuilder app) | |||
//{ | |||
// if (app == null) | |||
// { | |||
// throw new ArgumentNullException(nameof(app)); | |||
// } | |||
// CheckRequirement(app); | |||
// var provider = app.ApplicationServices; | |||
// if (provider.GetService<DashboardOptions>() != null) | |||
// { | |||
// if (provider.GetService<DiscoveryOptions>() != null) | |||
// { | |||
// app.UseMiddleware<GatewayProxyMiddleware>(); | |||
// } | |||
// app.UseMiddleware<DashboardMiddleware>(); | |||
// } | |||
// return app; | |||
//} | |||
private static void CheckRequirement(IApplicationBuilder app) | |||
{ | |||
var marker = app.ApplicationServices.GetService<CapMarkerService>(); | |||
if (marker == null) | |||
{ | |||
throw new InvalidOperationException( | |||
"AddCap() must be called on the service collection. eg: services.AddCap(...)"); | |||
} | |||
var messageQueueMarker = app.ApplicationServices.GetService<CapMessageQueueMakerService>(); | |||
if (messageQueueMarker == null) | |||
{ | |||
throw new InvalidOperationException( | |||
"You must be config used message queue provider at AddCap() options! eg: services.AddCap(options=>{ options.UseKafka(...) })"); | |||
} | |||
var databaseMarker = app.ApplicationServices.GetService<CapStorageMarkerService>(); | |||
if (databaseMarker == null) | |||
{ | |||
throw new InvalidOperationException( | |||
"You must be config used database provider at AddCap() options! eg: services.AddCap(options=>{ options.UseSqlServer(...) })"); | |||
} | |||
} | |||
} | |||
//sealed class CapStartupFilter : IStartupFilter | |||
//{ | |||
// public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) | |||
// { | |||
// return app => | |||
// { | |||
// app.UseCapDashboard(); | |||
// next(app); | |||
// }; | |||
// } | |||
//} | |||
} |
@@ -1,27 +0,0 @@ | |||
// Copyright (c) .NET Core Community. All rights reserved. | |||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||
using System; | |||
using DotNetCore.CAP.Abstractions; | |||
using DotNetCore.CAP.Infrastructure; | |||
namespace DotNetCore.CAP.Internal | |||
{ | |||
internal class JsonContentSerializer : IContentSerializer | |||
{ | |||
public T DeSerialize<T>(string messageObjStr) | |||
{ | |||
return Helper.FromJson<T>(messageObjStr); | |||
} | |||
public object DeSerialize(string content, Type type) | |||
{ | |||
return Helper.FromJson(content, type); | |||
} | |||
public string Serialize<T>(T messageObj) | |||
{ | |||
return Helper.ToJson(messageObj); | |||
} | |||
} | |||
} |
@@ -1,28 +0,0 @@ | |||
// Copyright (c) .NET Core Community. All rights reserved. | |||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||
using DotNetCore.CAP.Abstractions; | |||
using DotNetCore.CAP.Messages; | |||
namespace DotNetCore.CAP.Internal | |||
{ | |||
internal class DefaultMessagePacker : IMessagePacker | |||
{ | |||
private readonly IContentSerializer _serializer; | |||
public DefaultMessagePacker(IContentSerializer serializer) | |||
{ | |||
_serializer = serializer; | |||
} | |||
public string Pack(CapMessage obj) | |||
{ | |||
return _serializer.Serialize(obj); | |||
} | |||
public CapMessage UnPack(string packingMessage) | |||
{ | |||
return _serializer.DeSerialize<CapMessageDto>(packingMessage); | |||
} | |||
} | |||
} |
@@ -1,39 +0,0 @@ | |||
// Copyright (c) .NET Core Community. All rights reserved. | |||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||
using System; | |||
using System.Reflection; | |||
using System.Threading.Tasks; | |||
using DotNetCore.CAP.Abstractions; | |||
using DotNetCore.CAP.Abstractions.ModelBinding; | |||
namespace DotNetCore.CAP.Internal | |||
{ | |||
internal class ComplexTypeModelBinder : IModelBinder | |||
{ | |||
private readonly ParameterInfo _parameterInfo; | |||
private readonly IContentSerializer _serializer; | |||
public ComplexTypeModelBinder(ParameterInfo parameterInfo, IContentSerializer contentSerializer) | |||
{ | |||
_parameterInfo = parameterInfo; | |||
_serializer = contentSerializer; | |||
} | |||
public Task<ModelBindingResult> BindModelAsync(string content) | |||
{ | |||
try | |||
{ | |||
var type = _parameterInfo.ParameterType; | |||
var value = _serializer.DeSerialize(content, type); | |||
return Task.FromResult(ModelBindingResult.Success(value)); | |||
} | |||
catch (Exception) | |||
{ | |||
return Task.FromResult(ModelBindingResult.Failed()); | |||
} | |||
} | |||
} | |||
} |
@@ -1,85 +0,0 @@ | |||
// Copyright (c) .NET Core Community. All rights reserved. | |||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||
using System; | |||
using System.ComponentModel; | |||
using System.Globalization; | |||
using System.Reflection; | |||
using System.Runtime.ExceptionServices; | |||
using System.Threading.Tasks; | |||
using DotNetCore.CAP.Abstractions.ModelBinding; | |||
namespace DotNetCore.CAP.Internal | |||
{ | |||
internal class SimpleTypeModelBinder : IModelBinder | |||
{ | |||
private readonly ParameterInfo _parameterInfo; | |||
private readonly TypeConverter _typeConverter; | |||
public SimpleTypeModelBinder(ParameterInfo parameterInfo) | |||
{ | |||
_parameterInfo = parameterInfo ?? throw new ArgumentNullException(nameof(parameterInfo)); | |||
_typeConverter = TypeDescriptor.GetConverter(parameterInfo.ParameterType); | |||
} | |||
public Task<ModelBindingResult> BindModelAsync(string content) | |||
{ | |||
if (content == null) | |||
{ | |||
throw new ArgumentNullException(nameof(content)); | |||
} | |||
var parameterType = _parameterInfo.ParameterType; | |||
try | |||
{ | |||
object model; | |||
if (parameterType == typeof(string)) | |||
{ | |||
if (string.IsNullOrWhiteSpace(content)) | |||
{ | |||
model = null; | |||
} | |||
else | |||
{ | |||
model = content; | |||
} | |||
} | |||
else if (string.IsNullOrWhiteSpace(content)) | |||
{ | |||
model = null; | |||
} | |||
else | |||
{ | |||
model = _typeConverter.ConvertFrom( | |||
null, | |||
CultureInfo.CurrentCulture, | |||
content); | |||
} | |||
if (model == null && !IsReferenceOrNullableType(parameterType)) | |||
{ | |||
return Task.FromResult(ModelBindingResult.Failed()); | |||
} | |||
return Task.FromResult(ModelBindingResult.Success(model)); | |||
} | |||
catch (Exception exception) | |||
{ | |||
var isFormatException = exception is FormatException; | |||
if (!isFormatException && exception.InnerException != null) | |||
{ | |||
exception = ExceptionDispatchInfo.Capture(exception.InnerException).SourceException; | |||
} | |||
throw; | |||
} | |||
} | |||
private bool IsReferenceOrNullableType(Type type) | |||
{ | |||
var isNullableValueType = Nullable.GetUnderlyingType(type) != null; | |||
return !type.GetTypeInfo().IsValueType || isNullableValueType; | |||
} | |||
} | |||
} |
@@ -1,23 +0,0 @@ | |||
// Copyright (c) .NET Core Community. All rights reserved. | |||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||
using System; | |||
namespace DotNetCore.CAP.Internal | |||
{ | |||
[Serializable] | |||
public class MethodBindException : Exception | |||
{ | |||
public MethodBindException() | |||
{ | |||
} | |||
public MethodBindException(string message) : base(message) | |||
{ | |||
} | |||
public MethodBindException(string message, Exception inner) : base(message, inner) | |||
{ | |||
} | |||
} | |||
} |
@@ -1,124 +0,0 @@ | |||
// Copyright (c) .NET Core Community. All rights reserved. | |||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||
using System; | |||
using System.Collections.Concurrent; | |||
using System.Reflection; | |||
using System.Runtime.CompilerServices; | |||
using DotNetCore.CAP.Abstractions; | |||
using DotNetCore.CAP.Abstractions.ModelBinding; | |||
using DotNetCore.CAP.Infrastructure; | |||
namespace DotNetCore.CAP.Internal | |||
{ | |||
/// <summary> | |||
/// A factory for <see cref="IModelBinder" /> instances. | |||
/// </summary> | |||
internal class ModelBinderFactory : IModelBinderFactory | |||
{ | |||
private readonly ConcurrentDictionary<Key, IModelBinder> _cache; | |||
private readonly IContentSerializer _serializer; | |||
public ModelBinderFactory(IContentSerializer contentSerializer) | |||
{ | |||
_serializer = contentSerializer; | |||
_cache = new ConcurrentDictionary<Key, IModelBinder>(); | |||
} | |||
public IModelBinder CreateBinder(ParameterInfo parameter) | |||
{ | |||
if (parameter == null) | |||
{ | |||
throw new ArgumentNullException(nameof(parameter)); | |||
} | |||
object token = parameter; | |||
var binder = CreateBinderCoreCached(parameter, token); | |||
if (binder == null) | |||
{ | |||
throw new InvalidOperationException("Format Could Not Create IModelBinder"); | |||
} | |||
return binder; | |||
} | |||
private IModelBinder CreateBinderCoreCached(ParameterInfo parameterInfo, object token) | |||
{ | |||
if (TryGetCachedBinder(parameterInfo, token, out var binder)) | |||
{ | |||
return binder; | |||
} | |||
if (!Helper.IsComplexType(parameterInfo.ParameterType)) | |||
{ | |||
binder = new SimpleTypeModelBinder(parameterInfo); | |||
} | |||
else | |||
{ | |||
binder = new ComplexTypeModelBinder(parameterInfo, _serializer); | |||
} | |||
AddToCache(parameterInfo, token, binder); | |||
return binder; | |||
} | |||
private void AddToCache(ParameterInfo info, object cacheToken, IModelBinder binder) | |||
{ | |||
if (cacheToken == null) | |||
{ | |||
return; | |||
} | |||
_cache.TryAdd(new Key(info, cacheToken), binder); | |||
} | |||
private bool TryGetCachedBinder(ParameterInfo info, object cacheToken, out IModelBinder binder) | |||
{ | |||
if (cacheToken == null) | |||
{ | |||
binder = null; | |||
return false; | |||
} | |||
return _cache.TryGetValue(new Key(info, cacheToken), out binder); | |||
} | |||
private struct Key : IEquatable<Key> | |||
{ | |||
private readonly ParameterInfo _metadata; | |||
private readonly object _token; | |||
public Key(ParameterInfo metadata, object token) | |||
{ | |||
_metadata = metadata; | |||
_token = token; | |||
} | |||
public bool Equals(Key other) | |||
{ | |||
return _metadata.Equals(other._metadata) && ReferenceEquals(_token, other._token); | |||
} | |||
public override bool Equals(object obj) | |||
{ | |||
var other = obj as Key?; | |||
return other.HasValue && Equals(other.Value); | |||
} | |||
public override int GetHashCode() | |||
{ | |||
var hash = new HashCodeCombiner(); | |||
hash.Add(_metadata); | |||
hash.Add(RuntimeHelpers.GetHashCode(_token)); | |||
return hash; | |||
} | |||
public override string ToString() | |||
{ | |||
return $"{_token} (Property: '{_metadata.Name}' Type: '{_metadata.ParameterType.Name}')"; | |||
} | |||
} | |||
} | |||
} |
@@ -1,40 +0,0 @@ | |||
// Copyright (c) .NET Core Community. All rights reserved. | |||
// Licensed under the MIT License. See License.txt in the project root for license information. | |||
using System; | |||
using DotNetCore.CAP.Infrastructure; | |||
namespace DotNetCore.CAP.Messages | |||
{ | |||
public abstract class CapMessage | |||
{ | |||
public virtual string Id { get; set; } | |||
public virtual DateTime Timestamp { get; set; } | |||
public virtual string Content { get; set; } | |||
public virtual string CallbackName { get; set; } | |||
} | |||
public sealed class CapMessageDto : CapMessage | |||
{ | |||
public CapMessageDto() | |||
{ | |||
Id = ObjectId.GenerateNewStringId(); | |||
Timestamp = DateTime.Now; | |||
} | |||
public CapMessageDto(string content) : this() | |||
{ | |||
Content = content; | |||
} | |||
public override string Id { get; set; } | |||
public override DateTime Timestamp { get; set; } | |||
public override string Content { get; set; } | |||
} | |||
} |
@@ -1,32 +0,0 @@ | |||
using System.IO; | |||
using System.Threading.Tasks; | |||
using DotNetCore.CAP.Messages; | |||
using System.Runtime.Serialization.Formatters.Binary; | |||
namespace DotNetCore.CAP.Serialization | |||
{ | |||
public class MemorySerializer : ISerializer | |||
{ | |||
public Task<TransportMessage> SerializeAsync(Message message) | |||
{ | |||
var bf = new BinaryFormatter(); | |||
using (var ms = new MemoryStream()) | |||
{ | |||
bf.Serialize(ms, message.Value); | |||
return Task.FromResult(new TransportMessage(message.Headers, ms.ToArray())); | |||
} | |||
} | |||
public async Task<Message> DeserializeAsync(TransportMessage transportMessage) | |||
{ | |||
using (var memStream = new MemoryStream()) | |||
{ | |||
var binForm = new BinaryFormatter(); | |||
await memStream.WriteAsync(transportMessage.Body, 0, transportMessage.Body.Length); | |||
memStream.Seek(0, SeekOrigin.Begin); | |||
var obj = binForm.Deserialize(memStream); | |||
return new Message(transportMessage.Headers, obj); | |||
} | |||
} | |||
} | |||
} |