SilverLight企业应用框架设计【三】服务端设计

一:缓存服务类型与方法

客户端请求的时候

为了方便的知道请求的类型与类型所包含的方法

我们把服务类型和方法缓存到静态字典中了

代码如下

    public class WCFRouteTable

    {

        static Dictionary<string, Type> routeService;

        static Dictionary<string, MethodInfo> routeMethods;

        static WCFRouteTable()

        {

            routeService = new Dictionary<string, Type>();

            routeMethods = new Dictionary<string, MethodInfo>();

            var ass = (typeof(WCFRouteTable)).Assembly;

            var ts = ass.GetTypes();

            foreach (var t in ts)

            {

                if (t.FullName.StartsWith("RTMDemo.Host.WCF"))

                {

                    routeService.Add(t.FullName, t);

                    foreach (var m in t.GetMethods())

                    {

                        var mName = string.Format("{0}.{1}", t.FullName, m.Name);

                        routeMethods.Add(mName, m);

                    }

                }

            }

        }

        public static Type GetWCFType(string key)

        {

            Type result = null;

            if (routeService.ContainsKey(key))

            {

                result = routeService[key];

            }

            return result;

        }

        public static MethodInfo GetMethodInfo(string key)

        {

            MethodInfo result = null;

            if (routeMethods.ContainsKey(key))

            {

                result = routeMethods[key];

            }

            return result;

        }



    }

二:托管HTTP请求

在webconfig中增加module以托管请求

    <modules>

            <add name="WcfHttpModule" type="RTMDemo.Host.WCFHttpModule, RTMDemo.Host"/>

    </modules>

托管请求对应的类的代码如下

    public class WCFHttpModule:IHttpModule

    {

        public void Dispose() { }

        /// <summary>

        /// 托管请求

        /// </summary>

        /// <param name="context"></param>

        public void Init(HttpApplication context)

        {

            context.BeginRequest += (sender, args) =>

            {

                string relativeAddress = HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.Remove(0, 2);

                Type serviceType = WCFRouteTable.GetWCFType(relativeAddress);

                if (null == serviceType)

                {

                    return;

                }

                IHttpHandler handler = new WCFHandler(serviceType);

                context.Context.RemapHandler(handler);

            };

        }

    }

通过这行代码

Type serviceType = WCFRouteTable.GetWCFType(relativeAddress);

用户只要请求如下路径

http://localhost/RTMDemo.Host/RTMDemo.Host.WCF.MenuService

就会得到MenuService的类型

然后把服务类型传给指定的处理程序

三:处理请求

在WCFHandler类中最重要的莫过于

处理请求的方法

代码如下

/// <summary>

        /// 处理请求

        /// </summary>

        /// <param name="context"></param>

        public void ProcessRequest(HttpContext context)

        {

            try

            {

                List<object> paramList = new List<object>();

                JavaScriptSerializer jss = new JavaScriptSerializer();

                var MethodKey = context.Request["MethodKey"];

                var minfo = WCFRouteTable.GetMethodInfo(MethodKey);

                var si = new MethodInvoker(minfo);

                ParameterInfo[] ps = minfo.GetParameters();

                var pstrs = context.Request.Form.AllKeys.OrderBy(m=>m).ToArray();

                var pIndex = 0;

                for(var i=0;i<pstrs.Length;i++)

                {

                    if (string.IsNullOrEmpty(pstrs[i]))

                    {

                        continue;

                    }

                    if (pstrs[i].StartsWith("p"))

                    {

                        var pStr = context.Request[pstrs[i]];

                        var obj = jss.Deserialize<object>(pStr);

                        var bts = Encoding.UTF8.GetBytes(pStr);

                        MemoryStream mss = new MemoryStream(Encoding.UTF8.GetBytes(pStr));

                        DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(ps[pIndex].ParameterType);                

                        var p = jsonSerializer.ReadObject(mss);

                        paramList.Add(p);

                        pIndex += 1;

                    }

                }



                //todo:此处性能不佳

                var instance = Activator.CreateInstance(ServiceType);

                var result = si.Execute(instance,paramList.ToArray());

                var ss = jss.Serialize(result);



                context.Response.ClearContent();

                context.Response.ContentEncoding = Encoding.UTF8;

                context.Response.ContentType = "application/json; charset=utf-8";

                context.Response.Write(ss);

                context.Response.Flush();

            }

            catch

            {

                context.Response.Write("我们不提供此服务的元数据~<br />");

                context.Response.Write("@@@@@@~<br />@@@@@@@~");

                return;

            }

        }

    }

