我的WCF数据服务(二)独立

由于当时正在学WCF,就使用了WCF作为数据提供,由于需要常驻内存,所以使用了WINDOWS服务作为载体。
当时觉得难点有1个,就是传递查询和排序条件,委托是不能在进程间传递的,幸亏有了 Expression 这个类,改一下参数的类型就行了,原来的代码基本不用动。但是 Expression 也不能直接就在进程间传递。后来读到了一篇文章介绍了 ExpressionSerializer 这个类,可以把表达式转换成XML,或者再转换回来。理论上可以了,就开始动手了。请看代码:

public class ModelPvd<T> : IModelPvd where T : class
    {
        protected ReaderWriterLock LockerRW = new ReaderWriterLock();//数据操作锁
        protected object lockerForOp = new object();//反序列化锁
        protected ExpressionSerializer serializer { private set; get; }//序列化器
        public string Name { private set; get; }//类名称
        protected List<T> Lm;//数据
        Func<int, T> FModelPrvd;//获取实体对象的委托,在类初始化时,会获取所有数据保存在这个变量。
        Action<List<T>, int> ADelDlgt;//列表删除器,当数据库删除了一条数据,也从Lm里删除这条数据。
        protected ILogWriter lw;//日志记录器
        public ModelPvd(Func<List<T>> dataPrvd, Func<int, T> modelPrvd, Action<List<T>, int> delDlgt, bool isAd, ILogWriter ilog)
        {
            List<Assembly> assemblies = new List<Assembly> { typeof(T).Assembly, typeof(ExpressionType).Assembly, typeof(IQueryable).Assembly };
            var resolver = new TypeResolver(assemblies, new[] { typeof(T), typeof(DateTime), typeof(decimal), typeof(object) });
            var knownTypeConverter1 = new KnownTypeExpressionXmlConverter(resolver);
            serializer = new ExpressionSerialization.ExpressionSerializer(resolver, new CustomExpressionXmlConverter[] { knownTypeConverter1 });
            //上边这一段是序列化器的生成,是从ExpressionSerializer的例子里拷来的。
            Lm = dataPrvd.Invoke();//获取数据
            Name = typeof(T).ToString();//因为有好些数据表都要做这个功能,这个名字用来区分。
            FModelPrvd = modelPrvd;
            ADelDlgt = delDlgt;
            lw = ilog;
        }
        public object[] GetList(int pageSize, int pageIndex, XElement match, XElement orderKeySelector, bool desc, out int recordCount)//查询数据功能。
        {
            Expression<Func<T, bool>> p;
            lock (lockerForOp)
            {
                p = serializer.Deserialize<Func<T, bool>>(match);
            }
            lw.Write(Name + "  " + p.ToString() + " l " + pageSize.ToString());
            int orderWay;//排序方式,0:按照表达式排序,1,随机排序。
            Expression<Func<T, int>> o = null;
                orderWay = orderKeySelector == null ? 1 : 0;
                if (orderWay == 0)
                {
                    lock (lockerForOp)
                    {
                        o = serializer.Deserialize<Func<T, int>>(orderKeySelector);
                    }
                }
            List<T> r;
            LockerRW.AcquireReaderLock(200);
            try
            {
                var l = Lm.Where(p.Compile());
                recordCount = l.Count();
                switch (orderWay)
                {
                    case 1:
                        r = l.OrderByDescending(x => Guid.NewGuid()).Take(pageSize).ToList();
                        break;
                    default:
                        if (desc)
                            r = l.OrderByDescending(o.Compile()).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
                        else
                            r = l.OrderBy(o.Compile()).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
                        break;
                }
            }
            finally
            {
                LockerRW.ReleaseReaderLock();
            }
            if (r == null)
                return null;
            return r.ToArray();
        }
        //////查询符合条件的数据数量。
        public int GetCount(XElement match)
        {
            int rst;
            Expression<Func<T, bool>> p;
            lock (lockerForOp)
            {
                p = serializer.Deserialize<Func<T, bool>>(match);
            }
            lw.Write(Name + " " + p.ToString() + "c");
            LockerRW.AcquireReaderLock(200);
            try
            {
                rst = Lm.Count(p.Compile());
            }
            finally { LockerRW.ReleaseReaderLock(); }
            return rst;
        }
        某一条数据发生变化(增删改)时,调用这个方法同步。
        public bool UpdateData(int Id)
        {
            var model = FModelPrvd.Invoke(Id);
            LockerRW.AcquireWriterLock(1000);
            try
            {
                ADelDlgt.Invoke(Lm, Id);
                if (model != null)
                    Lm.Add(model);
            }
            finally
            {
                LockerRW.ReleaseWriterLock();
            }
            return true;
        }
    }

下面是实现的接口。

public interface IModelPvd
    {
        string Name { get; }
        object[] GetList(int pageSize, int pageIndex, XElement match, XElement orderKeySelector, bool desc, out int recordCount);
        int GetCount(XElement match);
        bool UpdateData(int Id);
    }

在WCF的服务实现类里,代码是这样的:

