本方案解決了下面3個主要的問題:數組
一、減小配置,爲了不每次新增service都須要去修改配置文件,包括服務器端跟各個客戶端的。服務器
二、可以使用函數重載,泛型函數,以及泛型類。框架
三、使項目可以快速地在wcf與直接調用dll之間切換。ide
整個解決方案分爲四塊內容:一、客戶端,二、契約層,三、服務端,四、實現層函數
一、客戶端:只能看到契約層,而看不到具體的實現;但也能夠經過直接引用實現層,從而脫離wcf(須要修改工廠方法,也能夠改進一下,經過配置文件來作這個事情,但這個不是本解決方案的重點,有興趣的能夠本身去實現)。單元測試
二、契約層:包含DTO對象模型跟各個服務接口測試
三、服務端:能看到契約層跟實現層編碼
四、實現層:使用Autofac跟Castle.DynamicProxy進行IOC跟AOP(動態代理中的攔截器)spa
爲解決第一個問題,早些年,已有人經過只暴露WCF的一個服務,而向該服務傳遞類名,函數名,參數數組來解決這一問題,可是用字符串在我看來實在是不太好,誰能保證本身在編碼的時候不會把字符串給寫錯呢,並且萬一須要更改服務名,vs的代碼重構機制也處理不了字符串。因此我以爲利用接口,應該是最好的解決方案,但問題是誰又能在不知道具體的實現類的狀況下,而針對接口憑空實例化出來一個對象呢。答案是有的,用Emit指令,不過Emit指令實在是有點難。此時我又想到了單元測試中經常使用的Rhino Mocks跟moq框架,便去查看了它們的源代碼,我發現其中一個用的.net自帶的真實代理(RealProxy),另外個用的是Castle.DynamicProxy,我的比較喜歡Castle.DynamicProxy,就用了它的CreateInterfaceProxyWithoutTarget,而後在自定義的攔截器中去調用實際的WCF服務,將返回回來的值設置給invocation.ReturnValue。.net
而且針對方法中的傳引用的參數,進行了處理,使其可以對傳引用的參數進行賦值。
下圖爲整個解決方案的結構:
測試的接口:
1 public interface IMyTest 2 { 3 int Test1(); 4 void Test2(); 5 int Test3(int value); 6 TestModel Test4(ref TestModel T); 7 void Test5(TestModel T); 8 void Test6(out int value); 9 void Test7(ref int value); 10 int Test8(int value = 8); 11 int Test9(int value1 = 0, int value2 = 0); 12 int Test10(params int[] values); 13 int Test11(ref List<int> lst); 14 int Test12(TestEnumModel m); 15 TestEnumModel Test13(TestEnumModel m); 16 T Test14<T>(T m); 17 string Test14<T>(T m, int value); 18 string Test14<T>(T m, string value); 19 string Test14<T>(T m, TestModel model); 20 }
1 public interface IMyTest2<T> 2 { 3 T Test(T aa); 4 }
DTO對象:
1 public class TestModel 2 { 3 public int A { get; set; } 4 } 5 6 public class TestImpModel : TestModel 7 { 8 public string B { get; set; } 9 } 10 11 public enum TestEnumModel 12 { 13 A = 0, 14 B = 1 15 }
具體實現:
1 internal class MyTest : IMyTest 2 { 3 public int Test1() 4 { 5 return 1; 6 } 7 8 public void Test2() 9 { 10 11 } 12 13 public int Test3(int value) 14 { 15 return value + 1; 16 } 17 18 public TestModel Test4(ref TestModel T) 19 { 20 T.A = T.A + 1; 21 return T; 22 } 23 24 public void Test5(TestModel T) 25 { 26 T.A = T.A + 1; 27 } 28 29 public void Test6(out int value) 30 { 31 value = 3; 32 } 33 34 public void Test7(ref int value) 35 { 36 value++; 37 } 38 39 40 public int Test8(int value = 8) 41 { 42 return value; 43 } 44 45 46 public int Test9(int value1 = 0, int value2 = 0) 47 { 48 return value1 + value2; 49 } 50 51 52 public int Test10(params int[] values) 53 { 54 return values.Sum(); 55 } 56 57 58 public int Test11(ref List<int> lst) 59 { 60 lst.Add(3); 61 return lst.Sum(); 62 } 63 64 public int Test12(TestEnumModel m) 65 { 66 return (int)m; 67 } 68 69 public TestEnumModel Test13(TestEnumModel m) 70 { 71 return m; 72 } 73 74 public T Test14<T>(T m) 75 { 76 return m; 77 } 78 79 public string Test14<T>(T m, int value) 80 { 81 return m.ToString() + value.ToString(); 82 } 83 84 public string Test14<T>(T m, string value) 85 { 86 return m.ToString() + value; 87 } 88 89 public string Test14<T>(T m, TestModel model) 90 { 91 model.A += 1; 92 return m.ToString() + model.A.ToString(); 93 } 94 }
1 internal class MyTest2<T> : IMyTest2<T> 2 { 3 public T Test(T aa) 4 { 5 return aa; 6 } 7 }
測試用例:
1 [TestMethod] 2 public void TestMethod1() 3 { 4 Assert.AreEqual(1, MyCreator.Create<IMyTest>().Test1()); 5 } 6 7 [TestMethod] 8 public void TestMethod2() 9 { 10 MyCreator.Create<IMyTest>().Test2(); 11 } 12 13 [TestMethod] 14 public void TestMethod3() 15 { 16 Assert.AreEqual(4, MyCreator.Create<IMyTest>().Test3(3)); 17 Assert.AreEqual(3, MyCreator.Create<IMyTest>().Test3(2)); 18 } 19 20 [TestMethod] 21 public void TestMethod4() 22 { 23 var tm = new TestModel() { A = 2 }; 24 var t = MyCreator.Create<IMyTest>().Test4(ref tm); 25 Assert.AreEqual(3, t.A); 26 Assert.AreEqual(3, tm.A); 27 } 28 29 [TestMethod] 30 public void TestMethod5() 31 { 32 var t = new TestModel() { A = 2 }; 33 MyCreator.Create<IMyTest>().Test5(t); 34 Assert.AreEqual(2, t.A); 35 } 36 37 [TestMethod] 38 public void TestMethod6() 39 { 40 int i = 0; 41 MyCreator.Create<IMyTest>().Test6(out i); 42 Assert.AreEqual(3, i); 43 } 44 45 [TestMethod] 46 public void TestMethod7() 47 { 48 int i = 0; 49 MyCreator.Create<IMyTest>().Test7(ref i); 50 Assert.AreEqual(1, i); 51 } 52 53 [TestMethod] 54 public void TestMethod8() 55 { 56 Assert.AreEqual(8, MyCreator.Create<IMyTest>().Test8()); 57 } 58 59 [TestMethod] 60 public void TestMethod9() 61 { 62 Assert.AreEqual(12, MyCreator.Create<IMyTest>().Test9(value2: 12)); 63 } 64 65 [TestMethod] 66 public void TestMethod10() 67 { 68 Assert.AreEqual(3, MyCreator.Create<IMyTest>().Test10(1, 2)); 69 } 70 71 [TestMethod] 72 public void TestMethod11() 73 { 74 List<int> lst = new List<int>(); 75 Assert.AreEqual(3, MyCreator.Create<IMyTest>().Test11(ref lst)); 76 Assert.AreEqual(1, lst.Count); 77 Assert.AreEqual(3, lst[0]); 78 } 79 80 [TestMethod] 81 public void TestMethod12() 82 { 83 Assert.AreEqual(1, MyCreator.Create<IMyTest>().Test12(TestEnumModel.B)); 84 } 85 86 [TestMethod] 87 public void TestMethod13() 88 { 89 Assert.AreEqual(TestEnumModel.B, MyCreator.Create<IMyTest>().Test13(TestEnumModel.B)); 90 } 91 92 [TestMethod] 93 public void TestMethod14() 94 { 95 Assert.AreEqual(TestEnumModel.B, MyCreator.Create<IMyTest>().Test14(TestEnumModel.B)); 96 } 97 98 [TestMethod] 99 public void TestMethod15() 100 { 101 Assert.AreEqual("B123", MyCreator.Create<IMyTest>().Test14(TestEnumModel.B, 123)); 102 } 103 104 [TestMethod] 105 public void TestMethod16() 106 { 107 Assert.AreEqual("Baaaaa", MyCreator.Create<IMyTest>().Test14(TestEnumModel.B, "aaaaa")); 108 } 109 110 [TestMethod] 111 public void TestMethod17() 112 { 113 TestImpModel m = new TestImpModel() { A = 1, B = "3" }; 114 Assert.AreEqual("B2", MyCreator.Create<IMyTest>().Test14(TestEnumModel.B, m)); 115 Assert.AreEqual(1, m.A); 116 Assert.AreEqual("3", m.B); 117 } 118 119 [TestMethod] 120 public void TestMethod18() 121 { 122 TestImpModel m = new TestImpModel() { A = 1, B = "3" }; 123 var n = MyCreator.Create<IMyTest2<TestImpModel>>().Test(m); 124 Assert.AreEqual(1, n.A); 125 Assert.AreEqual("3", n.B); 126 }
項目源代碼:DynamicWCF.rar