统一客户端调用入口 借助反射和委托
在做MVC项目或者WebAPI项目时,经常会遇到JS和后台动态交互的情况,按照以前的逻辑是每个请求对应不同的URL(即不同的后台Action),久而久之造成很难维护的局面,让人尴尬万分,
$.get("/Home/Action4", { item1: "1" }, function (data) { alert(data); }); $.get("/Home/Action3", { item1: "2" }, function (data) { alert(data); }); $.get("/Home/Action2", { item1: "3" }, function (data) { alert(data); }); $.get("/Home/Action1", { item1: "4" }, function (data) { alert(data); });
每个页面有几个交互,不同的页面又有很多不同的交互,每个模块。。。。。。。 但是现在借助伟大的.net平台提供的反射和委托机制,我们终于可以改变这种混乱的局面,统一前端和后台数据交互的入口: 优势自不必说,下面是一个测试案例: 前端Ajax请求部分:
<script type="text/Javascript"> $.get("/Home/DynamicEnvoke", { item1: "NumChars|OneString|4362846327846328" }, function (data) { alert(data); }); $.get("/Home/DynamicEnvoke", { item1: "SubTract|TwoInt32s|2|1" }, function (data) { alert(data); });</script>
既然是统一入口,所以可以看到URL不再变化,变化的只是传入的参数,每个参数用|分隔,至于客户端的URL可以封装成常量或其他办法。 DynamicEnvoke是什么? 一个后台的入口Public的方法,传递的参数仅仅是一个字符串类型的参数,这里可以重写Model绑定机制来支持更高级的模型类型(如数组、集合、字典,复杂类型,具体参考
public object DynamicEnvoke(string item1) { var args = item1.Split('|'); Type deltype = Type.GetType(args[1]); if (deltype == null) { Console.WriteLine("invalid deltype args"); return null; } Delegate del = null; try { var mi = typeof(HomeController).GetMethod(args[0], BindingFlags.NonPublic | BindingFlags.Static); del = Delegate.CreateDelegate(deltype, mi); } catch (Exception ex) { Console.WriteLine(ex.ToString()); return null; } object[] callbackargs = new object[args.Length - 2]; if (del.GetType() == typeof(TwoInt32s)) { for (int i = 2; i < args.Length; i++) { callbackargs[i - 2] = Int32.Parse(args[i]); } } else if (del.GetType() == typeof(OneString)) { Array.Copy(args, 2, callbackargs, 0, callbackargs.Length); } var result = del.DynamicInvoke(callbackargs); return result; }
这是整个解决方案的关键所在,主要是构建一个Delegate对象然后调用DynamicInvoke方法,调用DynamicInvoke时,它会保证在内部传递的参数与回调方法期望的参数一致,否则抛出异常, 执行完成后返回回调方法的返回值,当然了这只是一个测试的示例,还有很多需要修改和完善的地方。 后台完整代码:
using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Web;using System.Web.Mvc;internal delegate object TwoInt32s(Int32 n1, Int32 n2);internal delegate object OneString(string str);namespace MvcApplication1.Controllers{ public class HomeController : Controller { public object DynamicEnvoke(string item1) { var args = item1.Split('|'); Type deltype = Type.GetType(args[1]); if (deltype == null) { Console.WriteLine("invalid deltype args"); return null; } Delegate del = null; try { var mi = typeof(HomeController).GetMethod(args[0], BindingFlags.NonPublic | BindingFlags.Static); del = Delegate.CreateDelegate(deltype, mi); } catch (Exception ex) { Console.WriteLine(ex.ToString()); return null; } object[] callbackargs = new object[args.Length - 2]; if (del.GetType() == typeof(TwoInt32s)) { for (int i = 2; i < args.Length; i++) { callbackargs[i - 2] = Int32.Parse(args[i]); } } else if (del.GetType() == typeof(OneString)) { Array.Copy(args, 2, callbackargs, 0, callbackargs.Length); } var result = del.DynamicInvoke(callbackargs); return result; } public ViewResult Home() { return View(); } private static object Add(int n1, int n2) { return n1 + n2; } private static object SubTract(Int32 n1, Int32 n2) { return n1 - n2; } private static object NumChars(string str) { return str.Length; } private static object Reverse(string str) { Char[] chars = str.ToCharArray(); Array.Reverse(chars); return new String(chars); } }}
前端完成代码:
@{ ViewBag.Title = "Home";}<script src="~/Content/jquery-1.9.1.min.js"></script><script type="text/Javascript"> $.get("/Home/DynamicEnvoke", { item1: "NumChars|OneString|4362846327846328" }, function (data) { alert(data); }); $.get("/Home/DynamicEnvoke", { item1: "SubTract|TwoInt32s|2|1" }, function (data) { alert(data); });</script>
下面送上一首情诗:《花痴》 |