注意:首先说这段代码还有很大的优化空间;也未经过严格的测试;但思路基本就是这样的

处理请求主要做了如下几步工作:

1.

先根据请求POST上来的信息得到准备执行的方法

var MethodKey = context.Request["MethodKey"];
var minfo = WCFRouteTable.GetMethodInfo(MethodKey);

MethodInvoker稍后再讲

2.

按顺序取出了方法的参数,并用DataContractJsonSerializer反序列化成对象

方法参数都是用JSON字符串传递的

3.

通过反射创建了服务的实例

然后调用该实例的方法

得到方法的返回值,并序列化成JSON字符串

4.

把返回值以JSON的形式输出给客户端

四:其他

1.

MethodInvoker是用的老赵的类;具体是哪篇文章,我已经找不到了。

public class MethodInvoker

    {

        private Func<object, object[], object> m_execute;



        public MethodInvoker(MethodInfo methodInfo)

        {

            this.m_execute = this.GetExecuteDelegate(methodInfo);

        }



        public object Execute(object instance, params object[] parameters)

        {

            return this.m_execute(instance, parameters);            

        }



        private Func<object, object[], object> GetExecuteDelegate(MethodInfo methodInfo)

        {

            ParameterExpression instanceParameter = Expression.Parameter(typeof(object), "instance");

            ParameterExpression parametersParameter = Expression.Parameter(typeof(object[]), "parameters");



            List<Expression> parameterExpressions = new List<Expression>();

            ParameterInfo[] paramInfos = methodInfo.GetParameters();

            for (int i = 0; i < paramInfos.Length; i++)

            {

                var ce = Expression.Constant(i);

                BinaryExpression valueObj = Expression.ArrayIndex(parametersParameter,ce);

                UnaryExpression valueCast = Expression.Convert(valueObj, paramInfos[i].ParameterType);

                parameterExpressions.Add(valueCast);

            }

            var instanceE = Expression.Convert(instanceParameter, methodInfo.ReflectedType);

            Expression instanceCast = methodInfo.IsStatic ? null : instanceE;

            MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, parameterExpressions);

            if (methodCall.Type == typeof(void))

            {

                Expression<Action<object, object[]>> lambda = Expression.Lambda<Action<object, object[]>>(methodCall, instanceParameter, parametersParameter);

                Action<object, object[]> execute = lambda.Compile();

                return (instance, parameters) =>

                {

                    execute(instance, parameters);

                    return null;

                };

            }

            else

            {

                UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));

                Expression<Func<object, object[], object>> lambda =Expression.Lambda<Func<object, object[], object>>(castMethodCall, instanceParameter, parametersParameter);

                return lambda.Compile();

            }

        }

    }

2.

服务类和数据访问的类没有什么特殊的

我这里只公布一个服务的类

    public class MenuService

    {

        public List<MenuM> GetAllMenu()

        {            

            using (var DA = new MenuDA())

            {

                var result = DA.GetAllMenu();

                return result;

            }

        }

        public void DelMenu(Guid Id)

        {

            using (var DA = new MenuDA())

            {

                DA.DelMenu(Id);

            }

        }

        public void AddMenu(MenuM m)

        {

            using (var DA = new MenuDA())

            {

                DA.AddMenu(m);

            }

        }

        public void UpdateMenu(MenuM m)

        {

            using (var DA = new MenuDA())

            {

                DA.UpdateMenu(m);

            }

        }

    }

MenuDa就是数据访问类了

很普通,就不在公布代码了

3.

完成这些工作之后

我们只要在客户端构造好表单

然后把表单POST到指定的路径

就能完成服务的访问了!

 

---------------------------------------------------------------

喜欢的话~请大家推荐我的文章

谢谢~

我真的很需要你们的支持

你可能感兴趣的:(silverlight)