<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                ## 一:文起緣由 ? ? ? ? ? 寫這一篇的目的源自于最近看同事在寫wcf的時候,用特別感覺繁瑣而且云里霧里的嵌套try catch來防止client拋出異常,特別感覺奇怪,就比如下面的代碼。 ~~~ 1 public void StartNormalMarketing(int shopId, List<int> marketingIdList) 2 { 3 4 using (SendEventMarketingService.DistributeServiceClient client = new SendEventMarketingService.DistributeServiceClient()) 5 { 6 try 7 { 8 9 client.StartByMarketingIDList(shopId, marketingIdList, SendEventMarketingService.MarketingType.NormalMarketing); 10 11 } 12 catch (Exception ex) 13 { 14 LogHelper.WriteLog("常規營銷活動開啟服務", ex); 15 } 16 finally 17 { 18 try 19 { 20 client.Close(); 21 } 22 catch (Exception) 23 { 24 client.Abort(); 25 } 26 } 27 } 28 } ~~~ 看完上面的代碼,不知道你是否有什么感想?而且我還問了同事,為什么try catch要寫成這樣,同事說是根據什么書上來的什么最佳實踐,這話一說,我也不敢輕易 懷疑了,只能翻翻源代碼看看這話是否有道理,首先我來說說對這段代碼的第一感覺。。。 1\. 代碼特別繁瑣   我們寫代碼,特別不喜歡繁瑣,上面的代碼就是一例,你try catch就try catch,還在finally中嵌套一個try catch,真的有點感覺像吃了兩只癩蛤蟆一樣。。。 2\. 混淆close和abort的用法     這種代碼給人的感覺就是為什么不精簡一下呢???比如下面這樣,起碼還可以少寫一對try catch,對吧。 ~~~ 1 public void StartNormalMarketing(int shopId, List<int> marketingIdList) 2 { 3 4 using (SendEventMarketingService.DistributeServiceClient client = new SendEventMarketingService.DistributeServiceClient()) 5 { 6 try 7 { 8 9 client.StartByMarketingIDList(shopId, marketingIdList, SendEventMarketingService.MarketingType.NormalMarketing); 10 11 client.Close(); 12 } 13 catch (Exception ex) 14 { 15 LogHelper.WriteLog("常規營銷活動開啟服務", ex); 16 17 client.Abort(); 18 } 19 } 20 } ~~~ 而且乍一看這段代碼和文中開頭那一段代碼貌似實現一樣,但是某些人的“最佳實踐”卻不是這樣,所以確實會導致我這樣的后來人犯迷糊,對吧。。。反正我就是頭暈, 簡直就是弄糊涂到什么時候該用close,什么時候該用abort。。。 ## 二:探索原理   為了弄明白到底可不可以用一個try catch來替代之,下面我們一起研究一下。 1\. ?從代碼注釋角度甄別     從類庫的注釋中,可以比較有意思的看出,abort方法僅僅比close多一個“立即”,再無其他,有意思,不過這對我來說并沒有什么卵用,因為這個注釋太 籠統了,為了讓自己更加徹底的明白,只能來翻看下close和abort的源代碼。 ![](https://box.kancloud.cn/2015-08-04_55c0b4348a89e.png) 2\. ?從源碼角度甄別   為了方便讓ILSpy調試Client代碼,現在我決定用ChannelFactory來代替,如下圖: ~~~ 1 namespace ConsoleApplication1 2 { 3 class Program 4 { 5 static void Main(string[] args) 6 { 7 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(); 8 9 try 10 { 11 var channel = factory.CreateChannel(); 12 13 factory.Close(); 14 } 15 catch (Exception ex) 16 { 17 factory.Abort(); 18 } 19 } 20 } 21 } ~~~ 為了讓大家更好的理解,我把close方法的源碼提供如下: ~~~ 1 // System.ServiceModel.Channels.CommunicationObject 2 [__DynamicallyInvokable] 3 public void Close(TimeSpan timeout) 4 { 5 if (timeout < TimeSpan.Zero) 6 { 7 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("timeout", SR.GetString("SFxTimeoutOutOfRange0"))); 8 } 9 using ((DiagnosticUtility.ShouldUseActivity && this.TraceOpenAndClose) ? this.CreateCloseActivity() : null) 10 { 11 CommunicationState communicationState; 12 lock (this.ThisLock) 13 { 14 communicationState = this.state; 15 if (communicationState != CommunicationState.Closed) 16 { 17 this.state = CommunicationState.Closing; 18 } 19 this.closeCalled = true; 20 } 21 switch (communicationState) 22 { 23 case CommunicationState.Created: 24 case CommunicationState.Opening: 25 case CommunicationState.Faulted: 26 this.Abort(); 27 if (communicationState == CommunicationState.Faulted) 28 { 29 throw TraceUtility.ThrowHelperError(this.CreateFaultedException(), Guid.Empty, this); 30 } 31 goto IL_174; 32 case CommunicationState.Opened: 33 { 34 bool flag2 = true; 35 try 36 { 37 TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 38 this.OnClosing(); 39 if (!this.onClosingCalled) 40 { 41 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosing"), Guid.Empty, this); 42 } 43 this.OnClose(timeoutHelper.RemainingTime()); 44 this.OnClosed(); 45 if (!this.onClosedCalled) 46 { 47 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosed"), Guid.Empty, this); 48 } 49 flag2 = false; 50 goto IL_174; 51 } 52 finally 53 { 54 if (flag2) 55 { 56 if (DiagnosticUtility.ShouldTraceWarning) 57 { 58 TraceUtility.TraceEvent(TraceEventType.Warning, 524292, SR.GetString("TraceCodeCommunicationObjectCloseFailed", new object[] 59 { 60 this.GetCommunicationObjectType().ToString() 61 }), this); 62 } 63 this.Abort(); 64 } 65 } 66 break; 67 } 68 case CommunicationState.Closing: 69 case CommunicationState.Closed: 70 goto IL_174; 71 } 72 throw Fx.AssertAndThrow("CommunicationObject.BeginClose: Unknown CommunicationState"); 73 IL_174:; 74 } 75 } ~~~ 然后我提供一下Abort代碼: ~~~ 1 // System.ServiceModel.Channels.CommunicationObject 2 [__DynamicallyInvokable] 3 public void Abort() 4 { 5 lock (this.ThisLock) 6 { 7 if (this.aborted || this.state == CommunicationState.Closed) 8 { 9 return; 10 } 11 this.aborted = true; 12 this.state = CommunicationState.Closing; 13 } 14 if (DiagnosticUtility.ShouldTraceInformation) 15 { 16 TraceUtility.TraceEvent(TraceEventType.Information, 524290, SR.GetString("TraceCodeCommunicationObjectAborted", new object[] 17 { 18 TraceUtility.CreateSourceString(this) 19 }), this); 20 } 21 bool flag2 = true; 22 try 23 { 24 this.OnClosing(); 25 if (!this.onClosingCalled) 26 { 27 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosing"), Guid.Empty, this); 28 } 29 this.OnAbort(); 30 this.OnClosed(); 31 if (!this.onClosedCalled) 32 { 33 throw TraceUtility.ThrowHelperError(this.CreateBaseClassMethodNotCalledException("OnClosed"), Guid.Empty, this); 34 } 35 flag2 = false; 36 } 37 finally 38 { 39 if (flag2 && DiagnosticUtility.ShouldTraceWarning) 40 { 41 TraceUtility.TraceEvent(TraceEventType.Warning, 524291, SR.GetString("TraceCodeCommunicationObjectAbortFailed", new object[] 42 { 43 this.GetCommunicationObjectType().ToString() 44 }), this); 45 } 46 } 47 } ~~~ 仔細觀察完這兩個方法,你會發現什么呢???至少我可以提出下面四個問題: 1:Abort是Close的子集嗎?   ?是的,因為如果你看懂了Close,你會發現Close只針對Faulted 和Opened做了判斷,而其中在Faulted的枚舉下會調用原生的Abort方法。。。如下圖 ![](https://box.kancloud.cn/2015-08-04_55c0b435bf3fc.png) 2:我能監視Client的各種狀態嗎?比如Created,Opening,Fault,Closed等等。。。    當然可以了,wcf的信道老祖宗就是ICommunicationObject,而它就有5種監聽事件,這些就可以隨時監聽,懂伐??? ![](https://box.kancloud.cn/2015-08-04_55c0b435de7b2.png) ~~~ 1 static void Main(string[] args) 2 { 3 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:1920/HomeServie")); 4 5 try 6 { 7 factory.Opened += (o, e) => 8 { 9 Console.WriteLine("Opened"); 10 }; 11 12 factory.Closing += (o, e) => 13 { 14 Console.WriteLine("Closing"); 15 }; 16 17 factory.Closed += (o, e) => 18 { 19 Console.WriteLine("Closed"); 20 }; 21 22 var channel = factory.CreateChannel(); 23 24 var result = channel.Update(new Student() { }); 25 26 factory.Close(); 27 } 28 catch (Exception ex) 29 { 30 factory.Abort(); 31 } 32 } ~~~ 3:Abort會拋出異常嗎?   ![](https://box.kancloud.cn/2015-08-04_55c0b43681381.png) 從這個截圖中可以看到非常有意思的一段,那就是居然abort活生生的把異常給吞了。。。骨頭都不給吐出來。。。真tmd的神奇到家了,想想也有道理,因為只有 這樣,我們上層的代碼在catch中才不會二次拋出“未處理異常”了,對吧,再轉念看一下Close方法。 ![](https://box.kancloud.cn/2015-08-04_55c0b4370f33e.png) 從上面圖中可以看到,Close在遇到Faulted之后調用Abort方法,如果說Abort方法調用失敗,Close方法會再次判斷狀態,如果還是Faulted的話,就會向上拋出 異常。。。這就是為什么Abort不會拋異常,Close會的原因,所以Close千萬不要放在Catch塊中。 4\. Abort代碼大概都干了些什么   這個問題問的好,要能完美解決的話,我們看下代碼,如下圖,從圖中可以看到,Abort的大目的就是用來關閉信道,具體會經過closeing,abort和closed這 三個方法,同時,這三個事件也會被老祖宗ICommunicationObject監聽的到。 ?![](https://box.kancloud.cn/2015-08-04_55c0b43831ed2.png) ![](https://box.kancloud.cn/2015-08-04_55c0b43848c7d.png) 好了,最后我們關注的一個問題在于下面這條語句是否應該放在Try塊中??? ~~~ 1 ChannelFactory<IHomeService> factory = new ChannelFactory<IHomeService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:1920/HomeServie")); ~~~ 很簡單,我們簡要的看一下代碼,看里面是否會有“異常”拋出即可。。。。 ![](https://box.kancloud.cn/2015-08-04_55c0b43872351.png) 可以看到,在new的過程中可能,或許會有異常的產生,所以最好把try catch改成下面這樣。。。 ~~~ 1 class Program 2 { 3 static void Main(string[] args) 4 { 5 ChannelFactory<IHomeService> factory = null; 6 try 7 { 8 factory = new ChannelFactory<IHomeService>(new BasicHttpBinding(), new EndpointAddress("http://localhost:1920/HomeServie")); 9 10 var channel = factory.CreateChannel(); 11 12 var result = channel.Update(new Student() { }); 13 14 factory.Close(); 15 16 throw new Exception(); 17 } 18 catch (Exception ex) 19 { 20 if (factory != null) 21 factory.Abort(); 22 } 23 } 24 } ~~~ 好了,綜合我上面所說的一切,我個人覺得最好的方式應該是上面這樣,夜深了,睡覺了,晚安。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看