@@ -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); | |||||
} | |||||
} | |||||
} | |||||
} |