public class Service1 : IService1
    {
    static List<IModelPvd> Limp;
        static LogWriter Lw = new LogWriter();
        static Service1()
        {
            GetAllData();
        }
        static void GetAllData()
        {
        Limp = new List<IModelPvd>();
            Limp.Add(new ModelPvdAd<Model.XXX>(DAL.XXX.GetListByDAL, DAL.XXX.GetModel, (x, y) => x.RemoveAll(z => z.Id == y),  Lw));
            }
            public int GetCount(string typeName, XElement match)
        {
            var m = Limp.Find(x => x.Name == typeName);
            if (m != null)
                return m.GetCount(match);
            else
                return 0;
        }
        public object[] GetList(string typeName, int pageSize, int pageIndex, XElement match, XElement orderKeySelector, bool desc, out int recordCount)
        {
            var m = Limp.Find(x => x.Name == typeName);
            if (m != null)
                return m.GetList(pageSize, pageIndex, match, orderKeySelector, desc, out recordCount);
            else
            {
                recordCount = 0;
                return null;
            }
        }
        public bool UpdateData(string typeName, int Id)
        {
        var m = Limp.Find(x => x.Name == typeName);
                    if (m != null)
                        return m.UpdateData(Id);
                    else
                        return false;
}
    }

还有WCF的接口代码:

public interface IService1
{
[OperationContract]
        [ServiceKnownType(typeof(Model.XXX))]
        object[] GetList(string typeName, int pageSize, int pageIndex, XElement match, XElement orderKeySelector, bool desc, out int recordCount);
        [OperationContract]
        int GetCount(string typeName, XElement match);

        [OperationContract]
        bool UpdateData(string typeName, int Id);
}

上边这几段代码,是服务器端。ExpressionSerializer 这个类会把传过来的 XML 转化成原始的LAMBDA表达式,一个 Expression<<Func<Model.XXX,bool>> 这样的条件表达式,或者一个 Expression<Func<Model.XXX,int>>这样的排序表达式。如果想随机排序,就把排序的 XML 传个 null 过来。
再来看看客户端:

public class ModelPvd<T> where T : class
    {
        protected object locker = new object();//序列化锁
        protected ExpressionSerializer serializer { private set; get; }//序列化器
        public string Name { private set; get; }//类名称
        public Expression<Func<T, int>> PrimaryKey;
        public ModelPvd(Expression<Func<T, int>> primaryKey)
        {
            List<Assembly> assemblies = new List<Assembly> { typeof(T).Assembly, typeof(ExpressionType).Assembly, typeof(IQueryable).Assembly };
            var resolver = new TypeResolver(assemblies, new[] { typeof(T), typeof(DateTime), typeof(decimal), typeof(object) });
            var knownTypeConverter1 = new KnownTypeExpressionXmlConverter(resolver);
            serializer = new ExpressionSerialization.ExpressionSerializer(resolver, new CustomExpressionXmlConverter[] { knownTypeConverter1 });
            Name = typeof(T).ToString();
            PrimaryKey = primaryKey;
        }
        public List<T> GetList<Tm>(int pageSize, int pageIndex, Expression<Func<T, bool>> Efma, Expression<Func<T, Tm>> orderBy, bool desc, out int recordCount)
        {
            System.Xml.Linq.XElement xmlOrder = null;
            if ((typeof(Tm) != typeof(int)) || orderBy == null)
            {
                xmlOrder = null;
            }
            else
            {
                lock (locker)
                {
                    xmlOrder = serializer.Serialize(orderBy);
                }
            }
            System.Xml.Linq.XElement xmlPredicate;
            lock (locker)
            {
                xmlPredicate = serializer.Serialize(Efma);
            }
            DataCenter.Service1Client Dcsc = All.GetDataCenterService();
            object[] l = Dcsc.GetList(typeof(T).ToString(), pageSize, pageIndex, xmlPredicate, xmlOrder, desc, out recordCount) as object[];
            All.CloseDc(Dcsc);
            var Lado = new List<T>();
            foreach (object i in l)
            {
                Lado.Add(i as T);
            }
            return Lado;
        }
        public int GetCount(Expression<Func<T, bool>> Efma, bool IsRebuild = true)
        {
            System.Xml.Linq.XElement xmlPredicate;
            lock (locker)
            {
                xmlPredicate = serializer.Serialize(Efma);
            }
            DataCenter.Service1Client Dcsc = All.GetDataCenterService();
            int rst = Dcsc.GetCount(typeof(T).ToString(), xmlPredicate);
            All.CloseDc(Dcsc);
            return rst;
        }
        public bool UpdateData(int id)
        {
            DataCenter.Service1Client Dcsc = All.GetDataCenterService();
            var l = Dcsc.UpdateData(typeof(T).ToString(), id);
            All.CloseDc(Dcsc);
            return l;
        }
    }

具体的BLL.XXX 里,代码是这样的:

static ModelPvdAd<Model.XXX> Pvd = new ModelPvdAd<Model.XXX>(x => x.Id);
        public List<Model.XXX> GetList(int pageSize, int pageIndex, Expression<Func<Model.XXX, bool>> Efma, Expression<Func<Model.XXX, int>> orderBy, bool desc, out int recordCount)
        {
            return Pvd.GetList(pageSize, pageIndex, Efma, orderBy, desc, out recordCount);
        }

这样就基本完成了,建个测试页面试一下。

Expression<Func<Model.XXX,bool>> q = x=>x.id>3 && x.id<100;
int rc;
var l = BLL.XXX.GetList(30,1,q,x=>x.id,true,out rc);

绑定到 Repeater 没有问题。
但是继续测试的时候遇到了问题。一旦表达式中含有变量,服务端就报错了。比如上边的例子改成:

int i=3,j=100,rc;
var l = BLL.XXX.GetList(30,1,x=>x.id>i && x.id<j,x=>x.id,true,out rc);

这样就不行了,原因是 表达式中的 i 和 j 在传递的时候,是临时类的变量,而不是 3 和 100。
要想知道我怎么解决的,看下一篇吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章