@@ -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(); | |||
_logger.LogInformation("Started consumer..."); | |||
} | |||
} | |||
} |
@@ -1,6 +1,9 @@ | |||
using System; | |||
using System.Reflection; | |||
using System.Collections.Concurrent; | |||
using System.Linq; | |||
using Microsoft.Extensions.DependencyInjection; | |||
using System.Collections.Generic; | |||
namespace Cap.Consistency | |||
{ | |||
@@ -44,6 +47,17 @@ namespace Cap.Consistency | |||
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> | |||
/// Adds a <see cref="ConsistencyMessageManager{TUser}"/> for the <seealso cref="MessageType"/>. | |||
/// </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.AddSingleton<QMessageFinder>(); | |||
if (setupAction != null) { | |||
services.Configure(setupAction); | |||
} | |||
@@ -1,11 +1,12 @@ | |||
{ | |||
{ | |||
"version": "1.0.0-*", | |||
"dependencies": { | |||
"Microsoft.AspNetCore.Http.Abstractions": "1.1.0-*", | |||
"Microsoft.Extensions.Options": "1.1.0-*", | |||
"Microsoft.Extensions.DependencyInjection.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": { | |||
"netstandard1.6": { | |||