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到指定的路径

就能完成服务的访问了!

 

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

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

谢谢~

我真的很需要你们的支持

时间: 2024-11-05 14:42:22

SilverLight企业应用框架设计【三】服务端设计的相关文章

SilverLight企业应用框架设计【五】客户端调用服务端(使用JSON传递数据,自己实现RESTful Web服务)

来个索引 SilverLight企业应用框架设计[四]实体层设计+为客户端动态生成服务代理(自己实现RiaService) SilverLight企业应用框架设计[三]服务端设计 SilverLight企业应用框架设计[二]框架画面 SilverLight企业应用框架设计[一]整体说明   在上一节中讲到的自动生成的服务代理类核心代码,如下 public event ServiceEventHandler Completed; public void GetAllMenu() { var si

Silverlight企业应用框架设计【六】自定义系统菜单(使用自己的DataForm)

索引 SilverLight企业应用框架设计[五]客户端调用服务端(使用JSON传递数据,自己实现RESTful Web服务) SilverLight企业应用框架设计[四]实体层设计+为客户端动态生成服务代理(自己实现RiaService) SilverLight企业应用框架设计[三]服务端设计 SilverLight企业应用框架设计[二]框架画面 SilverLight企业应用框架设计[一]整体说明   首先我们设计的窗体如下 xaml代码如下: <location:BasePage x:Cl

SilverLight企业应用框架设计【一】整体说明

Silverlight企业应用框架设计[六]自定义系统菜单(使用自己的DataForm) SilverLight企业应用框架设计[五]客户端调用服务端(使用JSON传递数据,自己实现RESTful Web服务) SilverLight企业应用框架设计[四]实体层设计+为客户端动态生成服务代理(自己实现RiaService) SilverLight企业应用框架设计[三]服务端设计 SilverLight企业应用框架设计[二]框架画面 SilverLight企业应用框架设计[一]整体说明 闲言碎语~

handler-android使用netty框架与PC服务端通信,接收到内容与发送内容不同

问题描述 android使用netty框架与PC服务端通信,接收到内容与发送内容不同 例如PC端发送888,android端却收到888后面还跟着一大串以前测试时候的内容, 部分代码如下,复制时括号有些错乱请勿在意: Bootstrap configureBootstrap(Bootstrap b, EventLoopGroup g) { b.group(g) .channel(NioSocketChannel.class) .remoteAddress(parements.getString(

cxf-CXF框架实现webService服务端,如何自定义实现组包、解包功能

问题描述 CXF框架实现webService服务端,如何自定义实现组包.解包功能 10C CXF框架实现webService服务端,如何自定义实现组包.解包功能?我现在要做webService服务端接口开发,打算用CXF来实现,但是组包.解包的功能想自己来实现,CXF支持这种扩展吗?该怎么做,非常感谢知道的大侠能详细指点 解决方案 http://blog.csdn.net/xzknet/article/details/17918343

SilverLight企业应用框架设计【四】实体层设计+为客户端动态生成服务代理(自己实现RiaService)

题外话: 对不住各位,本打算年前把这个系列写完,结果由于杂务缠身一直推到年后 我特别痛恨我自己!我觉得不但对不起各位!也对不起自己. 最近烦躁不安,不能专心向学.也不知道如何是好. -- 好吧,言归正传 说个前提条件: 此项目虽然使用了silverlight 4.0 但是服务端只能在dotNet3.5下运行 这也是我们为什么自己实现riaService的原因 实体层设计 由于有这个限制条件,我们设计的实体层也有所区别 如下图为实体层的程序集(只有MenuM实体类,其他实体类未加入.) 下面来看一

SilverLight企业应用框架设计【二】框架画面

框架画面分为上中下三层 由下面一个Grid控件完成布局 <Grid x:Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition Height="60"></RowDefinition> <RowDefinition Height="*"></RowDefinition> <RowDefinition Height=

WinForm企业应用框架设计【五】系统登录以及身份验证+源码

索引 WinForm企业应用框架设计[一]界限划分与动态创建WCF服务(no svc!no serviceActivations!) WinForm企业应用框架设计[二]团队内部的约定和客户端按约定识别WCF服务 WinForm企业应用框架设计[三]框架窗体设计:动态创建菜单: WinForm企业应用框架设计[四]动态创建业务窗体 WinForm企业应用框架设计[五]系统登录以及身份验证+源码 闲话休提~ 一:登录的画面与客户端逻辑 为了在打开程序的时候先弹出登录窗体 我们修改了主窗体的构造函数

Mvc3框架调用服务端控件解决方案

原文:http://www.cnblogs.com/rushoooooo/archive/2011/04/30/2033570.html /*BY:rush date:2011年4月30日 20:17:38*/ /*说明:.net mvc3框架,View层调用服务端控件,输出到.cshtml文件中显示*/ 1.先说说.net mvc2以前版本以及普通.net网页窗口的使用方式,即没有使用Razor模板以前使用服务端控件的方法.(这里以TreeView控件为例) 新建一个.aspx文件,点击设计视