由于Orlans不支持Linq 表达式参数,所以只能把Linq 表达式参数转换为JObject类型的参数
有关Orleans自定义序列化参数
http://dotnet.github.io/orleans/Documentation/Advanced-Concepts/Serialization.html
序列化JObject类型的参数代码如下:
using Newtonsoft.Json.Linq;
using Orleans.Runtime;
using Orleans.Serialization;
using System;
namespace NoobOrleans.Core
{
/// <summary>
/// An implementation of IExternalSerializer for usage with linq types.
/// </summary>
public class JsonSerializer : IExternalSerializer
{
//增加自定义的处理类
private static readonly Type JsonType = typeof(JObject);
protected Logger logger;
public JsonSerializer()
{
}
/// <summary>
/// Initializes the external serializer
/// </summary>
/// <param name="logger">The logger to use to capture any serialization events</param>
public void Initialize(Logger logger)
{
this.logger = logger;
}
/// <summary>
/// Informs the serialization manager whether this serializer supports the type for serialization.
/// </summary>
/// <param name="itemType">The type of the item to be serialized</param>
/// <returns>A value indicating whether the item can be serialized.</returns>
public bool IsSupportedType(Type itemType)
{
if (JsonType.IsAssignableFrom(itemType))
{
return true;
}
return false;
}
/// <summary>
/// Tries to create a copy of source.
/// </summary>
/// <param name="source">The item to create a copy of</param>
/// <param name="context">The context in which the object is being copied.</param>
/// <returns>The copy</returns>
public virtual object DeepCopy(object source, ICopyContext context)
{
if (source == null)
{
return null;
}
//Expression expression = source as Expression;
//if (expression == null)
//{
// throw new ArgumentException("The provided item for serialization in not an instance of " + typeof(Expression), "item");
//}
//byte[] outBytes = serializer.SerializeBinary(expression);
//object target = serializer.DeserializeBinary(outBytes);//
//return target;
return source;
}
/// <summary>
/// Tries to serialize an item.
/// </summary>
/// <param name="item">The instance of the object being serialized</param>
/// <param name="context">The context in which the object is being serialized.</param>
/// <param name="expectedType">The type that the deserializer will expect</param>
public virtual void Serialize(object item, ISerializationContext context, Type expectedType)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var writer = context.StreamWriter;
if (item == null)
{
writer.WriteNull();
return;
}
Type type = item.GetType();
var typeHandle = type.TypeHandle;
if (logger != null)
{
logger.Verbose("JsonSerializer,Serialize,expectedType:" + expectedType + ",item.type:" + type + ",item.TypeHandle:" + typeHandle);
}
var input = item as JObject;
string str = input.ToString();
if (logger != null)
{
logger.Verbose("JsonSerializer,JObject.ToString():" + str);
}
context.SerializationManager.Serialize(str, context.StreamWriter);
}
/// <summary>
/// Tries to deserialize an item.
/// </summary>
/// <param name="context">The context in which the object is being deserialized.</param>
/// <param name="expectedType">The type that should be deserialized</param>
/// <returns>The deserialized object</returns>
public virtual object Deserialize(Type expectedType, IDeserializationContext context)
{
if (expectedType == null)
{
throw new ArgumentNullException(nameof(expectedType));
}
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
var typeHandle = expectedType.TypeHandle;
if (logger != null)
{
logger.Verbose("JsonSerializer,Deserialize,expectedType:" + expectedType + ",expectedType.TypeHandle:" + expectedType.TypeHandle);
}
var str = (string)context.SerializationManager.Deserialize(typeof(string), context.StreamReader);
if (logger != null)
{
logger.Verbose("JsonSerializer,Deserialize,str:" + str);
}
return JObject.Parse(str);
}
}
}
Linq表达式转换为JObject对象代码如下
注意需要引用第三方“ Serialize.Linq.dll”库
对应的Github地址如下:
https://github.com/esskar/Serialize.Linq
using Newtonsoft.Json.Linq;
using Orchard.Data;
using Serialize.Linq.Serializers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace Orchard.Orleans
{
/// <summary>
///
/// </summary>
public static partial class ExpressionExtension
{
/// <summary>
/// Predicate JObject
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="predicate"></param>
/// <returns></returns>
public static JObject ToJObject<TEntity>(this Expression<Func<TEntity, bool>> predicate) where TEntity : class
{
string predicateJson = JsonSerializerUtils.SerializeText(predicate);
if (string.IsNullOrEmpty(predicateJson))
{
return null;
}
return JObject.Parse(predicateJson);
}
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="expression"></param>
/// <returns></returns>
public static JObject ToJObject<TEntity,TProperty>(this Expression<Func<TEntity,TProperty>> expression) where TEntity : class
{
string predicateJson = JsonSerializerUtils.SerializeText(expression);
if (string.IsNullOrEmpty(predicateJson))
{
return null;
}
return JObject.Parse(predicateJson);
}
/// <summary>
/// Order By JObject Array
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="orderByExpressions"></param>
/// <returns></returns>
public static JObject[] ToJObjectArray<TEntity>(this IOrderByExpression<TEntity>[] orderByExpressions) where TEntity : class
{
if (orderByExpressions == null || orderByExpressions.Length == 0) return null;
List<JObject> orderByList = new List<JObject>();
foreach (var item in orderByExpressions)
{
orderByList.Add(item.ToJObject());
}
return orderByList.ToArray();
}
/// <summary>
/// Update JObject
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="updateExpression">updateExpression</param>
/// <returns></returns>
public static JObject ToJObject<TEntity>(this Expression<Func<TEntity, TEntity>> updateExpression) where TEntity : class
{
string predicateJson = JsonSerializerUtils.SerializeText(updateExpression);
if (string.IsNullOrEmpty(predicateJson))
{
return null;
}
return JObject.Parse(predicateJson);
}
}
/// <summary>
///
/// </summary>
public static partial class OrleansJsonExtension
{
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="jsonObject"></param>
/// <returns></returns>
public static Expression<Func<TEntity, bool>> ToPredicate<TEntity>(this JObject jsonObject) where TEntity : class
{
if (jsonObject == null) return null;
var result = JsonSerializerUtils.DeserializeJObject(jsonObject);
if (result == null)
{
return null;
}
else
{
return result as Expression<Func<TEntity, bool>>;
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="jsonObject"></param>
/// <returns></returns>
public static IOrderByExpression<TEntity> ToOrderBy<TEntity>(this JObject jsonObject) where TEntity : class
{
if (jsonObject == null) return null;
var expressionTxt = jsonObject["expression"].ToString();
if (string.IsNullOrEmpty(expressionTxt)) return null;
var descending = (bool)jsonObject["descending"];
var strPropertyType = jsonObject["propertyType"].ToString();
var expression = JsonSerializerUtils.DeserializeText(expressionTxt);
if (expression == null)
{
return null;
}
else
{
Type genericType = typeof(OrderByExpression<,>);
Type propertyType = Type.GetType(strPropertyType);
Type[] typeArgs = { typeof(TEntity), propertyType };
Type implementType = genericType.MakeGenericType(typeArgs);
//var tmpOrderByExpression = expression as Expression<Func<TEntity,int>>;
//return new OrderByExpression<TEntity, int>(tmpOrderByExpression, descending);
//var instance= Activator.CreateInstance(implementType, new object[] { expression, descending });
#region 动态的泛型类型 暂时想不到更好的办法
if (propertyType == typeof(int))
{
return GetOrderByExpression<TEntity, int>(expression, descending);
}
if (propertyType == typeof(uint))
{
return GetOrderByExpression<TEntity, uint>(expression, descending);
}
else if (propertyType == typeof(short))
{
return GetOrderByExpression<TEntity, short>(expression, descending);
}
else if (propertyType == typeof(ushort))
{
return GetOrderByExpression<TEntity, ushort>(expression, descending);
}
else if (propertyType == typeof(long))
{
return GetOrderByExpression<TEntity, long>(expression, descending);
}
else if (propertyType == typeof(ulong))
{
return GetOrderByExpression<TEntity, ulong>(expression, descending);
}
else if (propertyType == typeof(string))
{
return GetOrderByExpression<TEntity, string>(expression, descending);
}
else if (propertyType == typeof(double))
{
return GetOrderByExpression<TEntity, double>(expression, descending);
}
else if (propertyType == typeof(decimal))
{
return GetOrderByExpression<TEntity, decimal>(expression, descending);
}
else if (propertyType == typeof(float))
{
return GetOrderByExpression<TEntity, float>(expression, descending);
}
else if (propertyType == typeof(byte))
{
return GetOrderByExpression<TEntity, byte>(expression, descending);
}
else if (propertyType == typeof(sbyte))
{
return GetOrderByExpression<TEntity, sbyte>(expression, descending);
}
else if (propertyType == typeof(DateTime))
{
return GetOrderByExpression<TEntity, DateTime>(expression, descending);
}
else if (propertyType == typeof(Guid))
{
return GetOrderByExpression<TEntity, Guid>(expression, descending);
}
else
{
return null;
}
#endregion
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="expression"></param>
/// <param name="descending"></param>
/// <returns></returns>
private static IOrderByExpression<TEntity> GetOrderByExpression<TEntity, TProperty>(Expression expression, bool descending) where TEntity : class
{
var tmpOrderByExpression = expression as Expression<Func<TEntity, TProperty>>;
return new OrderByExpression<TEntity, TProperty>(tmpOrderByExpression, descending);
}
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <returns></returns>
public static IOrderByExpression<TEntity>[] ToOrderByArray<TEntity>(this JObject[] jsonObjects) where TEntity : class
{
if (jsonObjects == null || jsonObjects.Length == 0)
{
return null;
}
List<IOrderByExpression<TEntity>> orderByList = new List<IOrderByExpression<TEntity>>();
foreach (var item in jsonObjects)
{
orderByList.Add(item.ToOrderBy<TEntity>());
}
return orderByList.ToArray();
}
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="jsonObject"></param>
/// <returns></returns>
public static Expression<Func<TEntity, TEntity>> ToUpdateExpression<TEntity>(this JObject jsonObject) where TEntity : class
{
if (jsonObject == null) return null;
var result = JsonSerializerUtils.DeserializeJObject(jsonObject);
if (result == null)
{
return null;
}
else
{
return result as Expression<Func<TEntity, TEntity>>;
}
}
}
/// <summary>
///
/// </summary>
public partial class JsonSerializerUtils
{
private static ExpressionSerializer serializer = new ExpressionSerializer(new Serialize.Linq.Serializers.JsonSerializer());
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="predicate"></param>
/// <returns></returns>
public static string SerializeText<TEntity>(Expression<Func<TEntity, bool>> predicate) where TEntity : class
{
return serializer.SerializeText(predicate);
}
/// <summary>
///
/// </summary>
/// <typeparam name="TEntity"></typeparam>
/// <param name="predicate"></param>
/// <returns></returns>
public static string SerializeText<TEntity,TProperty>(Expression<Func<TEntity, TProperty>> expression) where TEntity : class
{
return serializer.SerializeText(expression);
}
/// <summary>
///
/// </summary>
/// <param name="jsonObject"></param>
/// <returns></returns>
public static Expression DeserializeJObject(JObject jsonObject)
{
if (jsonObject==null)
{
return null;
}
string strJson = jsonObject.ToString();
if (string.IsNullOrEmpty(strJson)) return null;
return serializer.DeserializeText(strJson);
}
/// <summary>
///
/// </summary>
/// <param name="jsonObject"></param>
/// <returns></returns>
public static Expression DeserializeText(string strJson)
{
if (string.IsNullOrEmpty(strJson)) return null;
return serializer.DeserializeText(strJson);
}
}
}
Grain对应的测试代码如下
/// <summary>
/// Used to get all entities based on given <paramref name="predicate"/>.
/// </summary>
/// <param name="jsonPredicate">A condition to filter entities</param>
/// <param name="jsonOrderByExpressions">order by </param>
/// <return awaits>List of all entities</return awaits>
public virtual async Task<List<TEntity>> GetListAsync(JObject jsonPredicate, params JObject[] jsonOrderByExpressions)
{
Expression<Func<TEntity, bool>> predicate = jsonPredicate.ToPredicate<TEntity>();
IOrderByExpression<TEntity>[] orderByExpressions = jsonOrderByExpressions.ToOrderByArray<TEntity>();
return await service.GetListAsync(predicate, orderByExpressions);
}
Orleans.Server 配置如下
<SerializationProviders>
<Provider type="NoobOrleans.Core.JsonSerializer,NoobOrleans.Core"/>
</SerializationProviders>
</Messaging>
Orleans.Client配置如下:
<SerializationProviders>
<Provider type="NoobOrleans.Core.JsonSerializer,NoobOrleans.Core"/>
</SerializationProviders>
测试代码如下
Expression> predicate = x => x.Id >= 100 && x.Id < 105;
Action<Orderable<AdmArea>> orderAction = (o =>
{
o.Desc(x => x.AreaID).Asc(x => x.CreateUser);
});
var orderByExpressions = new IOrderByExpression<AdmArea>[] {
new OrderByExpression<AdmArea, string>(u => u.AreaID), // a string, asc
new OrderByExpression<AdmArea, int>(u => u.Id, true)
};
var result = await grain.GetListAsync(predicate.ToJObject(),
orderByExpressions.ToJObjectArray());