@@ -1,3 +1,6 @@ | |||||
{ | { | ||||
"projects": [ "src", "test" ] | |||||
"projects": [ "src", "test" ], | |||||
"sdk": { | |||||
"version": "1.0.0-preview2-1-003177" | |||||
} | |||||
} | } |
@@ -57,6 +57,7 @@ namespace Cap.Consistency.Server | |||||
consumer.Start(); | consumer.Start(); | ||||
_logger.LogInformation("Started consumer..."); | _logger.LogInformation("Started consumer..."); | ||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,6 +1,9 @@ | |||||
using System; | using System; | ||||
using System.Reflection; | using System.Reflection; | ||||
using System.Collections.Concurrent; | |||||
using System.Linq; | |||||
using Microsoft.Extensions.DependencyInjection; | using Microsoft.Extensions.DependencyInjection; | ||||
using System.Collections.Generic; | |||||
namespace Cap.Consistency | namespace Cap.Consistency | ||||
{ | { | ||||
@@ -44,6 +47,17 @@ namespace Cap.Consistency | |||||
return AddScoped(typeof(IConsistencyMessageStore<>).MakeGenericType(MessageType), typeof(T)); | return AddScoped(typeof(IConsistencyMessageStore<>).MakeGenericType(MessageType), typeof(T)); | ||||
} | } | ||||
public virtual ConsistencyBuilder AddMessageMethodTable() { | |||||
var provider = Services.BuildServiceProvider(); | |||||
var finder = provider.GetRequiredService<QMessageFinder>(); | |||||
finder.GetQMessageMethods(Services); | |||||
return null; | |||||
// Services.AddSingleton(serviceType, concreteType); | |||||
// return Add(typeof(IConsistencyMessageStore<>).MakeGenericType(MessageType), typeof(T)); | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// Adds a <see cref="ConsistencyMessageManager{TUser}"/> for the <seealso cref="MessageType"/>. | /// Adds a <see cref="ConsistencyMessageManager{TUser}"/> for the <seealso cref="MessageType"/>. | ||||
/// </summary> | /// </summary> | ||||
@@ -0,0 +1,162 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Linq.Expressions; | |||||
using System.Reflection; | |||||
using System.Threading.Tasks; | |||||
namespace Cap.Consistency.Extensions | |||||
{ | |||||
public static class ReflectionExtensions | |||||
{ | |||||
public static Type MakeDefType(this TypeInfo byRefTypeInfo) | |||||
{ | |||||
if (byRefTypeInfo == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(byRefTypeInfo)); | |||||
} | |||||
if (!byRefTypeInfo.IsByRef) | |||||
{ | |||||
throw new ArgumentException($"Type {byRefTypeInfo} is not passed by reference."); | |||||
} | |||||
var assemblyQualifiedName = byRefTypeInfo.AssemblyQualifiedName; | |||||
var index = assemblyQualifiedName.IndexOf('&'); | |||||
assemblyQualifiedName = assemblyQualifiedName.Remove(index, 1); | |||||
return byRefTypeInfo.Assembly.GetType(assemblyQualifiedName, true); | |||||
} | |||||
public static bool CanInherited(this TypeInfo typeInfo) | |||||
{ | |||||
if (typeInfo == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(typeInfo)); | |||||
} | |||||
if (!typeInfo.IsClass || typeInfo.IsSealed) | |||||
{ | |||||
return false; | |||||
} | |||||
if (typeInfo.IsNested) | |||||
{ | |||||
return typeInfo.IsNestedPublic && typeInfo.DeclaringType.GetTypeInfo().IsPublic; | |||||
} | |||||
else | |||||
{ | |||||
return typeInfo.IsPublic; | |||||
} | |||||
} | |||||
internal static MethodInfo GetMethodBySign(this TypeInfo typeInfo, MethodInfo method) | |||||
{ | |||||
if (method.IsGenericMethod) | |||||
{ | |||||
foreach (var genericMethod in typeInfo.DeclaredMethods.Where(m => m.IsGenericMethod)) | |||||
{ | |||||
if (method.ToString() == genericMethod.ToString()) | |||||
{ | |||||
return genericMethod; | |||||
} | |||||
} | |||||
} | |||||
return typeInfo.GetMethod(method.Name, method.GetParameterTypes()); | |||||
} | |||||
public static Type[] GetParameterTypes(this MethodInfo method) | |||||
{ | |||||
if (method == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(method)); | |||||
} | |||||
return method.GetParameters().Select(parame => parame.ParameterType).ToArray(); | |||||
} | |||||
public static bool IsPropertyBinding(this MethodInfo method) | |||||
{ | |||||
if (method == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(method)); | |||||
} | |||||
return method.GetBindingProperty() != null; | |||||
} | |||||
public static PropertyInfo GetBindingProperty(this MethodInfo method) | |||||
{ | |||||
if (method == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(method)); | |||||
} | |||||
foreach (var property in method.DeclaringType.GetTypeInfo().DeclaredProperties) | |||||
{ | |||||
if (property.CanRead && property.GetMethod == method) | |||||
{ | |||||
return property; | |||||
} | |||||
if (property.CanWrite && property.SetMethod == method) | |||||
{ | |||||
return property; | |||||
} | |||||
} | |||||
return null; | |||||
} | |||||
public static MethodInfo GetMethod<T>(Expression<T> expression) | |||||
{ | |||||
if (expression == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(expression)); | |||||
} | |||||
var methodCallExpression = expression.Body as MethodCallExpression; | |||||
if (methodCallExpression == null) | |||||
{ | |||||
throw new InvalidCastException("Cannot be converted to MethodCallExpression"); | |||||
} | |||||
return methodCallExpression.Method; | |||||
} | |||||
public static MethodInfo GetMethod<T>(string name) | |||||
{ | |||||
if (name == null) | |||||
{ | |||||
throw new ArgumentNullException(nameof(name)); | |||||
} | |||||
return typeof(T).GetTypeInfo().GetMethod(name); | |||||
} | |||||
internal static MethodInfo ReacquisitionIfDeclaringTypeIsGenericTypeDefinition(this MethodInfo methodInfo, Type closedGenericType) | |||||
{ | |||||
if (!methodInfo.DeclaringType.GetTypeInfo().IsGenericTypeDefinition) | |||||
{ | |||||
return methodInfo; | |||||
} | |||||
return closedGenericType.GetTypeInfo().GetMethod(methodInfo.Name, methodInfo.GetParameterTypes()); | |||||
} | |||||
internal static string GetFullName(this MemberInfo member) | |||||
{ | |||||
var declaringType = member.DeclaringType.GetTypeInfo(); | |||||
if (declaringType.IsInterface) | |||||
{ | |||||
return $"{declaringType.Name}.{member.Name}".Replace('+', '.'); | |||||
} | |||||
return member.Name; | |||||
} | |||||
internal static bool IsReturnTask(this MethodInfo methodInfo) | |||||
{ | |||||
return typeof(Task).GetTypeInfo().IsAssignableFrom(methodInfo.ReturnType.GetTypeInfo()); | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,14 @@ | |||||
using System; | |||||
namespace Cap.Consistency | |||||
{ | |||||
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)] | |||||
sealed class QMessageAttribute : Attribute | |||||
{ | |||||
public QMessageAttribute(string messageName) { | |||||
MessageName = messageName; | |||||
} | |||||
public string MessageName { get; private set; } | |||||
} | |||||
} |
@@ -0,0 +1,48 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Threading.Tasks; | |||||
using System.Collections.Concurrent; | |||||
using Cap.Consistency.Extensions; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
namespace Cap.Consistency | |||||
{ | |||||
public class QMessageFinder | |||||
{ | |||||
public ConcurrentDictionary<string, QMessageMethodInfo> GetQMessageMethods(IServiceCollection serviceColloection) { | |||||
if (serviceColloection == null) { | |||||
throw new ArgumentNullException(nameof(serviceColloection)); | |||||
} | |||||
var qMessageTypes = new ConcurrentDictionary<string, QMessageMethodInfo>(); | |||||
foreach (var serviceDescriptor in serviceColloection) { | |||||
foreach (var method in serviceDescriptor.ServiceType.GetTypeInfo().DeclaredMethods) { | |||||
var messageMethodInfo = new QMessageMethodInfo(); | |||||
if (method.IsPropertyBinding()) { | |||||
continue; | |||||
} | |||||
var qMessageAttr = method.GetCustomAttribute<QMessageAttribute>(); | |||||
if (qMessageAttr == null) { | |||||
continue; | |||||
} | |||||
messageMethodInfo.MessageName = qMessageAttr.MessageName; | |||||
messageMethodInfo.ImplType = method.DeclaringType; | |||||
messageMethodInfo.MethodInfo = method; | |||||
qMessageTypes.AddOrUpdate(qMessageAttr.MessageName, messageMethodInfo, (x, y) => y); | |||||
} | |||||
} | |||||
return qMessageTypes; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,17 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Threading.Tasks; | |||||
namespace Cap.Consistency | |||||
{ | |||||
public class QMessageMethodInfo | |||||
{ | |||||
public MethodInfo MethodInfo { get; set; } | |||||
public Type ImplType { get; set; } | |||||
public string MessageName { get; set; } | |||||
} | |||||
} |
@@ -0,0 +1,40 @@ | |||||
using System; | |||||
using System.Collections; | |||||
using System.Collections.Generic; | |||||
namespace Cap.Consistency | |||||
{ | |||||
public class RouteTable : IReadOnlyList<QMessageMethodInfo> | |||||
{ | |||||
public RouteTable() { | |||||
} | |||||
public RouteTable(List<QMessageMethodInfo> messageMethods) { | |||||
QMessageMethods = messageMethods; | |||||
} | |||||
public QMessageMethodInfo this[int index] { | |||||
get { | |||||
throw new NotImplementedException(); | |||||
} | |||||
} | |||||
public int Count { | |||||
get { | |||||
throw new NotImplementedException(); | |||||
} | |||||
} | |||||
public List<QMessageMethodInfo> QMessageMethods { get; set; } | |||||
public IEnumerator<QMessageMethodInfo> GetEnumerator() { | |||||
throw new NotImplementedException(); | |||||
} | |||||
IEnumerator IEnumerable.GetEnumerator() { | |||||
throw new NotImplementedException(); | |||||
} | |||||
} | |||||
} |
@@ -33,6 +33,10 @@ namespace Microsoft.Extensions.DependencyInjection | |||||
services.TryAddScoped<ConsistencyMessageManager<TMessage>, ConsistencyMessageManager<TMessage>>(); | services.TryAddScoped<ConsistencyMessageManager<TMessage>, ConsistencyMessageManager<TMessage>>(); | ||||
services.AddSingleton<QMessageFinder>(); | |||||
if (setupAction != null) { | if (setupAction != null) { | ||||
services.Configure(setupAction); | services.Configure(setupAction); | ||||
} | } | ||||
@@ -1,11 +1,12 @@ | |||||
{ | |||||
{ | |||||
"version": "1.0.0-*", | "version": "1.0.0-*", | ||||
"dependencies": { | "dependencies": { | ||||
"Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*", | "Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*", | ||||
"Microsoft.Extensions.Options": "1.1.0-*", | "Microsoft.Extensions.Options": "1.1.0-*", | ||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "1.1.0", | "Microsoft.Extensions.DependencyInjection.Abstractions": "1.1.0", | ||||
"Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", | "Microsoft.Extensions.Logging.Abstractions": "1.1.0-*", | ||||
"NETStandard.Library": "1.6.1" | |||||
"NETStandard.Library": "1.6.1", | |||||
"Microsoft.Extensions.DependencyInjection": "1.1.0" | |||||
}, | }, | ||||
"frameworks": { | "frameworks": { | ||||
"netstandard1.6": { | "netstandard1.6": { | ||||