tag:blogger.com,1999:blog-59037478190261435612024-03-13T19:45:57.307+08:00Geeky RuleBruce Zhang's Blog about Software & LifeBruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.comBlogger47125tag:blogger.com,1999:blog-5903747819026143561.post-9595143941204161992011-07-21T17:03:00.001+08:002011-07-21T17:03:27.799+08:00Autonomous and Intelligent Object<p>I insist on that the object must be autonomous, that means it should own its data and behavior that can express its features. It will responsible for managing its data and state. The autonomous object reflects the basic principle of OO, that is "The data and the related behaviors should be encapsulated together." The object which owns the behaviors is smart, it is like it has a general sense, to judge for itself, without other objects informing. Other hand, the object should be an expert who can handle and manage its data. <p>For example, we need handle the parameters which are submitted by the customer to fetch the parameter objects we want to get in our project. The values of these parameters are placed in the web request. In advance we have get the information of parameter type according to the configuration. We provide three kinds of parameter:<br>1. Simple Parameter<br>2. Item Parameter<br>3. Table Parameter <p>I have defined the ParameterGraph class which can read the configuration info and create the concrete parameter subclass object by the parameter type. These parameter classes extends the same abstract class ParameterBase, and the ParameterBase implements the Parameter interface. The class diagram is as below: <p><a href="http://lh4.ggpht.com/-IDX6nkh-6r0/TifrV89BvAI/AAAAAAAAAVM/GPRKvvvmXoo/s1600-h/parameter%25255B3%25255D.png"><img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="parameter" border="0" alt="parameter" src="http://lh3.ggpht.com/-tfl1xp17ht0/TifrXfm-hAI/AAAAAAAAAVQ/CrpVqlG-2j8/parameter_thumb%25255B3%25255D.png?imgmax=800" width="471" height="318"></a> Because the data of parameters are stored in the web request, so we must parse the request. Essentially, the parameters in the web request are stored in the map, we should distinguish the parameters according to their name, then fill the data into the corresponding parameter object. We think it is the process of collecting the data of request and assembling parameter objects. This behavior is defined in the ReportParameterAction class. At first, I implement this function like this:</p> <div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:e82e4c45-044e-4946-b830-a6ac71ac3758" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">private</span><span style="color: #000000;"> Map</span><span style="color: #000000;"><</span><span style="color: #000000;">String,Parameter</span><span style="color: #000000;">></span><span style="color: #000000;"> collectParameters(ServletRequest request, ParameterGraph parameterGraph) {<br /> </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> (Parameter para : parameterGraph.getParmaeters()) {<br /> Map</span><span style="color: #000000;"><</span><span style="color: #000000;">String,Parameter</span><span style="color: #000000;">></span><span style="color: #000000;"> paraMap </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> HashTable</span><span style="color: #000000;"><</span><span style="color: #000000;">String, Parameter</span><span style="color: #000000;">></span><span style="color: #000000;">();<br /> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (para instanceOf SimpleParameter) {<br /> String[] values </span><span style="color: #000000;">=</span><span style="color: #000000;"> request.getParameterValues(para.getName());<br /> para.setValues(values);<br /> paraMap.put(para.getName(),para);<br /> } </span><span style="color: #0000FF;">else</span><span style="color: #000000;"> {<br /> </span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (para instanceOf ItemParameter) {<br /> ItemParameter itemPara </span><span style="color: #000000;">=</span><span style="color: #000000;"> (ItemParameter)para;<br /> </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> (Item item : itemPara.getItems()) {<br /> String[] values </span><span style="color: #000000;">=</span><span style="color: #000000;"> request.getParameterValues(item.getName());<br /> item.setValues(values);<br /> }<br /> paraMap.put(itemPara.getName(),itemPara);<br /> }</span><span style="color: #0000FF;">else</span><span style="color: #000000;"> {<br /> TableParameter tablePara </span><span style="color: #000000;">=</span><span style="color: #000000;"> (TableParameter)para;<br /> String[] rows </span><span style="color: #000000;">=</span><span style="color: #000000;"><br /> request.getParameterValues(para.getRowName());<br /> String[] columns </span><span style="color: #000000;">=</span><span style="color: #000000;"><br /> request.getParameterValues(para.getColumnName());<br /> String[] dataCells </span><span style="color: #000000;">=</span><span style="color: #000000;"><br />request.getParameterValues(para.getDataCellName());<br /><br /> </span><span style="color: #0000FF;">int</span><span style="color: #000000;"> columnSize </span><span style="color: #000000;">=</span><span style="color: #000000;"> columns.size;<br /> </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> (</span><span style="color: #0000FF;">int</span><span style="color: #000000;"> i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">; i </span><span style="color: #000000;"><</span><span style="color: #000000;"> rows.size;i</span><span style="color: #000000;">++</span><span style="color: #000000;">) {<br /> </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> (</span><span style="color: #0000FF;">int</span><span style="color: #000000;"> j</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;j </span><span style="color: #000000;"><</span><span style="color: #000000;"> columns.size;j</span><span style="color: #000000;">++</span><span style="color: #000000;">) {<br /> TableParameterElement element </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> TableParameterElement();<br /> element.setRow(rows.get(i));<br /> element.setColumn(columns.get(j);<br /> element.setDataCell(dataCells[columnSize </span><span style="color: #000000;">*</span><span style="color: #000000;"> i </span><span style="color: #000000;">+</span><span style="color: #000000;"> j]);<br /> tablePara.addElement(element);<br /> }<br /> paraMap.put(tablePara.getName(),tablePara);<br /> }<br /> }<br /> }<br /> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> parameterGraph.getParameters();<br />}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p>There are different logic to handle the different kind of parameter. For instance, if we want to collect the TableParameter, we must recoginize the row, column and data cells of table, and let their names to be key of map, and the value of map is the String array in fact. When I was writting these code like this, my intuition tell me that it exists bad smell. Maybe something is going wrong? In the collectParameters() method, there is very terrible branch statement. It will determine the runtime type of parameter to choose the differant processing logic. Why should we do like this? According to the class diagram, the parameter subclasses have the different method to process the value of paramter, such as getValue(), getItems(), getElement(). These methods can not be generized into the abstract super class. So that we must downcast the concrete type to invoke the corresponding method.</p><br /><p>Now, let’s consider the issue from two perspective. First, who own the data which be processed by branch statement? These data are belong to the related parameter object except the request as the datasource for parameters. So, according to the OO principle described above, we should encapsulate these processing logic into the corresponding parameter subclass. </p><br /><p>Second, we might consider about the abstraction of parameter. Although the different parameter has the different value, and the behaviors of process these value are different also, so we can’t generalize these logic. In fact, if you agree this opinion, it means you don’t really understand the meaning of abstract. Because we focused on the details, but not analyze the interface from the perspective of common features. In the previous description, I have referred to this common feature, that is: whatever value you want to process, you want to fill these value into the parameter object essentially, as for how to fill, it belongs to the scope of implementation details. So we can define such method in the paramter interface:</p><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:a26abab3-c07a-484d-aeaf-c0b7e0a55d18" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">interface</span><span style="color: #000000;"> Parameter {<br /> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> fillData(ParameterRequest request);<br />}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p>Note, I play a trick here. Comparing between the fillData() and collectParameters() methods, they accept the different argument. In fillData() method, I provide the ParameterRequest to replace the ServletRequest. What happen?</p><br /><p>Two reasons. First, the ServletRequest interface is defined in the Servlet. If Parameter object want to use ServletRequest, it must depends on the Servlet package(Parameter and ReportParameterAction belong to two different packages, we can’t involve the dependency in the package that Parameter belong to). Second, ServletRequest interface is a huge interface, and it is difficult to implement. Consider about this situation: we want to do unit test for Parameter, it is very difficult to mock ServletRequest interface. In fact, we just want to invoke the getParameterValues() operation here. So, I provide the ParameterRequest interface:</p><br /><p><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:e1faae63-d72b-4de4-bfda-e76b9e589390" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">interface</span><span style="color: #000000;"> ParameterRequest {<br /> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> String[] getParameterValues(String name);<br />}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>Let’s continue to look at the processing of parameter. We move the processing logic into the fillData() method of each parameter subclass:<br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:7820fc69-e290-42b0-aef6-b6f8f0beca2c" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">class</span><span style="color: #000000;"> SimpleParameter </span><span style="color: #0000FF;">extends</span><span style="color: #000000;"> ParameterBase {<br /> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> fillData(ParameterRequest request) {<br /> </span><span style="color: #0000FF;">this</span><span style="color: #000000;">.setValues(request.getParameterValues(</span><span style="color: #0000FF;">this</span><span style="color: #000000;">.getName()));<br /> }<br />}<br /></span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">class</span><span style="color: #000000;"> ItemParameter </span><span style="color: #0000FF;">extends</span><span style="color: #000000;"> ParameterBase {<br /> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> fillData(ParameterRequest request) {<br /> </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> (Item item : </span><span style="color: #0000FF;">this</span><span style="color: #000000;">.getItems()) {<br /> String[] values<br />request.getParameterValues(item.getName());<br /> item.setValues(values);<br /> }<br /> }<br />}<br /></span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">class</span><span style="color: #000000;"> TableParameter </span><span style="color: #0000FF;">extends</span><span style="color: #000000;"> ParameterBase {<br /> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> fillData(ParameterRequest request) {<br /> String[] rows </span><span style="color: #000000;">=</span><span style="color: #000000;"><br /> request.getParameterValues(</span><span style="color: #0000FF;">this</span><span style="color: #000000;">.getRowName());<br /> String[] columns </span><span style="color: #000000;">=</span><span style="color: #000000;"><br /> request.getParameterValues(</span><span style="color: #0000FF;">this</span><span style="color: #000000;">.getColumnName());<br /> String[] dataCells </span><span style="color: #000000;">=</span><span style="color: #000000;"><br />request.getParameterValues(</span><span style="color: #0000FF;">this</span><span style="color: #000000;">.getDataCellName());<br /><br /> </span><span style="color: #0000FF;">int</span><span style="color: #000000;"> columnSize </span><span style="color: #000000;">=</span><span style="color: #000000;"> columns.size;<br /> </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> (</span><span style="color: #0000FF;">int</span><span style="color: #000000;"> i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">; i </span><span style="color: #000000;"><</span><span style="color: #000000;"> rows.size;i</span><span style="color: #000000;">++</span><span style="color: #000000;">) {<br /> </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> (</span><span style="color: #0000FF;">int</span><span style="color: #000000;"> j</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;j </span><span style="color: #000000;"><</span><span style="color: #000000;"> columns.size;j</span><span style="color: #000000;">++</span><span style="color: #000000;">) {<br />TableParameterElement element </span><span style="color: #000000;">=</span><span style="color: #000000;"><br /></span><span style="color: #0000FF;">new</span><span style="color: #000000;"> TableParameterElement();<br /> element.setRow(rows.get(i));<br /> element.setColumn(columns.get(j);<br /> element.setDataCell(dataCells[columnSize </span><span style="color: #000000;">*</span><span style="color: #000000;"> i </span><span style="color: #000000;">+</span><span style="color: #000000;"> j]);<br /> </span><span style="color: #0000FF;">this</span><span style="color: #000000;">.addElement(element);<br /> }<br /> }<br /> }<br />}<br /><br /></span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div>Now, these parameter objects all are autonomous objects, they can handle their data, don’t need the other object tell them. They have the ability of judge there behavior intelligently. Let’s look at the code snippet of client:</p><br /><div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E6:0ff2844a-55f8-4778-8ff5-4761813c600a" class="wlWriterEditableSmartContent"><pre style="background-color:#FFFFFF;white-space:-moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; white-space: pre-wrap; word-wrap: break-word;overflow: auto;"><span style="color: #0000FF;">private</span><span style="color: #000000;"> Map</span><span style="color: #000000;"><</span><span style="color: #000000;">String,Parameter</span><span style="color: #000000;">></span><span style="color: #000000;"> collectParameters(ServletRequest request, ParameterGraph parameterGraph) {<br /> </span><span style="color: #0000FF;">for</span><span style="color: #000000;"> (Parameter para : parameterGraph.getParmaeters()) {<br /> Map</span><span style="color: #000000;"><</span><span style="color: #000000;">String,Parameter</span><span style="color: #000000;">></span><span style="color: #000000;"> paraMap </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> HashTable</span><span style="color: #000000;"><</span><span style="color: #000000;">String, Parameter</span><span style="color: #000000;">></span><span style="color: #000000;">();<br /> para.fillData(</span><span style="color: #0000FF;">new</span><span style="color: #000000;"> ParameterRequest() {<br /> </span><span style="color: #0000FF;">public</span><span style="color: #000000;"> String[] getParameterValues(String name) {<br /> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> request.getParameterValues(name);<br /> }<br /> );<br /> }<br /> </span><span style="color: #0000FF;">return</span><span style="color: #000000;"> parameterGraph.getParameters();<br />}</span></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div><br /><p>Because the parameter itself can process its data from the request, so ReportParameterAction doesn’t consider about these complex situations. The structure of the code becomes more clear, and the responsibilities of these objects becomes more accurate. It improves the extensibility of the program due to we do the correct encapsulation to remove the branch statement. That is a benifit of autonomous object. Please keep in your mind that autonomous principle and expert pattern while you want to assign the responsibilities. </p> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-275458565663254472011-06-21T16:05:00.000+08:002011-06-21T16:05:11.702+08:00Design decides on performanceIn our legacy system, we found a stupid design decision. We provide the service of business suite for our customer. The relationship between customer and business suite is stored in the user_busi_suite table. When the administrator of system want to delete the specific business suite, the program should check whether the business suite was subscribed by user at first. If the business suite had been subscribed, it will popup the alert window to give the noticement.<br />
Guess how to implement this function in the legacy system? It fetched the all user who subscribed this suite, then draw a dicision whether delete it depending on the size of user list:<br />
<div id="codeSnippetWrapper"><pre id="codeSnippet" style="background-color: white; border-bottom-style: none; border-left-style: none; border-right-style: none; border-top-style: none; color: black; direction: ltr; font-family: 'Courier New', courier, monospace; font-size: 10pt; line-height: 12pt; margin: 0em; overflow: visible; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; width: 100%;">List<user> users = busiSuiteRepository.fetchSubsribersWith(suiteId);
<span style="color: blue;">if</span> (users == null || users.size() == 0) {
busiSuiteRepository.remove(suiteId);
}</user></pre></div>Its implementation will effect on the performance seriously. The query of the user with suite is not necessary. We should better define the property for BusinessSuite which indicates whether it was subscribed by user. Like this:<br />
<div id="codeSnippetWrapper"><pre id="codeSnippet" style="background-color: white; border-bottom-style: none; border-left-style: none; border-right-style: none; border-top-style: none; color: black; direction: ltr; font-family: 'Courier New', courier, monospace; font-size: 10pt; line-height: 12pt; margin: 0em; overflow: visible; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left; width: 100%;"><span style="color: blue;">public</span> <span style="color: blue;">class</span> BusinessSuite {
<span style="color: blue;">private</span> <span style="color: blue;">boolean</span> subscriptionFlag = false;
<span style="color: blue;">public</span> <span style="color: blue;">boolean</span> isSubscribed() {
<span style="color: blue;">return</span> subscriptionFlag;
}
<span style="color: blue;">public</span> <span style="color: blue;">void</span> subscribe() {
subscriptionFlag = true;
}
}
BusinessSuite bs = busiSuiteRepository.with(suiteId);
<span style="color: blue;">if</span> (!bs.isSubscribed()) {
busiSuiteRepository.remove(suiteId);
}</pre></div>Don't need to query the list of user, we only get the value of subsription flag to draw a decision. That's easy!Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-21877563722866839752010-07-23T11:26:00.001+08:002010-07-23T11:26:53.695+08:00SessionStore in Rails<p>Recently, I am learning how to use Rails( the version is 2.3.5,ruby version is 1.8.6). I need to use session in Rails。Considering about the scalability, we should store the session to database(MySQL 5.x). The default value of session_store in Rails is File, so we need to modify the configuration of environment.rb file which is located in config foler. The setting is:</p> <p>config.action_controller.session_store = :active_record_store</p> <p>But, unexpected progress is in the matter, when I modified the setting value, the website can not be open(Firefox), the error page is as below:<a href="http://lh5.ggpht.com/_4YVDJ1U3Hok/TEkLjG-_pFI/AAAAAAAAAUI/yL7hIlSVF5Q/s1600-h/image%5B4%5D.png"><img title="image" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="154" alt="image" src="http://lh4.ggpht.com/_4YVDJ1U3Hok/TEkLwlVcmRI/AAAAAAAAAUM/R8URIbtMK_A/image_thumb%5B2%5D.png?imgmax=800" width="564" border="0"></a>I know it must be session issue. After checking the session table in database and the configuration of session in rails, no problem was found. But when I checked the log, I found the following error information:</p> <p>Status: 500 Internal Server Error <br> Mysql::Error: Data too long for column 'session_id' at row 1: INSERT INTO `sessions` (`updated_at`, `session_id`, `data`, `created_at`) VALUES('2010-07-23 01:17:05', 'BAh7CDoPc2Vzc2lvbl9pZCIlMDNlNTg0ZDg2NjJkZmFjZTdiMjUwN2ExNmYyNGNjNjAiCmZsYXNoSUM6J0FjdG <br>lvbkNvbnRyb2xsZXI6OkZsYXNoOjpGbGFzaEhhc2h7AAY6CkB1c2VkewA6EF9jc3JmX3Rva2VuIjFWNStxMUc <br>4bThmUmJHQ3VHRGQ3Q2RJR2p1aStUejdtRmRtc0xJY1RIOUNrPQ==--6f29ea421cd0f14d5e8de70935515c26021c254f', 'BAh7AA==\n', '2010-07-23 01:17:05')</p> <p>Obviously, the crux of problem is clearly that the session_id is too long instead of configuration of session. So I checked the columns of sessions table. Its definition is:</p> <p><a href="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEkL0nMyCFI/AAAAAAAAAUQ/K7MfP_NT9Pc/s1600-h/image%5B8%5D.png"><img title="image" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="141" alt="image" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEkL4lXHgqI/AAAAAAAAAUU/sgthUHxVq2U/image_thumb%5B4%5D.png?imgmax=800" width="557" border="0"></a> However, I had setted the value of secret of session, like this:</p> <p>config.action_controller.session = { <br> :key => '_session', <br> :secret => 'f914e9b1bbdb829688de8512f5fea7d8e83fb35bfe2b56bcf1e6438d1d1b7837c532f8c2ece2a2 <br>d0e37812e9b210824089b1810a4e238a61dfd922dc9dd62521' <br>}</p> <p>Despite I changed it into shorter value, the error is still.</p> <p>Finnally, I found the answer.It is incredible but simple. That is clearing cookie in the explorer. That's OK! Now, let's query the session table:</p> <p><a href="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEkL7R3H9FI/AAAAAAAAAUY/0B-ziYPKrY0/s1600-h/image%5B12%5D.png"><img title="image" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="199" alt="image" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEkL-TPcRXI/AAAAAAAAAUc/e-7j60JyqwA/image_thumb%5B6%5D.png?imgmax=800" width="643" border="0"></a> </p> <p>The length of session_id becomes normal and the system becomes normal too. It is really a trap that is tend to be ingored. Mark it!</p> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-80264839419362737792010-07-16T23:23:00.001+08:002010-07-16T23:23:17.803+08:00Installing RadRails Plug-in in the MyEclipse<p>Preparation: Before installing it, I suggest you'd better install ruby, rails and MySQL at first. The installer package for ruby that I choose is rubyinstaller for windows version, you can download it from <a href="http://rubyinstaller.org">http://rubyinstaller.org</a>. The process of installing is very simple, you only need to follow the wizard and do it(Notice: During installing, you must make sure the checkbox of Enable RubyGems option is checked. It's the default value):</p> <p><a href="http://lh4.ggpht.com/_4YVDJ1U3Hok/TEB4BdyqSrI/AAAAAAAAARg/8el11xTfO24/s1600-h/image3.png"><img title="image" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="313" alt="image" src="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB4I7zaaHI/AAAAAAAAARk/sHNq5tSyUbo/image_thumb1.png?imgmax=800" width="400" border="0"></a> </p> <p>After installing completed, you can open the command window and input the command line: Ruby –v. If the version of ruby can be displayed normally, it proved the installing was sucessful!(The installer would add the system path for ruby automatically. And my version of ruby is 1.8.6.)</p> <p>Next, we should update Gem system. You can execute the command on the command windows: gem update –system; then we should execute the command "gem install -v=2.3.5 rails" to install Rails. After installed, you can execute the command "rails –v" to check the version of Rails.</p> <p>Now, you need to install MySQL. Please pay attention to the version number of MySQL. It seams like the MySQL adapter that ruby provided is just for 5.0 version. The version of MySQL DB that I installed is 5.0.18 for windows. You can download it from MySQL official website. Here I omitted the process of installing for MySQL. If you want to verify whether the installing is sucessful, you might input the command line as below (Suppose the username and password all are "root"):</p> <p><a href="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4KYLlr-I/AAAAAAAAARo/YB3-Qdnqqkc/s1600-h/024.jpg"><img title="02" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="366" alt="02" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4MWeJLSI/AAAAAAAAARs/_m68a_iQBVY/02_thumb2.jpg?imgmax=800" width="558" border="0"></a> </p> <p>Then we need to install the gem for mysql. The gem I choosed is mysql-2.8.1-x86-mswin32.gem. After you fetch this file and save it in the installing directory for ruby(Suppose it is c:\ruby), you can switch the current directory to c:\ruby, and execute command line:</p> <p>gem install mysql-2.8.1-x86-mswin32.gem</p> <p><a href="http://lh5.ggpht.com/_4YVDJ1U3Hok/TEB4NRTbeyI/AAAAAAAAARw/lgW18SRFN8w/s1600-h/033.jpg"><img title="03" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="367" alt="03" src="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB4O94OsII/AAAAAAAAAR0/n2tqyawVEUs/03_thumb1.jpg?imgmax=800" width="558" border="0"></a> The system will give the result it showed "Sucessfully installed". But I don't know the specfic reason that the gem installer cann't install the related document and give the error message "No definition for …".</p> <p>Now, we are going to install the RadRails plug-in, it is my topic of this article. The version of MyEclipse is 8.5. The installing steps are as below:</p> <p>1. Start MyEclipse application, and choose "MyEclipse" menu, go to "MyEclipse Configuration Center" item.</p> <p><a href="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4Q8n3JzI/AAAAAAAAAR4/HmwPDf1Hlfk/s1600-h/043.jpg"><img title="04" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="403" alt="04" src="http://lh4.ggpht.com/_4YVDJ1U3Hok/TEB4TQCiGjI/AAAAAAAAAR8/6HQosTj5yQw/04_thumb1.jpg?imgmax=800" width="558" border="0"></a></p> <p>2. Choose "Software" tag, and click the "add site" on the left side:</p> <p><a href="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4Wm9cVOI/AAAAAAAAASA/f-bB1Jt4M34/s1600-h/053.jpg"><img title="05" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="403" alt="05" src="http://lh5.ggpht.com/_4YVDJ1U3Hok/TEB4aJ640XI/AAAAAAAAASE/fANlKb25Fsw/05_thumb1.jpg?imgmax=800" width="558" border="0"></a> It will pop up the dialog box:</p> <p><a href="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4bTYte8I/AAAAAAAAASI/k9rXJPkNs_I/s1600-h/063.jpg"><img title="06" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="269" alt="06" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4cn8IPvI/AAAAAAAAASM/CcoOagAVh7I/06_thumb1.jpg?imgmax=800" width="400" border="0"></a> </p> <p></p> <p>3. Input the name of site(The naming is up to you, I choose the name "Rails") and URL:</p> <p><a title="http://download.aptana.com/tools/radrails/plugin/install/radrails-bundle" href="http://download.aptana.com/tools/radrails/plugin/install/radrails-bundle">http://download.aptana.com/tools/radrails/plugin/install/radrails-bundle</a></p> <p>4. Now, the section which name is "Personal Site" emerges from the left side. There is the name of new site "Rails":</p> <p><a href="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB4fVcof0I/AAAAAAAAASQ/he4TV0lfNGA/s1600-h/073.jpg"><img title="07" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="403" alt="07" src="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB4hyii8pI/AAAAAAAAASU/cSLTKwLMQDo/07_thumb1.jpg?imgmax=800" width="558" border="0"></a> 5. Click the site name, the system will connect to the URL and download the remoted data. It will last about one minute, then it will show the treeview structure of Rails-Aptana RadRails. Now you can click it, there should be show the message "Managed Changes:1 Change" in the Pending Changes section which locates in the bottom and right of the screen. </p> <p><a href="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4kAsWHlI/AAAAAAAAASY/6JCZWuC7Wz8/s1600-h/083.jpg"><img title="08" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="403" alt="08" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4mmpU4BI/AAAAAAAAASc/3V3ylZh2QvM/08_thumb1.jpg?imgmax=800" width="558" border="0"></a> </p> <p>6. Click "Apply 1 Change" button, the system will validate the MyEclipse at first:</p> <p> <img title="09" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="303" alt="09" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4nkWgtCI/AAAAAAAAASg/4-_Xl9zODRU/09_thumb1.jpg?imgmax=800" width="400" border="0"><a href="http://lh5.ggpht.com/_4YVDJ1U3Hok/TEB4pGv4W5I/AAAAAAAAASk/_DbRoG7-LgE/s1600-h/107.jpg"><img title="10" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="327" alt="10" src="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB4rbLYmfI/AAAAAAAAASo/ZvnQ0Vr0kdw/10_thumb3.jpg?imgmax=800" width="400" border="0"></a> Then, It will pop up the dialog box "Accept Software License". We might select it and click "Next" button:</p> <p><a href="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB4tSj49RI/AAAAAAAAASs/UQ2gO5Jfwm8/s1600-h/113.jpg"><img title="11" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="327" alt="11" src="http://lh4.ggpht.com/_4YVDJ1U3Hok/TEB4ueKyMzI/AAAAAAAAASw/ptEqZ2shsz0/11_thumb1.jpg?imgmax=800" width="400" border="0"></a>Then, click "Update" button, it is executing update operation:</p> <p><a href="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4wlgkl_I/AAAAAAAAAS0/dWHAMmyD_LY/s1600-h/123.jpg"><img title="12" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="327" alt="12" src="http://lh4.ggpht.com/_4YVDJ1U3Hok/TEB4yIwPN7I/AAAAAAAAAS4/A-sieBQrU4Q/12_thumb1.jpg?imgmax=800" width="400" border="0"></a> </p> <p></p> <p>The process will progress slowly. It is very strange that it is normal at the beginning of update operation, but the error occurs frequently at the end of operation:</p> <p><a href="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB40QCYThI/AAAAAAAAAS8/y6QL2zYbb6A/s1600-h/133.jpg"><img title="13" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="456" alt="13" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB42pfgXuI/AAAAAAAAATA/XCj9mNu0alg/13_thumb1.jpg?imgmax=800" width="558" border="0"></a> Don't worry! Please wait for a few minutes, it will pop up the dialog box to show the error information:</p> <p><a href="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB45VrobZI/AAAAAAAAATE/409yO66fR44/s1600-h/143.jpg"><img title="14" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="456" alt="14" src="http://lh4.ggpht.com/_4YVDJ1U3Hok/TEB473SkEeI/AAAAAAAAATI/Qq14tsmZ-qI/14_thumb1.jpg?imgmax=800" width="558" border="0"></a> At this time, you must click "Back" button to back the dialog box, and click "update" button again, it will restart to update. It will skip the sucessful operation and repeat the wrong operation. Unfortunally, only one wrong operation can be corrected every time, the error diaglog box is popped up as ghost. I don't know how to handle this issue, the one way that I know is to repeat the process until it corrected all wrong operation. I try to find out the reason, but I failed. The error is not related to bandwidth of network. </p> <p>This terrible process will be lasted for about two hours andsuccessful final. The system requires to restart MyEclipse.</p> <p>After installing the plug-in, the system maybe notices the user to auto-install gems, the diagram is as below:</p> <p><a href="http://lh5.ggpht.com/_4YVDJ1U3Hok/TEB498C9TZI/AAAAAAAAATM/5GiaAXrW-cI/s1600-h/15%5B7%5D.jpg"><img title="15" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="480" alt="15" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB4_p1ARsI/AAAAAAAAATQ/rpuJVzcB-3U/15_thumb%5B5%5D.jpg?imgmax=800" width="357" border="0"></a> Although I didn't try these, but I strongly suggest not to install these gems because these gems with the latest version will be conflicted with the existed version.</p> <p>To validate whether the plug-in had been installed sucessfully, and integrated with ruby, rails and MySQL, we might create the sample project to check it. At first, we will change the view in MyEclipse into RadRails:</p> <p><a href="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB5BrRcHqI/AAAAAAAAATU/dSy3qhTDHFc/s1600-h/16%5B3%5D.jpg"><img title="16" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="480" alt="16" src="http://lh5.ggpht.com/_4YVDJ1U3Hok/TEB5Dk0GnoI/AAAAAAAAATY/r0zVsJ3QSSk/16_thumb%5B1%5D.jpg?imgmax=800" width="380" border="0"></a> Then, you can create a new rails project on the ruby explorer:</p> <p><a href="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB5FlsHGnI/AAAAAAAAATc/8AgRE5WqKhY/s1600-h/17%5B3%5D.jpg"><img title="17" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="325" alt="17" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB5H5zfAWI/AAAAAAAAATg/vukcOo9DLCc/17_thumb%5B1%5D.jpg?imgmax=800" width="488" border="0"></a> Input the project name "Sample" in the pop-up dialog box, and select mysql database:</p> <p><a href="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB5JxvrOYI/AAAAAAAAATk/ijFxfa_2BJk/s1600-h/18%5B3%5D.jpg"><img title="18" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="480" alt="18" src="http://lh5.ggpht.com/_4YVDJ1U3Hok/TEB5L7iFx8I/AAAAAAAAATo/6o26l221tnk/18_thumb%5B1%5D.jpg?imgmax=800" width="504" border="0"></a>Click the "Finish" button, it will execute the rails command automaticlly and generate the related folders and files with Rails. The directory structure is as below:</p> <p><a href="http://lh4.ggpht.com/_4YVDJ1U3Hok/TEB5NzUAKRI/AAAAAAAAATs/Bb2QV9PwnNI/s1600-h/19%5B3%5D.jpg"><img title="19" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="488" alt="19" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TEB5QtKUlGI/AAAAAAAAATw/Tj9ute8Kark/19_thumb%5B1%5D.jpg?imgmax=800" width="244" border="0"></a> Now, please open the database.yaml file in the directory with "config", and modify the configuration like this(The precondition is that I had create the database "oa" in the MySQL):</p> <p><a href="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB5SCGZiVI/AAAAAAAAAT0/AI2lHR04Vrk/s1600-h/20%5B3%5D.jpg"><img title="20" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="325" alt="20" src="http://lh6.ggpht.com/_4YVDJ1U3Hok/TEB5UZz8VWI/AAAAAAAAAT4/Yt9dv9htFYo/20_thumb%5B1%5D.jpg?imgmax=800" width="569" border="0"></a> Then switch to the server window in MyEclipse, and start the server of Sample project(using WebRick server) with the default port number 3000. After server is running, you can open the explorer such as Internet Explorer or Firefox, and input the <a href="http://localhost:3000">URL:http://localhost:3000</a>:</p> <p><a href="http://lh4.ggpht.com/_4YVDJ1U3Hok/TEB5Wn81r5I/AAAAAAAAAT8/Sywj72mAfiw/s1600-h/21%5B3%5D.jpg"><img title="21" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="403" alt="21" src="http://lh4.ggpht.com/_4YVDJ1U3Hok/TEB5Y85cRsI/AAAAAAAAAUA/mtDPRl0Aukw/21_thumb%5B1%5D.jpg?imgmax=800" width="556" border="0"></a> Click the link "About your application's environment", if the information related to ruby can be display correctly, it proved the plug-in had been installed sucessfully and the development environment was prepared normally.</p> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-46603098655820581712010-07-13T11:49:00.001+08:002010-07-13T11:51:56.927+08:00Art of Object Design on MPDay<p>Last sunday, I gave a speaking as a speaker in the msup open day conference in ShangHai. My topic was <em>Art of Object Design</em>, mainly focused on low level design in the software development lifecycle. I want to dig the essence of software design deeply. As we know, there are amount of principles and patterns for software achitecting and design. It is impossible to grasp all of these. You know more, understand less. Through by analyzing the essence and core idea of design patterns and architecture patterns, I summarized seven principles including Reusability, Extensibility, Separation, Change, Simplicity, Consistency, Indirection. </p> <p><a href="http://lh5.ggpht.com/_4YVDJ1U3Hok/TDvh6AcFfSI/AAAAAAAAAQM/0PmIeCrZ3WI/s1600-h/05%5B4%5D.jpg"><img title="" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="300" alt="" src="http://lh5.ggpht.com/_4YVDJ1U3Hok/TDvh7cagy-I/AAAAAAAAAQQ/De2L161fxOE/05_thumb%5B2%5D.jpg?imgmax=800" width="400" border="0"></a><a href="http://lh3.ggpht.com/_4YVDJ1U3Hok/TDvh9uwlj9I/AAAAAAAAAQU/j8Pg2tR153Q/s1600-h/03%5B3%5D.jpg"><img title="" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="300" alt="" src="http://lh3.ggpht.com/_4YVDJ1U3Hok/TDvh-6DweTI/AAAAAAAAAQY/AnRe_L70KZE/03_thumb%5B1%5D.jpg?imgmax=800" width="400" border="0"></a> </p> <p><strong>Reusability</strong></p> <p>The most evil enemy in the software development is repeat. It results in developing repeaded so that we cann't reuse some components and functions effeciency. It would generate the bad smell of solution sprawl. How to avoid repeat? We must keep the objects to be fine-grained and high cohesion. It needs to use encapsulation reasonable. We can improve the reusability of software based on three-level: method, class and module. For instance, we can extract method or super class, define some helper class, devide modules by dependency. The following diagram demonstrates how to apply template method pattern to reuse some codes in JUnit Framework:</p> <p><a href="http://lh6.ggpht.com/_4YVDJ1U3Hok/TDviBP5u4hI/AAAAAAAAARA/migw6l_-Xys/s1600-h/image%5B52%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="346" alt="image" src="http://lh4.ggpht.com/_4YVDJ1U3Hok/TDviDXDX8bI/AAAAAAAAARE/P16yxaWbrJc/image_thumb%5B38%5D.png?imgmax=800" width="450" border="0"></a> </p> <p><strong>Extensibility</strong></p> <p>The excellence structure of software should be extensible so that we can add functions without modifying the source code. There are two meaning of extensibility. First we don't add new features to expose it, that is an extensiblity internal. We can decorate the target object or control it by providing a proxy object. Second is an extensiblity external. The inheritance and composition are the common approach. Of course, we don't forget the abstraction. For example, the Runnable interface in Java supports the extensiblity of business when you want to write the multi-thread program. </p><span style="font-weight: bold; color: rgb(0,0,128)">class</span> <span style="color: rgb(0,0,0)">MyThreadStart</span> <span style="font-weight: bold; color: rgb(0,0,128)">implements</span> <span style="color: rgb(0,0,0)">Runnable</span> <span style="color: rgb(0,0,0)">{</span><br> <span style="font-weight: bold; color: rgb(0,0,128)">public</span> <span style="font-weight: bold; color: rgb(0,0,128)">void</span> <span style="color: rgb(0,0,0)">run</span>() <span style="color: rgb(0,0,0)">{</span><br> <span style="color: rgb(0,136,0); font-style: italic">//do something</span><br> <span style="color: rgb(0,0,0)">}</span><br><span style="color: rgb(0,0,0)">}</span><br><br><span style="color: rgb(0,0,0)">Thread</span> <span style="color: rgb(0,0,0)">controller</span> <span style="color: rgb(0,0,0)">=</span> <span style="font-weight: bold; color: rgb(0,0,128)">new</span> <span style="color: rgb(0,0,0)">Thread</span>(<span style="font-weight: bold; color: rgb(0,0,128)">new</span> <span style="color: rgb(0,0,0)">ThreadStart</span>());<br><span style="color: rgb(0,0,0)">controller</span><span style="color: rgb(0,0,0)">.</span><span style="color: rgb(255,0,0)">start</span>(); <p><strong>Separation</strong></p> <p>Concern separation is the most important principle for architecting architecture. The classic patterns which embody the concern separtion are layered architecture pattern and MVC pattern. The key element of separtion is that seperating changeful resposiblity from changeless object. That is core value of SRP also. Of course, we must focus on the collaboration between objects too. The following diagrams list my opinon about separation: <img title="image" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="135" alt="image" src="http://lh6.ggpht.com/_4YVDJ1U3Hok/TDviEKauiUI/AAAAAAAAAQk/RkwOkuVcsao/image_thumb%5B28%5D.png?imgmax=800" width="406" border="0"><a href="http://lh5.ggpht.com/_4YVDJ1U3Hok/TDviE9v6vuI/AAAAAAAAAQo/2wpfBu0sLOA/s1600-h/image%5B34%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="290" alt="image" src="http://lh5.ggpht.com/_4YVDJ1U3Hok/TDviF2sK9YI/AAAAAAAAAQs/lb7GebW2bqg/image_thumb%5B22%5D.png?imgmax=800" width="406" border="0"></a> <a href="http://lh5.ggpht.com/_4YVDJ1U3Hok/TDviGxQmRCI/AAAAAAAAAQw/Mb_fWiXjIeo/s1600-h/image%5B36%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="339" alt="image" src="http://lh6.ggpht.com/_4YVDJ1U3Hok/TDviH38nVrI/AAAAAAAAAQ0/E0fWD-xPsW8/image_thumb%5B24%5D.png?imgmax=800" width="406" border="0"></a></p> <p><strong>Change</strong></p> <p>One of the inevitable thing is change in the software development. So we must find the change point when we analyze the requirement. In my experience, I think these points always are changed as below:</p> <p>1. Business Rule (Solution: Specification Pattern)</p> <p>2. Algorithm and Strategy (Solution: Strategy Pattern)</p> <p>3. Command and Request (Solution: Command Pattern)</p> <p>4. Hardware Environment (Solution: Abstraction Layer or Gateway Pattern)</p> <p>5. Protocol and Standard (Solution: Metadata)</p> <p>6. Data Schema (Solutioin: Encapsulate Data or Information Hide)</p> <p>7. Business Flow (Solution: Customize Workflow)</p> <p>8. System Configuration (Solution: Metadata or Database)</p> <p>9. User Interface and Presentation (Solution: Layered Pattern, MVC Pattern)</p> <p>10. External Services (Solution: Abstraction Layer or Service Facade)</p> <p><strong>Simplicity</strong></p> <p>There are two important principles we have always to keep in mind. These are KISS(Keep it simple and stupid) and YAGNI(You aren't gonna need it). How to simplify the complex implemention? We can use encapsulation to hide the complex implementation. The abstraction is the other way. It might unify model, and elimilate the difference. As architect, most of them want to pursue the perfect solution. It's wrong! Many anti-patterns related with this idea, such as <a href="http://en.wikipedia.org/wiki/Analysis_paralysis">Analysis Paralysis</a>, <a href="http://en.wikipedia.org/wiki/Accidental_complexity">Accidental Complexity</a>.</p> <p><strong>Consistency</strong></p> <p>So called "Consistency" includes interface, format, invoking way and solution. If we have consistant interface, so the implementation can be substituted. If we have consistant format, we can infer the overall design from the part of design. Consistant invoking way would help client understand the intention of service provider. Consistant solution is the basic of cooperation of team. For example, we can achieve the consistant invoking way by using composit pattern:</p> <p><a href="http://lh4.ggpht.com/_4YVDJ1U3Hok/TDviIy0NR0I/AAAAAAAAARI/i1L0X4sY3ko/s1600-h/image%5B51%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="318" alt="image" src="http://lh4.ggpht.com/_4YVDJ1U3Hok/TDviKn7u3HI/AAAAAAAAARM/TE4FomLzSDU/image_thumb%5B37%5D.png?imgmax=800" width="400" border="0"></a> <strong>Indirection</strong></p> <p>David Wheeler said:"All problems in computer science can be solved by another level of indirection". Indirection in software programming is achieved by delegation, abstraction and collaboration. Indirection can reduce dependence, hide the detail and simplify the client call. Many pattens are reflect the indirection thought, such as Facade Pattern, Mediator Pattern, Adapter Pattern, Strategy Pattern, Service Locator Pattern.</p> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-64301268603485176012010-07-09T17:33:00.002+08:002010-07-12T23:02:34.618+08:00Hunt a new Job<p>I changed my job recently. When I worked in a new company, I found everything is not ok. I don't like my job responsibility. As current role, I need to go out on business often, and communication with some fresh guys who don't understand what is software developing. I felt I am a cheater. That's terrible.<br /></p> <p>I need change, but the new job can't give me new opportunity and challedge. Of course, the new job can't help me improve my ability. Don't hesitate, I want to hunt a new job. </p>Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-29948263801417512792010-07-09T17:19:00.001+08:002010-07-09T17:19:44.879+08:00I am back<p>Don't ask me the reason why I don't update my blog these days. Maybe I am lazy. In fact, I can't visit the wordpress normally in China. Fortunately, one of my freinds introduce one way to handle this issue, so I am back. </p> <p>These days, I don't stop keeping my moving. I wrote and posted some articles about software in my chinese blog(<a href="http://www.agiledon.com)">http://www.agiledon.com)</a>. Well, I'll continue to write these with english version. Wait for me. Thanks.</p> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-58611594364699538272009-06-01T11:51:00.000+08:002010-07-10T11:51:31.313+08:00Stream operation in WCF<div class="main"> <div class="snap_preview"> <p>WCF provides the support for Stream object. It typically recommends the developer to handle the message which size is too large as Stream object for the sake of high performance.</p> <p>However, there are some constraints on Stream operation to note:<br>1. The constraint of Binding</p> <p>The valid bindings include BasicHttpBinding, NetTcpBinding and NetNamePipeBinding for Stream operation. In addition, we can’t use Reliable Messaging while handling the Stream object. If you are considering about the security of message, this way is not a good choice.</p> <p>2. The constraint of Stream object</p> <p>The object, you want to transport as a parameter with WCF Operation, must be serializable. Unfortunately, FileStream class can’t be serialized. We have to use Stream, MemoryStream. The Stream class is the main option for handling a stream object.</p> <p>It is very interesting of transform between FileStream and Stream class. For example, the following implementation of the operation in a service:<br><span style="color: rgb(0,0,255)">public</span><span style="color: rgb(0,0,0)"> Stream TransferDocument(Document document)<br>{<br> FileStream stream </span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,255)">new</span><span style="color: rgb(0,0,0)"> FileStream<br> (document.LocalPath, FileMode.Open, FileAccess.Read);<br> </span><span style="color: rgb(0,0,255)">return</span><span style="color: rgb(0,0,0)"> stream;<br>}</span></p> <p>Note, the type of return value of TransferDocument() method is Stream. But the ture type should be FileStream. Due to FileStream is the subclass of Stream, so it is no problem according to polymorphism of OO. When the client want to invoke TransferDocument() method, we can’t assign the return value to FileStream object in fact:<br><span style="color: rgb(0,0,0)">FileStream stream </span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)"> m_service.TransferDocument(doc);</span></p> <p>The value of stream object is null now. So we must do like this:<br><span style="color: rgb(0,0,0)">Stream stream </span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)"> m_service.TransferDocument(doc);</span></p> <p>It is strange that WCF can’t serialize the Length property of Stream object. On the client side, we can not use the Length property. If you want to do, it will throw a NotSupportedException.</p> <p>3. The constraint of TransferMode</p> <p>The default value of TransferMode is setted to Buffered. If you want to use Stream operation, you must change the default setting of TransferMode. We can set it to Streamed, StreamedRequest or StreamedResponse according to the different cases.</p> <p>4. The constraint of MaxReceiveMessage</p> <p>The default value of MaxReceiveMessage property is 64kb. If the size of transported stream object exceeds the setting value of MaxReceiveMessage, It will throw a CommunicationException during the client invokes the operation of service to handle this stream object. So we should change the value depending on the specific situation. The value ranges from 1 to 9223372036854775807(i.e. Int32.MaxValue). If the setting value is outside the range, the program can not be compiled successfully. Set its value in programmatic:<br><span style="color: rgb(0,0,0)">binding.</span>MaxReceivedMessageSize<span style="color: rgb(0,0,0)"> </span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)"> 120000</span><span style="color: rgb(0,0,0)">;</span></p> <p>And set it in administrative:<br><span style="color: rgb(0,0,0)"><</span><span style="color: rgb(0,0,0)">binding …… maxReceivedMessageSize</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">“</span><span style="color: rgb(0,0,0)">120000</span><span style="color: rgb(0,0,0)">“</span><span style="color: rgb(0,0,0)">/></span></p> <p>5. The constraint of Operation Parameters</p> <p>WCF applies the strict constraint on the parameters of operation including stream objects. There can be only one stream object as the parameter(in, out, ref parameter or return value) in the method signature. So these definitions of the method are all invalid as below:<br><span style="color: rgb(0,0,255)">void</span><span style="color: rgb(0,0,0)"> Transfer(Stream s1, Stream s2);<br></span><span style="color: rgb(0,0,255)">void</span><span style="color: rgb(0,0,0)"> Transfer(Stream s1, </span><span style="color: rgb(0,0,255)">out</span><span style="color: rgb(0,0,0)"> Stream s2);<br></span><span style="color: rgb(0,0,255)">void</span><span style="color: rgb(0,0,0)"> Transfer(Stream s1, </span><span style="color: rgb(0,0,255)">ref</span><span style="color: rgb(0,0,0)"> Stream s2);<br>Stream Transfer(Stream stream);</span></p> <p>If you define the method like above, it will occur the run-time error.</p> <p>6. The constraint of Instance Activation</p> <p>Because we can only use the BasicHttpBinding, NetTcpBinding or NetNamedPipeBinding in the stream operaiton, it will impact on the mode of instance activation, in particular Session mode. First, BasicHttpBinding doesn’t support Session mode. Secondly, although the other bindings(NetTcpBinding or NetNamedPipeBinding) support Session mode, we can’t set the value of ReliableSession to the true because the stream operation doesn’t support reliable messaging. So if you set the value of SessionMode to SessionMode.Required for the service, it will throw an exception.</p> <p>In fact, the stream operation(i.e. the value of TransferMode is not Buffered) itself doesn’t support Session mode. Even we set the value of SessionMode to Allowed, and set the value of InstanceContextMode to PerSession while using NetTcpBinding, the behavior of service is still PerCall mode. And the value of SessionId(get it through by OperationContext.Current.SessionId) should be null at this time.</p> <p>Finally, I recommend you increase the value of SendTimeOut property because the calling a large stream object will last too long time. For example, set its value to 10 minutes in programmatic:<br><span style="color: rgb(0,0,0)">binding.SendTimeout </span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)"> TimeSpan.FromMinutes(</span><span style="color: rgb(0,0,0)">10</span><span style="color: rgb(0,0,0)">);</span></p> <p>Or set it in administrative:<br><span style="color: rgb(0,0,0)"><</span><span style="color: rgb(0,0,0)">binding …… sendTimeout</span><span style="color: rgb(0,0,0)">=</span><span style="color: rgb(0,0,0)">“</span><span style="color: rgb(0,0,0)">00:10:00</span><span style="color: rgb(0,0,0)">“</span><span style="color: rgb(0,0,0)">/></span></p> <p>Note, the configuration of Binding on the service and client side must keep in consistent.</p> <p><a href="http://www.c-sharpcorner.com/UploadFile/BruceZhang/Stream-Operation-WCF06012009011758AM/Stream-Operation-WCF.aspx">This article on C# Corner</a>.</p></div></div> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-30111489029646188582009-05-17T09:08:00.001+08:002010-07-10T11:35:04.659+08:00Focus on the Extension of WCF Behavior<div class="main"> <div class="snap_preview"> <p>WCF provides the flexible and extensible architecture for the developer. The most common situation is to customize the extension of behavior. It is not complex, but some issues should be noticed. This article is prepare to discuss how to extend the behavior in WCF.</p> <p>On the service side, if we want to extend the behavior, we need to extend the <strong>DispatchRuntime</strong> and <strong>DispatchOperation</strong>. The points of extension include inspecting parameters, messages and invoker of operations. The corresponding interfaces are <strong>IParameterInspector <span style="color: rgb(255,102,0)">(</span></strong><span style="color: rgb(255,102,0)">to inspect parameters<strong>)</strong></span>, <strong>IDispatchMessageInspector</strong><span style="color: rgb(255,102,0)">(to inspect messages)</span> and <strong>IOperationInvoker</strong><span style="color: rgb(255,102,0)">(to invoke the operation)</span>. On the client side, we should extend the <strong>ClientRuntime</strong> and <strong>ClientOperation, </strong>and the points of extension include inspecting parameters and messages. The corresponding interfaces are <strong>IParameterInspector</strong> and <strong>IClientMessageInspector</strong>. All interfaces are placed in System.ServiceModel.Dispatcher namespace. Note please that <strong>IParameterInspector can be applied both service side and client side</strong>.</p> <p>It seems like implementation of <a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming">AOP</a> (Aspect Oriented Programming) to implement these interfaces. We can inject some additional logic before and after invoking the related methods, so we call these extensions “Listener”. For example, There are some methods in IParameterInspector interface as below:</p> <div style="font-size: 10pt; background: white; color: black; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">void</span> AfterCall(<span style="color: blue">string</span> operationName, <span style="color: blue">object</span>[] outputs, <span style="color: blue">object</span> returnValue, <span style="color: blue">object</span> correlationState);</p> <p style="margin: 0pt"><span style="color: blue">object</span> BeforeCall(<span style="color: blue">string</span> operationName, <span style="color: blue">object</span>[] inputs);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">BeforeCall() method will be invoked before we invoke the target method of the service object, and AfterCall() method will be occured after the target method is invoked. For instance, we can validate if the value of parameter is less than zero before the method is invoked. If yes, it will throw an exception:</p> <div style="font-size: 10pt; background: white; color: black; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">CalculatorParameterInspector</span> : <span style="color: rgb(43,145,175)">IParameterInspector</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> BeforeCall(<span style="color: blue">string</span> operationName, <span style="color: blue">object</span>[] inputs)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">int</span> x = inputs[0] <span style="color: blue">as</span> <span style="color: blue">int</span>;</p> <p style="margin: 0pt"> <span style="color: blue">int</span> y = inputs[1] <span style="color: blue">as</span> <span style="color: blue">int</span>;</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (x < 0 || y < 0)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">FaultException</span>(<span style="color: rgb(163,21,21)">“The number can not be less than zero.”</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: blue">null</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> AfterCall(<span style="color: blue">string</span> operationName, <span style="color: blue">object</span>[] outputs, <span style="color: blue">object</span> returnValue, <span style="color: blue">object</span> correlationState)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//empty;</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">It distinguishs between the service and client side to inspect the parameter, and the methods of interface are quite converse to the order of messaging(Note: IDispatchMessageInspector interface includes BeforeSendReply() and AfterReceiveRequest(); and IClientMessageInspector interface includes BeforeSendRequest() and AfterReceiveReply()). We might handle the message through by the methods of this interface, for example, printing the message header:</p> <div style="font-size: 10pt; background: white; color: black; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">PrintMessageInterceptor</span> : <span style="color: rgb(43,145,175)">IDispatchMessageInspector</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"><span style="color: blue"> #region</span> IDispatchMessageInspector Members</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">object</span> AfterReceiveRequest(<span style="color: blue">ref</span> System.ServiceModel.Channels.<span style="color: rgb(43,145,175)">Message</span> request, <span style="color: rgb(43,145,175)">IClientChannel</span> channel, <span style="color: rgb(43,145,175)">InstanceContext</span> instanceContext)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> MessageBuffer buffer = request.CreateBufferedCopy(<span style="color: rgb(43,145,175)">Int32</span>.MaxValue);</p> <p style="margin: 0pt"> request = buffer.CreateMessage();</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">Console</span>.WriteLine(<span style="color: rgb(163,21,21)">“After Receive Request:”</span>);</p> <p style="margin: 0pt"> <span style="color: blue">foreach</span> (MessageHeader header <span style="color: blue">in</span> request.Headers)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">Console</span>.WriteLine(header);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">Console</span>.WriteLine(<span style="color: blue">new</span> <span style="color: blue">string</span>(<span style="color: rgb(163,21,21)">‘*’</span>, 20));</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: blue">null</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> BeforeSendReply(<span style="color: blue">ref</span> System.ServiceModel.Channels.<span style="color: rgb(43,145,175)">Message</span> reply, <span style="color: blue">object</span> correlationState)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> MessageBuffer buffer = reply.CreateBufferedCopy(<span style="color: rgb(43,145,175)">Int32</span>.MaxValue);</p> <p style="margin: 0pt"> reply = buffer.CreateMessage();</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">Console</span>.WriteLine(<span style="color: rgb(163,21,21)">“Before Send Request:”</span>);</p> <p style="margin: 0pt"> <span style="color: blue">foreach</span> (MessageHeader header <span style="color: blue">in</span> reply.Headers)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">Console</span>.WriteLine(header);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">Console</span>.WriteLine(<span style="color: blue">new</span> <span style="color: blue">string</span>(<span style="color: rgb(163,21,21)">‘*’</span>, 20));</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><span style="color: blue"> #endregion</span></p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">There are four different kinds of behaviors including <strong>Service Behavior</strong>, <strong>Endpoint Behavior</strong>, <strong>Contract Behavior</strong> and <strong>Operation Behavior</strong>. Their corresponding interfaces are <strong>IServiceBehavior</strong>, <strong>IEndpointBehavior</strong>, <strong>IContractBehavior</strong> and <strong>IOperationBehavior</strong>. Although they are different interface by nature, but their methods are almost similar including: AddBindingParameters(), ApplyClientBehavior() and ApplyDispatchBehavior().</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><strong>Note: Because IServiceBehavior is only used on the service side, so it has no ApplyClientBehavior() method.</strong></p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">We can customize our class to implement these interface, but some key elements should be underlined:</p> <p style="margin: 0pt">1. The scope of the behavior. Table 1 describes all situations:</p> <table cellspacing="0" cellpadding="0" border="1"> <tbody> <tr> <td width="90" rowspan="2"> <p align="center">Behavior Type</p></td> <td width="126" rowspan="2"> <p align="center">Interface</p></td> <td width="302" colspan="4"> <p align="center">Scope</p></td></tr> <tr> <td width="66"> <p align="center">Service</p></td> <td width="76"> <p align="center">Endpoint</p></td> <td width="85"> <p align="center">Contract</p></td> <td width="76"> <p align="center">Operation</p></td></tr> <tr> <td width="90"> <p align="center">Service</p></td> <td width="126"> <p align="center">IServiceBehavior</p></td> <td width="66"> <p align="center">Y</p></td> <td width="76"> <p align="center">Y</p></td> <td width="85"> <p align="center">Y</p></td> <td width="76"> <p align="center">Y</p></td></tr> <tr> <td width="90"> <p align="center">Endpoint</p></td> <td width="126"> <p align="center">IEndpointBehavior</p></td> <td width="66"> <p align="center"> </p></td> <td width="76"> <p align="center">Y</p></td> <td width="85"> <p align="center">Y</p></td> <td width="76"> <p align="center">Y</p></td></tr> <tr> <td width="90"> <p align="center">Contract</p></td> <td width="126"> <p align="center">IContractBehavior</p></td> <td width="66"> <p align="center"> </p></td> <td width="76"> <p align="center"> </p></td> <td width="85"> <p align="center">Y</p></td> <td width="76"> <p align="center">Y</p></td></tr> <tr> <td width="90"> <p align="center">Operation</p></td> <td width="126"> <p align="center">IOperationBehavior</p></td> <td width="66"> <p align="center"> </p></td> <td width="76"> <p align="center"> </p></td> <td width="85"> <p align="center"> </p></td> <td width="76"> <p align="center">Y</p></td></tr></tbody></table> <p style="margin: 0pt"> </p> <p style="margin: 0pt">2. We can add the extension of service behavior, contract behavior and operation behavior by applying on custom attribute, but can not add the extension of endpoint behavior in this way. We can add the extension of service behavior and endpoint behavior by using config file, but can not add the extension of contract behavior and operation behavior in this way. All behaviors can be added by ServiceDescription.</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">To add the extended behavior by applying on custom attribute, we can let the custom behavior derived from Attribute class. Then we can apply it on service, contract or operation:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt">[<span style="color: rgb(43,145,175)">AttributeUsage</span>(<span style="color: rgb(43,145,175)">AttributeTargets</span>.Class|<span style="color: rgb(43,145,175)">AttributeTargets</span>.Interface)]</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">MyServiceBehavior</span>:<span style="color: rgb(43,145,175)">Attribute</span>, IServiceBehavior</p> <p style="margin: 0pt">{}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">[<span style="color: rgb(43,145,175)">MyServiceBehavior</span>]</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">interface</span> <span style="color: rgb(43,145,175)">IService</span></p> <p style="margin: 0pt">{ }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">If you want to add the extended behavior by using config file, you must define a class derived from BehaviorExtensionElement (It belongs to System.ServiceModel.Configuration namespace) class, then override the BehaviorType property and CreateBehavior() method. BehaviorType property returns the type of extended behavior, and CreateBehavior() is responsible for creating the instance of the extended behavior:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">MyBehaviorExtensionElement</span> : <span style="color: rgb(43,145,175)">BehaviorExtensionElement</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> MyBehaviorExtensionElement() { }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">override</span> <span style="color: rgb(43,145,175)">Type</span> BehaviorType</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">get</span> { <span style="color: blue">return</span> <span style="color: blue">typeof</span>(MyServiceBehavior); }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">protected</span> <span style="color: blue">override</span> <span style="color: blue">object</span> CreateBehavior()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: blue">new</span> MyServiceBehavior();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">If the element which should be configured add the new property, we must apply the ConfigurationPropertyAttribute on this new one:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt">[<span style="color: rgb(43,145,175)">ConfigurationProperty</span>(<span style="color: rgb(163,21,21)">"providerName"</span>, IsRequired = <span style="color: blue">true</span>)]</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">virtual</span> <span style="color: blue">string</span> ProviderName</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">get</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: blue">this</span>[<span style="color: rgb(163,21,21)">"ProviderName"</span>] <span style="color: blue">as</span> <span style="color: blue">string</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">set</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">this</span>[<span style="color: rgb(163,21,21)">"ProviderName"</span>] = <span style="color: blue">value</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">The detail of config file like this:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue"><</span><span style="color: rgb(163,21,21)">configuration</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">system.serviceModel</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">services</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">service</span><span style="color: blue"> </span><span style="color: red">name</span><span style="color: blue">=</span>“<span style="color: blue">MessageInspectorDemo.Calculator</span>“<span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">endpoint</span><span style="color: blue"> </span><span style="color: red">behaviorConfiguration</span><span style="color: blue">=</span>“<span style="color: blue"><strong>messageInspectorBehavior</strong></span>“</p> <p style="margin: 0pt"><span style="color: blue"> </span><span style="color: red">address</span><span style="color: blue">=</span>“<span style="color: blue">http://localhost:801/Calculator</span>“</p> <p style="margin: 0pt"><span style="color: blue"> </span><span style="color: red">binding</span><span style="color: blue">=</span>“<span style="color: blue">basicHttpBinding</span>“</p> <p style="margin: 0pt"><span style="color: blue"> </span><span style="color: red">contract</span><span style="color: blue">=</span>“<span style="color: blue">MessageInspectorDemo.ICalculator</span>“<span style="color: blue">/></span></p> <p style="margin: 0pt"><span style="color: blue"> </</span><span style="color: rgb(163,21,21)">service</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> </</span><span style="color: rgb(163,21,21)">services</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">behaviors</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">serviceBehaviors</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">behavior</span><span style="color: blue"> </span><span style="color: red">name</span><span style="color: blue">=</span>“<span style="color: blue">messageInspectorBehavior</span>“<span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">myBehaviorExtensionElement</span><span style="color: blue"> </span><span style="color: red"><strong>providerName</strong></span><span style="color: blue">=</span>“<span style="color: blue">Test</span>“<span style="color: blue">/></span></p> <p style="margin: 0pt"><span style="color: blue"> </</span><span style="color: rgb(163,21,21)">behavior</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> </</span><span style="color: rgb(163,21,21)">serviceBehaviors</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> </</span><span style="color: rgb(163,21,21)">behaviors</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">extensions</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">behaviorExtensions</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> <</span><span style="color: rgb(163,21,21)">add</span><span style="color: blue"> </span><span style="color: red">name</span><span style="color: blue">=</span>“<span style="color: blue">myBehaviorExtensionElement</span>“</p> <p style="margin: 0pt"><span style="color: blue"> </span><span style="color: red">type</span><span style="color: blue">=</span>“<span style="color: blue"><strong>MessageInspectorDemo.MyBehaviorExtensionElement, </strong></span></p> <p style="margin: 0pt"><span style="color: blue"><strong> MessageInspectorDemo, </strong></span></p> <p style="margin: 0pt"><span style="color: blue"><strong> Version=1.0.0.0, </strong></span></p> <p style="margin: 0pt"><span style="color: blue"><strong> Culture=neutral, </strong></span></p> <p style="margin: 0pt"><span style="color: blue"><strong> PublicKeyToken=null</strong></span>“<span style="color: blue">/></span></p> <p style="margin: 0pt"><span style="color: blue"> </</span><span style="color: rgb(163,21,21)">behaviorExtensions</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> </</span><span style="color: rgb(163,21,21)">extensions</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"> </</span><span style="color: rgb(163,21,21)">system.serviceModel</span><span style="color: blue">></span></p> <p style="margin: 0pt"><span style="color: blue"></</span><span style="color: rgb(163,21,21)">configuration</span><span style="color: blue">></span></p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><span style="color: rgb(0,0,0)">Please notes the contents which font are bold. <myBehaviorExtensionElement> is our extended behavior, and providerName</span> is the new property of MyBehaviorExtensionElement. If you extended IEndpointBehavior, <serviceBehaviors> section should be replaced with <endpointBehaviors>. The extensions of custom behaviors will be placed in the <extensions></extensions> section. The value of name attribute must match the configuration of <behavior> section, both are “myBehaviorExtensionElement”.</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">The value of type inside the <behaviorExtensions> section you want to add must be the full name of type. The first part of the full name is the full type name, and the second part of the name is the namespace. Version, Culture and PublicKeyToken are also indispensable elements. The string of type name use the comma as a splitter. <span style="color: rgb(255,102,0)"><strong>After the comma, it must left a space</strong></span>, otherwise we can not add the configuration of extended behavior normally. Why does it give the awful constraint here? Because the value is prepared for reflect technology. I agree that it is a defect. I hope microsoft will solve this problem in the next release of WCF.</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">3. In the body of related methods, we need to add the extensions of checking parameters, messages and operation invoker. The relationship between the extension of them exists here. For checking parameters, the logic of extensions might be added in ApplyClientBehavior() and ApplyDispatchBehavior() of IOperationBehavior interface. For example, we can define a CalculatorParameterValidation class for CalculatorParameterInspector:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">CalculatorParameterValidation</span> : <span style="color: rgb(43,145,175)">Attribute</span>, <span style="color: rgb(43,145,175)">IOperationBehavior</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"><span style="color: blue"> #region</span> IOperationBehavior Members</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> AddBindingParameters(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription,</p> <p style="margin: 0pt"> BindingParameterCollection bindingParameters)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> ApplyClientBehavior(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription,</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">ClientOperation</span> clientOperation)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">CalculatorParameterInspector</span> inspector = <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">CalculatorParameterInspector</span>();</p> <p style="margin: 0pt"> clientOperation.ParameterInspectors.Add(inspector);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> ApplyDispatchBehavior(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription,</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">DispatchOperation</span> dispatchOperation)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">CalculatorParameterInspector</span> inspector = <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">CalculatorParameterInspector</span>();</p> <p style="margin: 0pt"> dispatchOperation.ParameterInspectors.Add(inspector);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Validate(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"><span style="color: blue"> #endregion</span></p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p></div> <p style="margin: 0pt">If it is not necessary to seperate the inspector from the extended behavior, a better solution is to let a custom class implement both IParameterInspector and IOperationBehavior. For example:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">CalculatorParameterValidation</span> : <span style="color: rgb(43,145,175)">Attribute</span>, <span style="color: rgb(43,145,175)">IParameterInspector</span>, <span style="color: rgb(43,145,175)">IOperationBehavior</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"><span style="color: blue"> #region</span> IParameterInspector Members</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> BeforeCall(<span style="color: blue">string</span> operationName, <span style="color: blue">object</span>[] inputs)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">int</span> x = inputs[0] <span style="color: blue">as</span> <span style="color: blue">int</span>;</p> <p style="margin: 0pt"> <span style="color: blue">int</span> y = inputs[1] <span style="color: blue">as</span> <span style="color: blue">int</span>;</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (x < 0 || y < 0)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">FaultException</span>(<span style="color: rgb(163,21,21)">“The number can not be less than zero.”</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: blue">null</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> AfterCall(<span style="color: blue">string</span> operationName, <span style="color: blue">object</span>[] outputs, <span style="color: blue">object</span> returnValue, <span style="color: blue">object</span> correlationState)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//empty;</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"><span style="color: blue"> #endregion</span></p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><span style="color: blue"> #region</span> IOperationBehavior Members</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> AddBindingParameters(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription,</p> <p style="margin: 0pt"> BindingParameterCollection bindingParameters)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> ApplyClientBehavior(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription,</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">ClientOperation</span> clientOperation)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="text-decoration: line-through"><span style="color: rgb(43,145,175)">CalculatorParameterInspector</span> inspector = <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">CalculatorParameterInspector</span>();</span></p> <p style="margin: 0pt"> clientOperation.ParameterInspectors.Add(<span style="color: blue">this</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> ApplyDispatchBehavior(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription,</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">DispatchOperation</span> dispatchOperation)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="text-decoration: line-through"><span style="color: rgb(43,145,175)">CalculatorParameterInspector</span> inspector = <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">CalculatorParameterInspector</span>();</span></p> <p style="margin: 0pt"> dispatchOperation.ParameterInspectors.Add(<span style="color: blue">this</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Validate(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"><span style="color: blue"> #endregion</span></p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p></div> <p style="margin: 0pt">While operation invoker is associated with IOperationBehavior, but in fact, it will do with Invoker property of DispatchOperation. Assume that we have defined a MyOperationInvoker class which implement the IOperationInvoker interface, the solution is:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">MyOperationInvoker</span> : <span style="color: rgb(43,145,175)">IOperationInvoker</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: green">//some implementation</span></p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">MyOperationInvokerBehavior</span> : <span style="color: rgb(43,145,175)">Attribute</span>, <span style="color: rgb(43,145,175)">IOperationBehavior</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"><span style="color: blue"> #region</span> IOperationBehavior Members</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> AddBindingParameters(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription,</p> <p style="margin: 0pt"> BindingParameterCollection bindingParameters)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> ApplyClientBehavior(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription,</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">ClientOperation</span> clientOperation)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> ApplyDispatchBehavior(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription,</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">DispatchOperation</span> dispatchOperation)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> dispatchOperation.Invoker = <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">MyOperationInvoker</span>(dispatchOperation.Invoker);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Validate(<span style="color: rgb(43,145,175)">OperationDescription</span> operationDescription)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"><span style="color: blue"> #endregion</span></p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">As far as message inspecting with Dispatch are concerned, we can add it using MessageInspectors property in DispatchRuntime owned by IServiceBehavior, or IEndpointBehavior, or IContractBehavior. For message inspecting with Client, we can add in using MessageInspectors property in ClientRuntime owned by IEndpointBehavior or IContractBehavior(IServiceBehavior can not be used on the client side, so it’s not IServiceBehavior’s business). For example:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">PrintMessageInspectorBehavior</span> : <span style="color: rgb(43,145,175)">IDispatchMessageInspector</span>, <span style="color: rgb(43,145,175)">IEndpointBehavior</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"><span style="color: blue"> #region</span> IEndpointBehavior Members</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> AddBindingParameters(<span style="color: rgb(43,145,175)">ServiceEndpoint</span> endpoint, BindingParameterCollection bindingParameters)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//empty;</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> ApplyClientBehavior(<span style="color: rgb(43,145,175)">ServiceEndpoint</span> endpoint, <span style="color: rgb(43,145,175)">ClientRuntime</span> clientRuntime)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <strong>clientRuntime</strong>.<strong>MessageInspectors</strong>.Add(<span style="color: blue">this</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> ApplyDispatchBehavior(<span style="color: rgb(43,145,175)">ServiceEndpoint</span> endpoint, <span style="color: rgb(43,145,175)">EndpointDispatcher</span> endpointDispatcher)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> endpointDispatcher.<strong>DispatchRuntime</strong>.<strong>MessageInspectors</strong>.Add(<span style="color: blue">this</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Validate(<span style="color: rgb(43,145,175)">ServiceEndpoint</span> endpoint)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//empty;</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"><span style="color: blue"> #endregion</span></p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: green">//The implemenation of DispatchMessageInspector; Omitted</span></p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">If our behavior implement the IServiceBehavior, we must iterate the ServiceHostBase object in the ApplyDispatchBehavior() method:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">void</span> ApplyDispatchBehavior(<span style="color: rgb(43,145,175)">ServiceDescription</span> serviceDescription, <span style="color: rgb(43,145,175)">ServiceHostBase</span> serviceHostBase)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">foreach</span> (<span style="color: rgb(43,145,175)">ChannelDispatcher</span> channelDispatcher <span style="color: blue">in</span> serviceHostBase.ChannelDispatchers)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">foreach</span> (<span style="color: rgb(43,145,175)">EndpointDispatcher</span> endpointDispatcher <span style="color: blue">in</span> channelDispatcher.Endpoints)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> endpointDispatcher.DispatchRuntime.MessageInspectors.Add(<span style="color: blue">this</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><a href="http://www.c-sharpcorner.com/UploadFile/BruceZhang/Extension-WCF-Behavior05172009215752PM/Extension-WCF-Behavior.aspx?ArticleID=75a49eec-d05a-4e47-8ec1-3ee4307a9e67">This article on CSharp Corner</a>.</p></div></div></div></div></div></div></div></div></div></div></div></div></div></div> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-61109952587445001732009-05-16T09:06:00.001+08:002010-07-10T11:36:38.526+08:00Dispose() in WCF<div class="main"> <div class="snap_preview"> <p>InfoQ posted a news “<a href="http://www.infoq.com/news/2009/03/WCF-Dispose">The problems with WCF and the Using Block</a>” about the disposing client resource in WCF and gave some solutions to this issue. I was looking for some material for this question, and wanted to give my summarization here.</p> <p>Without doubting, a resource (a unmanaged resource especially) need to implement the IDisposable interface. It’s a precondition to use the using statement to manage the resources. However, if some exceptions occured in the using block, the resource couldn’t be recyled normally. Some important resouces such as the connection would keep opening and occupy the port and channel if they weren’t disposed. So it would impact on the performance of the system.</p> <p>The best practice Microsoft recommends is using try/catch/(finally) statement. It requires the developer invoke the Close() in try block, and use the Abort() in catch block. The news provided the biggest difference between the Close() and the Abort:</p> <blockquote> <p>Close() take a Timeout and has an async version, and also Close() can throw Exceptions. Abort() conversely is not supposed to block (or throw any expected exceptions), and therefore doesn’t have a timeout or an async version.</p></blockquote> <p>In a short, Close() will dispose the resoucres friendly and Abort() will do ungracefully. Because Close() may throw some exceptions such as CommunicationException and TimeoutException, so the code snippet on the client side would be like this:</p> <div style="font-size: 10pt; background: white; color: black; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">var</span> myClient = <span style="color: blue">new</span> MyClient();</p> <p style="margin: 0pt"><span style="color: blue">try</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: green">//do something</span></p> <p style="margin: 0pt"> myClient.Close();</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"><span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">CommunicationException</span>)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> myClient.Abort();</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"><span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">TimeoutException</span>)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> myClient.Abort();</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"><span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">Exception</span>)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> myClient.Abort();</p> <p style="margin: 0pt"> <span style="color: blue">throw</span>;</p> <p style="margin: 0pt">}</p></div> <p>It is necessary of catching an exception at the end of code lines, because we don’t know if Close() method throws some unexpected exceptions such as OutOfMemoryException. In the news of InfoQ, the author introduced a solution to solve this issue provided by Steve Smith. He encapsulates these tedious code with using extension method. The type it wants to extend is ICommunicationObject, because all client objects implement the ICommunicationObject interface. The code snippet Stevie Smith wrote is as below:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">Extensions</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">void</span> CloseConnection(<span style="color: blue">this</span> <span style="color: rgb(43,145,175)">ICommunicationObject</span> myServiceClient)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (myServiceClient.State != <span style="color: rgb(43,145,175)">CommunicationState</span>.Opened)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> myServiceClient.Close();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">CommunicationException</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> Debug.Print(ex.ToString());</p> <p style="margin: 0pt"> myServiceClient.Abort();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">TimeoutException</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> Debug.Print(ex.ToString());</p> <p style="margin: 0pt"> myServiceClient.Abort();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">Exception</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> Debug.Print(ex.ToString());</p> <p style="margin: 0pt"> myServiceClient.Abort();</p> <p style="margin: 0pt"> <span style="color: blue">throw</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">We can replace the Close() with CloseConnection() method to avoid writting the repeated and tedious try/catch/finally statement. The other nice way is to use lambda expression. Its usage looks like using syntax. It defines a static method which accepts a ICommunicationObject object parameter and Action delegate:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">Util</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">void</span> Using<T>(T client, <span style="color: rgb(43,145,175)">Action</span> action)</p> <p style="margin: 0pt"> <span style="color: blue">where</span> T : <span style="color: rgb(43,145,175)">ICommunicationObject</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> action(client);</p> <p style="margin: 0pt"> client.Close();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">CommunicationException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> client.Abort();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">TimeoutException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> client.Abort();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">Exception</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> client.Abort();</p> <p style="margin: 0pt"> <span style="color: blue">throw</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">We can pass the client implementation as lambda expression to Using() method:</p> <p style="margin: 0pt"><span style="color: rgb(43,145,175)">Util</span>.Using(<span style="color: blue">new</span> MyClient(), client =></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> client.SomeWCFOperation();</p> <p style="margin: 0pt"> <span style="color: green">//Do something;</span></p> <p style="margin: 0pt">});</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">In fact, there is another way to solve this issue. We can define a custom ChannelFactory to implement the IDisposable interface and let it as a Wrapper class to ChannelFactory. It also encapsulates the try/catch/finally statement in the Close() method of the custom ChannelFactory:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">MyChannelFactory</span> : <span style="color: rgb(43,145,175)">IDisposable</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">private</span> <span style="color: rgb(43,145,175)">ChannelFactory</span> m_innerFactory;</p> <p style="margin: 0pt"> <span style="color: blue">public</span> MyChannelFactory(<span style="color: rgb(43,145,175)">ChannelFactory</span> factory)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_innerFactory = factory;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> ~MyChannelFactory()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> Dispose(<span style="color: blue">false</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Close()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> Close(<span style="color: rgb(43,145,175)">TimeSpan</span>.FromSeconds(10));</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Close(<span style="color: rgb(43,145,175)">TimeSpan</span> span)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (m_innerFactory != <span style="color: blue">null</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (m_innerFactory.State != <span style="color: rgb(43,145,175)">CommunicationState</span>.Opened)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_innerFactory.Close(span);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">CommunicationException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_innerFactory.Abort();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (TimeOutException)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_innerFactory.Abort();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">Exception</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_innerFactory.Abort();</p> <p style="margin: 0pt"> <span style="color: blue">throw</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">private</span> <span style="color: blue">void</span> Dispose(booling disposing)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (disposing)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> Close();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">void</span> <span style="color: rgb(43,145,175)">IDisposable</span>.Dispose()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> Dispose(<span style="color: blue">true</span>);</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">GC</span>.SuppressFinalize(<span style="color: blue">this</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Anyway, the essence of these solutions is to encapsulate the repeated logic, and ensure the security, performance and stability of the system.</p></div></div> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-42438035164564612132009-05-14T09:01:00.000+08:002010-07-10T09:01:56.596+08:00Times Reader 2.0<div class="main"> <div class="snap_preview"> <p>On May 12th, New York Times announced the <a href="http://firstlook.blogs.nytimes.com/2009/05/12/times-reader-20-is-now-available/">Times Reader 2.0 is now available</a>. This new version is powered by Adobe AIR and can run equally well on Windows, Mac, Linux platform. If you are member of New York Times website, you can free download it. Installing it, it becomes more convenient to read the news from New York Times.</p> <p>There are many columns such as International, National, Opinion, Business, Sport etc in Times Reader. It will help you find the news which you are interested in. It also offers the latest news so that you can obtain the latest information in time. You can choose the news according to the publishing date. In fact, it provides all news in a week. In the Times Reader, you may change the browsed way. Even you can watch the news in video or pictures. It is the extraordinary experience.</p> <p style="text-align: left"><img class="aligncenter size-full wp-image-122" title="timesreader01" style="display: block; float: none; margin-left: auto; margin-right: auto" height="449" alt="timesreader01" src="http://brucezhang.files.wordpress.com/2009/05/timesreader01.jpg?w=560&h=449" width="560"></p> <p style="text-align: center">Figure 1: Front Page</p> <p style="text-align: center"><img class="aligncenter size-full wp-image-123" title="timesreader02" style="display: block; float: none; margin-left: auto; margin-right: auto" height="454" alt="timesreader02" src="http://brucezhang.files.wordpress.com/2009/05/timesreader02.jpg?w=560&h=454" width="560">Figure 2: News in Pictrures</p> <p style="text-align: center"><img class="aligncenter size-full wp-image-124" title="timesreader03" style="display: block; float: none; margin-left: auto; margin-right: auto" height="452" alt="timesreader03" src="http://brucezhang.files.wordpress.com/2009/05/timesreader03.jpg?w=560&h=452" width="560">Figrue 3: Browse Mode</p> <p style="text-align: left">I remember that I had installed the oldest version of Times Reader a couple of years ago. It was developed by WPF which is a technology produced by Microsoft. I have to agree it was amazing experience at that time. It improved the readability and useability for us. If each of publishers of newspaper provided the reader like this, no one doesn’t like to visit the website maybe, I think.</p> <p>The new version of Times Reader was dropping WPF/Sivlerlight for Adobe AIR. What does it mean? It means Microsoft lost the important customer? It means Adobe AIR is better than WPF/Silverlight? Both are right, maybe. After New York Times announced the new version of Times Reader, <a href="http://www.infoq.com">InfoQ</a> reported the news which title is “<a href="http://www.infoq.com/news/2009/05/Times-AIR-Reader">New York Times Dropping WPF/Silverlight for Adobe AIR</a>“. The author wrote: “The biggest hurdle [of WPF]was the lack of cross-platform support.” I agree his opinion. Additionally, the compatibility of WPF/Silverlight is the other issue.</p> <p>In the field of Rich Client Application, Microsoft lost more and more customers this year. After one year of using Silverlight, MLB swithed back to Flash to show its boradcasted live on the internet on 2009. Now, New York Times choose Adobe instead of Microsoft. What does it happen? Perhaps Microsoft should think about its strategy and improve the quality of service.</p></div></div> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-62025532599009898712009-05-13T08:58:00.000+08:002010-07-10T08:59:36.377+08:00Dragon Boat Festival<p><a href="http://lh4.ggpht.com/_4YVDJ1U3Hok/TDfF58DNrpI/AAAAAAAAAP8/7PCLHabzcwo/s1600-h/image%5B5%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: block; float: none; margin-left: auto; border-left: 0px; margin-right: auto; border-bottom: 0px" height="185" alt="image" src="http://lh6.ggpht.com/_4YVDJ1U3Hok/TDfF9ACS26I/AAAAAAAAAQA/CboDNadIOY8/image_thumb%5B3%5D.png?imgmax=800" width="545" border="0"></a> <p>Dragon Boat Festival is occuring on the fifth day of the fifth lunar month. It’s a significant holiday celebrated in china, and the one with the longest history. The Dragon Boat Festival is celebrated by boat races in the shape of dragon. Competing team rows their boats forward to a drumbeat racing to the finish end first. <p>The boat races during the Dragon Boat Festival are traditional custom to attempt to rescue the patriotic poet Chu Yuan. Chu Yuan drown on the fifth day of the fifth lunar month in 277 B.C. Chinese citizen now throw bamboo leaves filled with cooked rice into the water. Therefore the fish could eat the rice rather than the hero poet. This later on turned into the custom of eating tzungtzu and rice dumpling. <p>The celebration’s is a time for protection from evil and disease for the rest of the year. It is done so by the different practices such as Hanging healthy herbs on the front door, drinking the alcohol mixing into realgar. After researched by Chinese Culture researcher, protection from evil and disease is the real and original meaning of this festival. As for tzungtzu, the people in the Xia Dynasty had already this traditional food in fact. So called memorizing the great poet Chu Yuan, it was attached into the festival at the end of the Han Dynasty, and became into the dominant meaning of the Dragon Boat Festival. Since the essence of the Dragon Boat Festival had changed, it is not only a tradional holiday, but also a Chinese culture heritage. <p>On May 28th this year, let’s celebrate the Dragon Boat Festival! Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-61366053630139767152009-05-05T17:25:00.000+08:002010-07-09T17:26:05.276+08:00Microsoft released BizTalk Server 2009<p><a href="http://lh4.ggpht.com/_4YVDJ1U3Hok/TDbrJiQj3yI/AAAAAAAAAP0/kU9tgwn6XM4/s1600-h/image%5B3%5D.png"><img title="image" style="border-right: 0px; border-top: 0px; display: inline; margin-left: 0px; border-left: 0px; margin-right: 0px; border-bottom: 0px" height="65" alt="image" src="http://lh5.ggpht.com/_4YVDJ1U3Hok/TDbrKyV_CoI/AAAAAAAAAP4/qEBJSFC-JSk/image_thumb%5B1%5D.png?imgmax=800" width="244" align="left" border="0"></a> Recently, Microsoft released BizTalk Server 2009 which is the latest version for Biztalk Server. BizTalk Server <a href="http://blogs.msdn.com/biztalk_server_team_blog/default.aspx">Team Blog</a> announced this news on April 28. It posted the key improvements in the BizTalk Server 2009 release: <ul> <li>New Application Lifecycle Management(ALM) exprience to make development teams more productive </li></ul> <ul> <li>New adapters and numerous enhancements that provide increased enterprise connectivity </li></ul> <ul> <li>New RFID mobile capabilities that will enable innovative solution to drive business value </li></ul> <p>The BizTalk Server 2009 release is the globalized product. It is available broadly in nine languages: Chinese simplified, Chinese traditional, English, French, German, Italian, Japanese, Korea and Spanish. Besides, it includes four edtions: Enterprise, Standard, Branch and Developer. The price of the new version is not change. More information about the price and upgrade, please visit “<a href="http://www.microsoft.com/biztalk/en/us/pricing-licensing.aspx">Pricing and licensing</a>” provided by Microsoft. <p>If you want to update it from BizTalk Server 2006 R2 to 2009,Nick Heppleston had posted a great article on his <a href="http://www.modhul.com/">blog</a> called “<a href="http://www.modhul.com/2009/04/11/a-quick-walkthrough-of-the-biztalk-2006-r2-upgrade-to-biztalk-2009-rtm/">A Quick Walkthrough of the BizTalk Server 2006 R2 Upgrade to BizTalk Server 2009 RTM</a>“. It is detail guide and introduces how to upgrade it step by step. <p>BizTalk Server 2009 is widely concerned in the technology community. Abdul Rafay raise his opinion in his <a href="http://abdulrafaysbiztalk.wordpress.com/2009/04/28/microsoft-announces-biztalk-server-2009/">blog</a>:<br>It supports the Windows Server 2008, VS 2008, .NET Framwork 3.5 and SQL Server 2008 which I think is a major change and will have advantages of the new advanced platform. <p>He briefly introduced the new adapters in BizTalk Server 2009:<br>Unlike the release of BizTalk Server R2, BizTalk 2009 comes with two new adapters Oracle E-Business Suites and SQL Server, while there has been an enhancement in the existing adapters which I still have to explore. <p>Microsoft also provided <a href="http://www.microsoft.com/biztalk/en/us/roadmap.aspx">the roadmap</a> of BizTalk Server. It said:”BizTalk Server 2009 represents the next release in Microsoft’s long-term strategy to enable the connected enterprise. ” The BizTalk Server 2009 continue to build on the investments made to address the concerns of Service Oriented Architecture and Enterprise Connectivity. Especially, the new release of BizTalk Server can take advantage of the latest virtualization improvements included as part of Windows Server 2008 Hyper-V. This capability can reduce the costs through lower hardware, energy and management overhead. <p>To learn more information about BizTalk Server 2009, Adlai Maschiach summarize some useful matirial on his <a href="http://blogs.microsoft.co.il/blogs/adlaim/archive/2009/04/30/biztalk-2009-rtm.aspx">blog</a> including MSDN Documents, Virtual Labs and BizTalk Server 2009 Solutinos. Of course, you can visit the <a href="http://www.microsoft.com/biztalk/en/us/default.aspx">Official Website of BizTalk Server</a> to learn more. Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-59840528066069193372009-04-24T11:55:00.004+08:002010-07-10T09:46:58.038+08:00VS 2008 Shortcut KeyThere are many useful shortcut keys in VS 2008. In this post, I'll write some most useful key which are always used by myself.<br /><span style="color: rgb(255, 102, 102);">Shift&Alt&Enter</span>: Switch to Full-Screen mode;<br /><span style="color: rgb(255, 102, 102);">Ctrl&Tab</span>: Similar with Alt-Tab in Windows OS, it can switch windows that have been open currently in VS;<br /><span style="color: rgb(255, 102, 102);">Ctrl&-</span>: To navigate backward to previous place. For example, if you want to explore some class's definition, you will select "go to definition" item from context menu to navigate the definition detail. After you view it, in the most case, you want to back the previous place, so you can press this shortcut key. That's great and convenient for the developer. It seems like "Undo" feature;<br /><span style="color: rgb(255, 102, 102);">Ctrl&Shift&-</span>: To navigate forward to next place.Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-49344772360983419012009-04-15T09:48:00.003+08:002009-04-15T10:23:38.909+08:00Design is an islandRecently, Kent Beck wrote a post which raise an opinion about software disign. It's a nice metaphore for disign. That is: design is an island.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_4YVDJ1U3Hok/SeU_zr_RlnI/AAAAAAAAAJQ/vXoaTfCd9Sw/s1600-h/island.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 212px;" src="http://3.bp.blogspot.com/_4YVDJ1U3Hok/SeU_zr_RlnI/AAAAAAAAAJQ/vXoaTfCd9Sw/s320/island.jpg" alt="" id="BLOGGER_PHOTO_ID_5324732291649476210" border="0" /></a>Kent wrote: Designing, then, is like walking an island. As long as you don't get your feet wet, your design is okay. It means that we should try to design enough to meet the current set of requirement, otherwise you might fall into the water.<br /><br />The "water line" is always changed because the tides always change the sea level. It means the change of requirement. That is inevitable. So we must beware not to let your feet wet. Kent said:"Design that are acceptable at other time of the year break down in the 10% of the year when you do 50% of your business." So you should keep your design fresh. It's the feature of the excellent architecture.<br /><br />"Climbing higher on irland requires effort, just as improving designs require effort." That's right. You should spend your money and time to improve your disign.<br /><br />Kent recoginzed the distributed application such as SOA and REST as the archipelago. It's interesting. The analogy is perfect. It's the extension of metaphore of island.<br /><br />Kent alos raise his opinions, for example earthquake and island sank. More details visit the kent beck's blog <a href="http://www.threeriversinstitute.org/blog/?p=122">here</a>. Enjoy it!Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-32512696334157264932009-03-31T11:38:00.000+08:002010-07-10T11:38:43.781+08:00Code Hightlight and IndentionGoogle Blogger is one of popular Blogs. Maybe millions of people own the blogger's blog. I like its convenient, it integrated with many nice features such as YouTube, Picasso Web Albums, Google Adsense etc. Unfortunately, it is not enough good for Sofware developer, the reason is that it doesn't provide the Code Hightlight feature. Worst of all, it will automatically trim the spaces in front of each line when you post your blog. It will spoil the indented code and effect the readability of code snippet. It is bad news, isn't it?<br><br>Of course, you can search for the corresponding Add-in to solve the problem. But I don't find the good add-in for blogger so far. Some of them are not convenient, some are no nice format, and some decrease the performance of website because they will read some information from server.<br><br>Now, I find the best way to solve it finnally. It's very easy. The key is one website I will strongly recommend for you. That is <a href="http://fayaa.com/code/">代码发芽网</a>(Which means code germination. Funny, aha.). You can paste your code snippet to it, and select the language such as C#, Javascript, Python, php etc. Then submit it. Finnally the code snippet will convert the format according to the language syntax and present with highlight style. Now you only need to select the result code and copy to your blog post. That's it.<br><br>It is not yet over. Blogger will automatically trim the spaces described before. So there is a peice of advice for you. If you place your code snippet inside the <> < /pre > in <span style="font-weight: bold">Compose</span> Mode, everything is ok. You will get the indented code with highlight. Here are some sample demos.<br><br><span style="font-weight: bold">C# Code Snippet:</span><span style="font-family: monospace"><br><pre><span style="color: rgb(0,0,255)">public</span> <span style="color: rgb(0,0,255)">class</span> <span style="color: rgb(43,145,175)">Bar</span><br><span style="color: rgb(0,0,255)">{</span><br> [CallTracingAttribute("In Bar ctor")]<br> <span style="color: rgb(0,0,255)">public</span> Bar() <span style="color: rgb(0,0,255)">{}</span><br> [CallTracingAttribute("In Bar.Calculate method")]<br> <span style="color: rgb(0,0,255)">public</span> <span style="color: rgb(43,145,175)">int</span> Calculate(<span style="color: rgb(43,145,175)">int</span> x, <span style="color: rgb(43,145,175)">int</span> y)<span style="color: rgb(0,0,255)">{</span> <span style="color: rgb(0,0,255)">return</span> x + y; <span style="color: rgb(0,0,255)">}</span><br><span style="color: rgb(0,0,255)">}</span><span style="font-family: monospace"></span></pre><br></span><span style="font-weight: bold">Javascript Code Snippet:</span><br><pre><span style="color: rgb(0,0,255)">function</span> bookmark(title, url) {<br><span style="color: rgb(0,0,255)">if</span> (document.all)<br>window.external.AddFavorite(url, title);<br><span style="color: rgb(0,0,255)">else</span> <span style="color: rgb(0,0,255)">if</span> (window.sidebar)<br>window.sidebar.addPanel(title, url, <span style="color: rgb(163,21,21)">""</span>)<br>}</pre><span style="font-weight: bold">Python Code Snippet:</span><br><pre><span style="color: rgb(0,128,0)">#!/usr/bin/env python</span><br><br><span style="color: rgb(163,21,21)">'makeTextFile.py -- create text file'</span><br><br><span style="color: rgb(0,0,255)">import</span> os<br>ls = os.linesep<br><br><span style="color: rgb(0,128,0)"># get filename</span><br><span style="color: rgb(0,0,255)">while</span> True:<br>fname = raw_input(<span style="color: rgb(163,21,21)">'Enter file name: '</span>)<br><span style="color: rgb(0,0,255)">if</span> os.path.exists(fname):<br><span style="color: rgb(0,0,255)">print</span><span style="color: rgb(163,21,21)">"*** ERROR: '</span><span style="color: rgb(163,21,21)">%s</span><span style="color: rgb(163,21,21)">' already exists"</span> % fname<br><span style="color: rgb(0,0,255)">else</span>:<br><span style="color: rgb(0,0,255)">break</span><br><br><span style="color: rgb(0,128,0)"># get file content (text) lines</span><br>all = []<br><span style="color: rgb(0,0,255)">print</span> <span style="color: rgb(163,21,21)">"</span><span style="color: rgb(163,21,21)">\n</span><span style="color: rgb(163,21,21)">Enter lines ('.' by itself to quit).</span><span style="color: rgb(163,21,21)">\n</span><span style="color: rgb(163,21,21)">"</span><br><br><span style="color: rgb(0,128,0)"># loop until user terminates input</span><br><span style="color: rgb(0,0,255)">while</span> True:<br>entry = raw_input(<span style="color: rgb(163,21,21)">'> '</span>)<br><span style="color: rgb(0,0,255)">if</span> entry == <span style="color: rgb(163,21,21)">'.'</span>:<br><span style="color: rgb(0,0,255)">break</span><br><span style="color: rgb(0,0,255)">else</span>:<br>all.append(entry)<br><br><span style="color: rgb(0,128,0)"># write lines to file with proper line-ending</span><br>fobj = open(fname, <span style="color: rgb(163,21,21)">'w'</span>)<br>fobj.writelines([<span style="color: rgb(163,21,21)">'</span><span style="color: rgb(163,21,21)">%s%s</span><span style="color: rgb(163,21,21)">'</span> % (x, ls) <span style="color: rgb(0,0,255)">for</span> x <span style="color: rgb(0,0,255)">in</span> all])<br>fobj.close()<br><span style="color: rgb(0,0,255)">print</span> <span style="color: rgb(163,21,21)">'DONE!'</span></pre>Only regret is that it can't deal with the html-like language in this way, because the blogger will parse them. Apart from this, it can't support the <span style="font-weight: bold">generic syntax</span>. Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-14171680081851741812009-03-31T09:20:00.006+08:002009-03-31T11:12:18.965+08:00QCon Beijing Will Be Open<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_4YVDJ1U3Hok/SdGKAQJtoWI/AAAAAAAAAIA/FM8UNSSKel4/s1600-h/1.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 320px; height: 150px;" src="http://2.bp.blogspot.com/_4YVDJ1U3Hok/SdGKAQJtoWI/AAAAAAAAAIA/FM8UNSSKel4/s320/1.jpg" alt="" id="BLOGGER_PHOTO_ID_5319184371841605986" border="0" /></a><br /><a href="http://qcon.infoq.com/">QCon</a> is Enterprise Software Development Conference for the leader of group, architect, project manager and senior software developer. The area it focuses on cover through Architecture Design, SOA, Agile, Case Study, etc. QCon is hosted by <a href="http://www.infoq.com/">InfoQ</a>. Since March, 2007, it has been hold four times in London UK, San Francisco USA. Upcoming conference will be hold in Beijing, China during April 7 to 9.<br /><br />In <a href="http://www.qconbeijing.com/">QCon Beijing</a>, Some of speakers include:<br />Rod Johnson: Spring Creator;<br />Martin Fowler: Author of the great books "Analysis Patterns" and "Refactoring", The Chief Scientist of Thoughtworks;<br />Randy Shoup: eBay senior architect;<br />Jeff Bar: Amazon Cloud Computin architect;<br />Dylan Shiemann: Dojo Toolkit founder;<br />Floyd Marinescu: Author of "EJB Patterns", InfoQ and TheServerSide founder;<br />Mao XinSheng: IBM China Web 2.0 chief architect;<br />Li Wei: Siments China Research Center chief architect;Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-42105178731275381332009-03-29T11:48:00.000+08:002010-07-10T11:48:30.498+08:00Using Extension Methods to Verify the Method Calling<p>Using the extension method provided by C# 3.0 as the new feature, you can add the new methods for the compiled assembly to meet the need of extensible. In addition to this, extension method can also be effective to reduce duplicate code and improve the reusability of system if you are able to combine the generic and type inference. For example, the method like this:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">CustomerDAL</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: rgb(43,145,175)">IEnumerable</span><Customer> FindCustomers(<span style="color: blue">string</span> roleName)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: blue">from</span> customer</p> <p style="margin: 0pt"> <span style="color: blue">in</span> context.Customer</p> <p style="margin: 0pt"> <span style="color: blue">where</span> customer.RoleName.Equals(roleName)</p> <p style="margin: 0pt"> <span style="color: blue">select</span> customer;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p>It will throw the NullReferenceException if you invoke it by this way as below when it returns null:</p> <p><span style="color: rgb(0,0,0)">Customer</span> <span style="color: rgb(0,0,0)">customer</span> <span style="color: rgb(0,0,0)">=</span> <span style="color: rgb(0,0,255)">new</span> <span style="color: rgb(0,0,0)">CustomerDAL</span><span style="color: rgb(0,0,0)">().</span><span style="color: rgb(0,0,0)">FindCustomers</span>(<span style="color: rgb(0,0,0)">Role</span><span style="color: rgb(0,0,0)">.</span><span style="color: rgb(0,0,0)">Admin</span><span style="color: rgb(0,0,0)">).</span><span style="color: rgb(0,0,0)">First</span>();</p> <p>So we have to verify the result. If it is null, the custom exception should be thrown:</p> <p style="margin: 0pt"><span style="color: blue">public</span> IEnumerable<Customer> FindCustomers(<span style="color: blue">string</span> roleName)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> IEnumerable<Customer> customers = from customer</p> <p style="margin: 0pt"> <span style="color: blue">in</span> context.Customer</p> <p style="margin: 0pt"> where customer.RoleName.Equals(roleName)</p> <p style="margin: 0pt"> select customer;</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (customers == <span style="color: blue">null</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> <span style="color: blue">new</span> MyException(<span style="color: rgb(163,21,21)">“Cann’t find the customers.”</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">return</span> customers;</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p>The logic of verification implemetation will spread through the everywhere in the system if there are too many methods which need to be verified. It is difficult to reuse these code, and it is bad smell absolutely.</p> <p>Craig Andera post the blog to solve this problem. He wrote:<br>A NullReferenceException would be thrown, but we wanted something more specific. So we came up with this:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">static</span> T OrThrow<T>(<span style="color: blue">this</span> T obj, Exception e) {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (obj == <span style="color: blue">null</span>) {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> e;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">return</span> obj;</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Using the OrThrow() method, the invoking way might be changed like this:</p> <p style="margin: 0pt">Customer customer = <span style="color: blue">new</span> CustomerDAL().</p> <p style="margin: 0pt"> FindCustomers(Role.Admin).OrThrow</p> <p style="margin: 0pt"> (<span style="color: blue">new</span> MyException(<span style="color: rgb(163,21,21)">“Can’t find Customer”</span>)).First();</p> <p style="margin: 0pt"> </p> <p>Craig continues to say:<br>the OrThrow extension method is generic on the type it’s invoked on, and it returns that type, so you can insert it into a chained expression and you don’t lose any intellisense. And because of type inference, you don’t actually have to specify the type, which cleans up the expression a bit.</p> <p>That is, OrThrow() method can be applied to any type. Following this idea, we can create an instance as default value to avoid to throw the NullReferenceException using the extension method:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">static</span> T Instance<T>(<span style="color: blue">this</span> T obj) where T:<span style="color: blue">new</span>()</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (obj == <span style="color: blue">null</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> obj = <span style="color: blue">new</span> T();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">return</span> obj;</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Due to type parameter T need to create an instance, we must add the constraint with new(). So that we can’t use the Instance<T> extension method for abstract type or interface type such as IEnumerable. But it is effective to method like this:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">ListObject</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: rgb(43,145,175)">List</span><<span style="color: blue">string</span>> Foo()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: blue">null</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Through by using Instance() method, we can invoke the related properties and methods of List instance safely. For example, we can use the Count property as below:</p> <p style="margin: 0pt">Console.WriteLine(<span style="color: blue">new</span> ListObject().Foo().Instance().Count);</p> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-23170635136464750242009-03-19T11:49:00.000+08:002010-07-10T11:50:33.881+08:00A Common Base Class for LINQ To SQL<div class="main"> <div class="snap_preview"> <p><strong>Introduction</strong></p> <p>Language-Integrated Query (LINQ) is a set of features in Visual Studio 2008 that extends powerful query capabilities to the language syntax of C# and Visual Basic. As a part of LINQ, LINQ to SQL provides a run-time architecture for managing relational data as objects. To some extent, it equals to an ORM tool or framework such as NHibernate and Castle based on the .NET framework. It becomes our preferred choice gradually when we want to access databases.</p> <p>In LINQ to SQL, all variables in the Data Model of a relational database can be strongly typed, which provides the benefit of compile-time validation and IntelliSense. We can fetch the data from the database using a query expression (it includes query syntax and method syntax).</p> <p>However, the strongly typed feature is not conducive to abstract the common logic of data operations, so the developer has to define a specific class to handle the entity object. It results in a large number of repeated codes If we can implement the base class which encapsulates common operations such as Select, Where, Add, Update, and Delete, it will be useful for N-tier applications.</p> <p><strong>Using the Code</strong></p> <p>Using my base class for LINQ to SQL, you can simply implement the class to access a database without a line of code. What you should do is to let your class derive my base class, like this:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">EmployeeAccessor</span> : <span style="color: rgb(43,145,175)">AccessorBase</span><Employee, NorthwindDataContext></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Now, you can add, update, delete, or select the data object with it. Please refer to the Unit Test Method:</p> <p style="margin: 0pt"> [<span style="color: rgb(43,145,175)">TestMethod</span>()]</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> UpdateEmployee()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">EmployeeAccessor</span> accessor = <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">EmployeeAccessor</span>();</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">IList</span><<span style="color: rgb(43,145,175)">Employee</span>> entities = accessor.Where(e => e.EmployeeID == 1);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">if</span> (entities != <span style="color: blue">null</span> && entities.Count > 0)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> entities[0].FirstName = <span style="color: rgb(163,21,21)">“Bruce”</span>;</p> <p style="margin: 0pt"> entities[0].LastName = <span style="color: rgb(163,21,21)">“Zhang”</span>;</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> accessor.Update(entities[0], <span style="color: blue">true</span>, <span style="color: blue">true</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">You may even let the Employee entity derive my base class directly:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">partial</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">Employee</span> : <span style="color: rgb(43,145,175)">AccessorBase</span><<span style="color: rgb(43,145,175)">Employee</span>, NorthwindDataContext></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Its behavior is very similar to the Rich Domain Model like Martin Fowler said in his article titled Anemic Domain Model.</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><strong>The implementation of the base class</strong></p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">The implementation of the query function is very simple. We can invoke a method called GetTable<TEntity>() in the DataContext of LINQ, then invoke some LINQ operations of the GetTable<TEntity>() method, and pass the Lambda Expression to it:</p> <p style="margin: 0pt"><span style="color: blue">public</span> IList<TEntity> Where(Func<TEntity, <span style="color: blue">bool</span>> predicate)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> <span style="color: blue">return</span> m_context.GetTable<TEntity>().Where(predicate).ToList<TEntity>();</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">We can also expose the method which accepts the condition clause using a dynamic query:</p> <p style="margin: 0pt"><span style="color: blue">public</span> IList<TEntity> Where(<span style="color: blue">string</span> predicate, <span style="color: blue">params</span> <span style="color: blue">object</span>[] values)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> <span style="color: blue">return</span> m_context.GetTable<TEntity>().Where(predicate, values).ToList<TEntity>();</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p>The implementation of the Update method (also the Delete method) is more complex. Though we can use the Attach methods LINQ introduces, there are some constraints for them. So, I have provided a couple of Update methods for different situations.</p> <p>At first, we must consider whether the entity has relationship with other entities or not. If yes, we have to remove the relationship from it. I have defined a Detach method using Reflection technology, like this:</p> <p style="margin: 0pt"> <span style="color: blue">private</span> <span style="color: blue">void</span> Detach(TEntity entity)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">foreach</span> (<span style="color: rgb(43,145,175)">FieldInfo</span> fi <span style="color: blue">in</span> entity.GetType().GetFields(<span style="color: rgb(43,145,175)">BindingFlags</span>.NonPublic | <span style="color: rgb(43,145,175)">BindingFlags</span>.Instance))</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (fi.FieldType.ToString().Contains(<span style="color: rgb(163,21,21)">“EntityRef”</span>))</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">var</span> value = fi.GetValue(entity);</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (value != <span style="color: blue">null</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> fi.SetValue(entity, <span style="color: blue">null</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (fi.FieldType.ToString().Contains(<span style="color: rgb(163,21,21)">“EntitySet”</span>))</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">var</span> value = fi.GetValue(entity);</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (value != <span style="color: blue">null</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">MethodInfo</span> mi = value.GetType().GetMethod(<span style="color: rgb(163,21,21)">“Clear”</span>);</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (mi != <span style="color: blue">null</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> mi.Invoke(value, <span style="color: blue">null</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> fi.SetValue(entity, value);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> } </p> <p>For EntityRef<T> fields, we may set their values to null by calling the SetValue of FieldInfo to remove the relationship. However, we can’t do EntitySet in the same way because it is a collection. If set to null, it will throw an exception. So, I get the method information of the field and invoke the Clear method to clear all the items in this collection.</p> <p>For the update operation, we can pass the changed entity and update it. The code snippet is shown below:</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Update(TEntity originalEntity, <span style="color: rgb(43,145,175)">Action</span><TEntity> update, <span style="color: blue">bool</span> hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//Remove the relationship between the entitis</span></p> <p style="margin: 0pt"> Detach(originalEntity);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> m_context.GetTable<TEntity>().Attach(originalEntity);</p> <p style="margin: 0pt"> update(originalEntity);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">ChangeConflictException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_context.ChangeConflicts.ResolveAll(<span style="color: rgb(43,145,175)">RefreshMode</span>.KeepCurrentValues);</p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> } </p> <p>Notice that the entity which will be updated must have a timestamp, or it will throw an exception.</p> <p>Don’t worry about the correctness of the final result when we remove the relationship between the entities. The Attach method is just responsible for associating the entity to a new instance of a DataContext to track the changes. When you submit the changes, the DataContext will check the real value in the mapping database and update or delete the record according to the passed entity. Especially, you should take an action such as Cascade in the database if you want to cascade the delete between the foreign key table and the primary key table.</p> <p>If the entity has no relationship with others, you may pass “false” to the hasrelationship parameter, like this:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt">accessor.Update(entities[0],<span style="color: blue">true</span>,<span style="color: blue">false</span>);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">It’s terrible to create the timestamp column for your data table which exists, maybe it will affect your whole system. (I strong recommend you to create the timestamp column for your database, it will improve the performance because it won’t check all columns if they have changed during handling the concurrency.) My solution to this issue is to pass the original entity and update it with the Action<TEntity> delegate, like this:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><summary></span></p> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> Update the entity which was passed</span></p> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> The changedEntity cann’t have the relationship between the entities</span></p> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"></summary></span></p> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><param name=”originalEntity”></span><span style="color: green">It must be unchanged entity in another data context</span><span style="color: gray"></param></span><span style="color: green"> </span></p> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><param name=”update”></span><span style="color: green">It is Action</span><span style="color: gray"><T></span><span style="color: green">delegate, it can accept Lambda Expression.</span><span style="color: gray"></param></span><span style="color: green"> </span></p> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><param name=”hasRelationship”></span><span style="color: green">Has relationship between the entities</span><span style="color: gray"></param></span></p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">void</span> Update(TEntity originalEntity, <span style="color: rgb(43,145,175)">Action</span><TEntity> update, <span style="color: blue">bool</span> hasRelationship)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//Remove the relationship between the entitis</span></p> <p style="margin: 0pt"> Detach(originalEntity);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> m_context.GetTable<TEntity>().Attach(originalEntity);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> update(originalEntity);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> SubmitChanges(m_context);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">InvalidCastException</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> ex;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">NotSupportedException</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> ex;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">Exception</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> ex;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p><strong>Concurrency Issue</strong></p> <p>Considering the concurrency issue, I give the default implementation for it by defining a virtual method called SubmitChanges. It will handle concurrency conflicts by the rule of last submit win. This method is as shown below:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><summary></span></p> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> It provides the default policy to handle the corrency conflict</span></p> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"></summary></span></p> <p style="margin: 0pt"><span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><param name=”context”></span><span style="color: green">Data Context</span><span style="color: gray"></param></span></p> <p style="margin: 0pt"><span style="color: blue">protected</span> <span style="color: blue">virtual</span> <span style="color: blue">void</span> SubmitChanges(TContext context)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> context.SubmitChanges(<span style="color: rgb(43,145,175)">ConflictMode</span>.ContinueOnConflict);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">ChangeConflictException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> context.ChangeConflicts.ResolveAll(<span style="color: rgb(43,145,175)">RefreshMode</span>.KeepCurrentValues);</p> <p style="margin: 0pt"> context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">Exception</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> ex;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">You may override the method in your subclass if you want to change the policy to handle the concurrency conflicts.</p> <p style="margin: 0pt"> </p> <p><strong>Others</strong></p> <p>Maybe you have noticed that the InitDataContext method is invoked in all methods to access the data. Its implementation is like this:</p> <div style="font-size: 10pt; background: white; color: black; font-family: verdana; moz-background-clip: -moz-initial; moz-background-origin: -moz-initial; moz-background-inline-policy: -moz-initial"> <p style="margin: 0pt"><span style="color: blue">private</span> TContext m_context = <span style="color: blue">null</span>;</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><span style="color: blue">private</span> TContext CreateContext()</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: rgb(43,145,175)">Activator</span>.CreateInstance<TContext>() <span style="color: blue">as</span> TContext;</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><span style="color: blue">private</span> <span style="color: blue">void</span> InitDataContext()</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> m_context = CreateContext();</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Why do we need to create a new instance of DataContext for each method? The reason is the caching policy in the DataContext. If you create a new instance of the DataContext and query the data from the database with it, then change its value and execute the same query with the same instance, the DataContext will return the data stored in the internal cache rather than remap the row to the table. For more information, please refer to LINQ in Action.</p> <p>So, the best practice is to create a new instance of the DataContext for each operation. Don’t worry about the performance, the DataContext is a lightweight resource.</p> <p style="margin: 0pt"><a href="http://www.codeproject.com/KB/linq/linq_base_class.aspx">This article on CodeProject</a>.</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">More details, please visit <a href="http://brucezhang.wordpress.com/2008/07/30/common-base-class-for-linq-to-sql/">this article</a> on my blog.</p></div></div></div></div></div></div> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-46315013610447757752009-03-07T11:54:00.000+08:002010-07-10T11:54:56.221+08:00Strategy Pattern and Delegate<div class="main"> <div class="snap_preview"> <p>Strategy Pattern will encapsulate a family of algorithm and make them interchangeable. So we can define the unified interface for the algorithm. It represents the polymorphism of OOD. For instance, we will develop a tool to calculate the tax. Assumed that the tax is divided into the personal income tax and enterprise tax. We can apply the Strategy Pattern into it and abstract the calculation of tax into the interface ITaxStrategy:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">interface</span> <span style="color: rgb(43,145,175)">ITaxStrategy</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">double</span> Calculate(<span style="color: blue">double</span> income);</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">The concrete tax strategies will implement the ITaxStrategy interface:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">PeronalTaxStrategy</span> : <span style="color: rgb(43,145,175)">ITaxStrategy</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">double</span> Calculate(<span style="color: blue">double</span> income)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//Implementation</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">EnterpriseTaxStrategy</span> : <span style="color: rgb(43,145,175)">ITaxStrategy</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">double</span> Calculate(<span style="color: blue">double</span> income)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//Implementation</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">At the same time, we will define the utility class to provide the clients with convenient.</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">TaxOp</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">private</span> <span style="color: rgb(43,145,175)">ITaxStrategy</span> strategy;</p> <p style="margin: 0pt"> <span style="color: blue">public</span> TaxOp(<span style="color: rgb(43,145,175)">ITaxStrategy</span> strategy)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">this</span>.strategy = strategy;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">double</span> GetTax(<span style="color: blue">double</span> income)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span> strategy.Calculate(income);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p>Now, the clients can invoke the related operation of TaxOp class to get the tax according to concrete strategy object which is passed as parameter of constructor.</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">App</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">void</span> Main(<span style="color: blue">string</span>[] args)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">TaxOp</span> op = <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">TaxOp</span>(<span style="color: blue">new</span> PersonalTaxStrategy());</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">Console</span>.WriteLine(<span style="color: rgb(163,21,21)">“The Personal Tax is :{0}”</span>, op.GetTax(1000));</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">It follows the idea of OOD. However, we can make use of the delegate syntax in C# for some simple algorithms. It will simplify our implementation. Maybe it will violate the idea of OOD, but it provides the extensibility also.</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">For the same example given before, we can modify the interface to delagate type:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">delegate</span> <span style="color: blue">double</span> <span style="color: rgb(43,145,175)">CalculateTax</span>(<span style="color: blue">double</span> income);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Of course, we should provide the different implemenation:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">Tax</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">double</span> CalculatePersonalTax(<span style="color: blue">double</span> income)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//Implementation</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">double</span> CalculateEnterpriseTax(<span style="color: blue">double</span> income)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//Implementation</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Accordingly, we must modify the TaxOp Class:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">TaxOp</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">private</span> <span style="color: rgb(43,145,175)">CalculateTax</span> calDel;</p> <p style="margin: 0pt"> <span style="color: blue">public</span> TaxOp(Calculate calDel)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">this</span>.calDel = calDel;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">double</span> GetTax(<span style="color: blue">double</span> income)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span> calDel(income);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">And the implementation of Clients program:</p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">App</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">void</span> Main(<span style="color: blue">string</span>[] args)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">TaxOp</span> op = <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">TaxOp</span>(<span style="color: blue">new</span> <span style="color: rgb(43,145,175)">CalculateTax</span>(<span style="color: rgb(43,145,175)">Tax</span>.CalculatePersonalTax));</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">Console</span>.WriteLine(<span style="color: rgb(163,21,21)">“The Personal Tax is :{0}”</span>, op.GetTax(1000));</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Two solutions are more or less the same. The code snippet is also similar. But the idea based on the essence of design is different completely. It’s the difference between OO and OP. The former encapsulates the behavior in an object; the latter handles the method directly, and uses the delegate to provide the extensibility. In fact, the delegate represents the feature of Functional Programming nearly. It seams like a pointer to the function in C++. In other words, the delegate is another ways of abstraction. It is more flexible than interface type. After C# 2.0 introduced the anonymous method, and C# 3.0 introduced the Lambda expression, delegate becomes more and more useful and popular on C# programming. Before C# 2.0, I prefer to interface; now I prefer to delegate. Even we may use the delegate type to provide the brand new implementation of some design patterns such as Strategy Pattern, Command Pattern etc.</p></div></div> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-89122329515901435572008-09-12T11:47:00.000+08:002010-07-10T11:47:48.056+08:00How to know Transaction Is Successful<div class="main"> <div class="snap_preview"> <p>Based on .Net Framework, it is convient to use transaction with System.Transactions.TransactionScope class. If no error occurs in the transaction scope, the TransactionScope object will complet, otherwise rollback.</p> <p>In some situations, we need execute some business logics after transaction complet successfully. Note that we don’t add some business logic code lines after complet() method. In another word, we must place these business logics out of the transaction scope. However, the transaction object had been disposed out of using statement. So, how to know the transaction is successful?</p> <p>Transaction object exposes the event called TransactionCompleted and provides TransactionStatus which is enumeration type. TransactionStatus enumeration type includes four values: Aborted, Committed, Active and InDoubt. Then we can make a decision depending on the value of TransactionStatus which is belong to TransactionInformation object. TransactionInformation object is a property of Transaction instance.</p> <p>The sample code is as below: </p> <div> <p style="margin: 0pt"><span style="color: blue">using</span> (TransactionScope ts = <span style="color: blue">new</span> TransactionScope())</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> Transaction transaction = Transaction.Current;</p> <p style="margin: 0pt"> transaction.TransactionCompleted += pro.OnCompleted;</p> <p style="margin: 0pt"> pro.UpdateEmployee();</p> <p style="margin: 0pt"> pro.DeleteCustomer();</p> <p style="margin: 0pt"> ts.Complete(); </p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><span style="color: blue">void</span> OnCompleted(<span style="color: blue">object</span> sender, TransactionEventArgs e)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> Debug.Assert(sender.GetType() == <span style="color: blue">typeof</span>(Transaction));</p> <p style="margin: 0pt"> Debug.Assert(<span style="color: blue">object</span>.ReferenceEquals(sender,e.Transaction));</p> <p style="margin: 0pt"> Transaction transaction = e.Transaction;</p> <p style="margin: 0pt"> <span style="color: blue">switch</span> (transaction.TransactionInformation.Status)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">case</span> TransactionStatus.Aborted:</p> <p style="margin: 0pt"> m_TransactionCommitted = <span style="color: blue">false</span>;</p> <p style="margin: 0pt"> <span style="color: green">//Not to do something when failed</span></p> <p style="margin: 0pt"> <span style="color: blue">break</span>;</p> <p style="margin: 0pt"> <span style="color: blue">case</span> TransactionStatus.Committed:</p> <p style="margin: 0pt"> m_TransactionCommitted = <span style="color: blue">true</span>;</p> <p style="margin: 0pt"> <span style="color: green">//do something when success</span></p> <p style="margin: 0pt"> <span style="color: blue">break</span>;</p> <p style="margin: 0pt"> <span style="color: blue">default</span>:</p> <p style="margin: 0pt"> m_TransactionCommitted = <span style="color: blue">false</span>;</p> <p style="margin: 0pt"> <span style="color: blue">break</span>;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p></div></div></div> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-66815340476894023272008-08-15T11:45:00.000+08:002010-07-10T11:47:04.291+08:00A Little Bit Regret for Generic in C#<div class="main"> <div class="snap_preview"> <p>In our project, I defined the ThrowHelper helper class to help us throw the customized exception. For instance, I defined a exception as below:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">EmployeeException</span> : <span style="color: rgb(43,145,175)">ApplicationException</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> EmployeeException()</p> <p style="margin: 0pt"> : <span style="color: blue">base</span>()</p> <p style="margin: 0pt"> { }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> EmployeeException(<span style="color: blue">string</span> message)</p> <p style="margin: 0pt"> : <span style="color: blue">base</span>(message)</p> <p style="margin: 0pt"> { }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> EmployeeException(<span style="color: blue">string</span> message, <span style="color: rgb(43,145,175)">Exception</span> innerException)</p> <p style="margin: 0pt"> : <span style="color: blue">base</span>(message, innerException)</p> <p style="margin: 0pt"> { }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Then we might define the method to throw it to be invoked by other developer conveniently:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">ThrowHelper</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> EmployeeException ThrowEmployeeException(<span style="color: blue">string</span> message)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LogService.Error(message);</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> <span style="color: blue">new</span> EmployeeException(message);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> EmployeeException ThrowEmployeeException(<span style="color: blue">string</span> message, <span style="color: rgb(43,145,175)">Exception</span> innerException)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LogService.Error(message, innerException);</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> <span style="color: blue">new</span> EmployeeException(message, innerException);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">The problem is that we need to add the method such as before if we defined a number of customized exceptions. It’s tedious. The developer must dislike this way whenever.</p> <p>Can we use the generic type to solve this problem? For example, we may define a new version method using generic type as below:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">ThrowHelperGeneric</span><TCustomException></p> <p style="margin: 0pt"> <span style="color: blue">where</span> TCustomException : <span style="color: rgb(43,145,175)">ApplicationException</span>, <span style="color: blue">new</span>()</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> TCustomException ThrowCustomException(<span style="color: blue">string</span> message)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LogService.Error(message);</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> <span style="color: blue">new</span> TCustomException(message);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> TCustomException ThrowCustomException(<span style="color: blue">string</span> message, <span style="color: rgb(43,145,175)">Exception</span> innerException)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LogService.Error(message, innerException);</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> <span style="color: blue">new</span> TCustomException(message, innerException);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Opps, it’s regretful. It can’t support to invoke constructor with parameter based on .Net framework. We have to use the reflection technology to solve it:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">ThrowHelperGeneric</span><TCustomException></p> <p style="margin: 0pt"> <span style="color: blue">where</span> TCustomException : <span style="color: rgb(43,145,175)">ApplicationException</span>, <span style="color: blue">new</span>()</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> TCustomException ThrowCustomException(<span style="color: blue">string</span> message)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LogService.Error(message);</p> <p style="margin: 0pt"> TCustomException exception = (TCustomException)<span style="color: blue">typeof</span>(TCustomException).GetConstructor(<span style="color: blue">new</span> <span style="color: rgb(43,145,175)">Type</span>[] { <span style="color: blue">typeof</span>(<span style="color: blue">string</span>) }).</p> <p style="margin: 0pt"> Invoke(<span style="color: blue">new</span> <span style="color: blue">object</span>[] { message });</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">throw</span> exception;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> TCustomException ThrowCustomException(<span style="color: blue">string</span> message, <span style="color: rgb(43,145,175)">Exception</span> innerException)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LogService.Error(message, innerException);</p> <p style="margin: 0pt"> TCustomException exception = (TCustomException)<span style="color: blue">typeof</span>(TCustomException).GetConstructor(<span style="color: blue">new</span> <span style="color: rgb(43,145,175)">Type</span>[] { <span style="color: blue">typeof</span>(<span style="color: blue">string</span>), <span style="color: blue">typeof</span>(<span style="color: rgb(43,145,175)">Exception</span>) }).</p> <p style="margin: 0pt"> Invoke(<span style="color: blue">new</span> <span style="color: blue">object</span>[] { message, innerException });</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">throw</span> exception;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">It’s a terrible choice. I don’t like to do in this way. Even though we can use new() in the where constraint, how come Microsoft can’t provide the similiar operator or keyword in the where constraint to constrain the type of the parameter in the constructor? Like this:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">ThrowHelperGeneric</span><TCustomException></p> <p style="margin: 0pt"> <span style="color: blue">where</span> TCustomException : <span style="color: rgb(43,145,175)">ApplicationException</span>, <span style="color: blue">new</span>(), <span style="color: blue">new</span>(<span style="color: blue">string</span>), <span style="color: blue">new</span>(<span style="color: blue">string</span>, <span style="color: rgb(43,145,175)">Exception</span>)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> TCustomException ThrowCustomException(<span style="color: blue">string</span> message)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LogService.Error(message);</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> <span style="color: blue">new</span> TCustomException(message);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> TCustomException ThrowCustomException(<span style="color: blue">string</span> message, <span style="color: rgb(43,145,175)">Exception</span> innerException)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LogService.Error(message, innerException);</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> <span style="color: blue">new</span> TCustomException(message, innerException);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt">I don’t know whether it will support this function in the furture version with C#. Is it too difficult?</p></div></div></div></div></div></div></div> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-44601867419066041792008-08-01T11:45:00.000+08:002010-07-10T11:45:36.658+08:00Programming Standard for Our Team<p></p> <div class="main"> <div class="snap_preview"> <p><span style="font-weight: bold">1. Exception Handling</span><br>1) Deprive all custom exceptions from System.ApplicationException, and putting all custom exceptions into WD.AIATools.Common.Exceptions namespace;<br>2) Define three overloaded version for constructor, such as:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">ActionParamsException</span> : <span style="color: rgb(43,145,175)">ApplicationException</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> ActionParamsException()</p> <p style="margin: 0pt"> : <span style="color: blue">base</span>()</p> <p style="margin: 0pt"> { }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> ActionParamsException(<span style="color: blue">string</span> message)</p> <p style="margin: 0pt"> : <span style="color: blue">base</span>(message)</p> <p style="margin: 0pt"> { }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> ActionParamsException(<span style="color: blue">string</span> message, <span style="color: rgb(43,145,175)">Exception</span> ex)</p> <p style="margin: 0pt"> : <span style="color: blue">base</span>(message, ex)</p> <p style="margin: 0pt"> { }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt">3) Provide a helper method which includes the logging operation for your custom exception in ThrowHelper class:</p> <div> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: rgb(43,145,175)">ActionParamsException</span> ThrowActionParamsException(<span style="color: blue">string</span> message, <span style="color: rgb(43,145,175)">Exception</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LogService.Error(message, ex);</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">ActionParamsException</span>(message, ex);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">4) In Data Access Layer, try to catch the exception which is thrown by .NET Framework, and re-throw the custom exception by invoking the helper method with ThrowHelper. For example:</p> <div> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> Foo();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (SqlException ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span>; <span style="color: green">//Avoid</span></p> <p style="margin: 0pt"> ThrowHelper.ThrowCustomException(<span style="color: rgb(163,21,21)">“message”</span>, ex); <span style="color: green">//OK</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">NotSupportedException</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> ThrowHelper.ThrowCustomException(<span style="color: rgb(163,21,21)">“message”</span>, ex); <span style="color: green">//OK</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">Exception</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> ThrowHelper.ThrowCustomException(<span style="color: rgb(163,21,21)">“message”</span>, ex); <span style="color: green">//OK</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">finally</span> <span style="color: green">//if necessary</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//do something</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">5) Don’t catch the exception in Business Logic Layer otherwise it is necessary.<br>6) In Presentation Layer, it includes two cases:<br>a) Show the error information on the current page through by catching the exception;<br>b) Link to the error page which includes the error information with Exception.Message;<br>7) Don’t catch the exception inside for or foreach statement.</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><span style="font-weight: bold">2. Robust Check Policy</span><br>1) Avoid throwing the NullReferenceException. Check whether the object is null before using it:</p> <div> <p style="margin: 0pt"><span style="color: blue">if</span> (someObject != <span style="color: blue">null</span>)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: green">//Do something;</span></p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"><span style="color: blue">else</span> <span style="color: green">//if necessary</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: green">//throw the custom exception or else</span></p> <p style="margin: 0pt">}</p> <p style="margin: 0pt">2) Never return the null value especially if the object is collection:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> IList GetSomeList()</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: green">//Something to do;</span></p> <p style="margin: 0pt"> <span style="color: blue">if</span> (NoItemInCollection)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: blue">new</span> List(); <span style="color: green">//OK</span></p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: blue">null</span>; <span style="color: green">//Avoid;</span></p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt">3) Always explicitly initialize an array of reference types using a for loop:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">MyClass</span>{}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><span style="color: blue">const</span> <span style="color: blue">int</span> ArraySize = 10;</p> <p style="margin: 0pt">MyClass[] array = <span style="color: blue">new</span> MyClass[ArraySize];</p> <p style="margin: 0pt"><span style="color: blue">for</span> (<span style="color: blue">int</span> index = 0; index < ArraySize; ++index)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> Array[index] = <span style="color: blue">new</span> MyClass();</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt">4) Prefer to use foreach statement instead of for statement;<br>5) Try to check what the instance’s type is before casting the reference type by using “is” operator:</p> <div> <p style="margin: 0pt"><span style="color: blue">if</span> (someObject <span style="color: blue">is</span> Foo)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> Foo <span style="color: blue">object</span> = (Foo)someObject;</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"><span style="color: green">//Or</span></p> <p style="margin: 0pt">Foo <span style="color: blue">object</span> = someObject <span style="color: blue">as</span> Foo;</p> <p style="margin: 0pt">6) Remember to dispose the resource when using the unmanaged resource; Always use a using statement in this situation.</p> <p><strong>3. Code Practices</strong><br>1) Avoid putting multiple classes in a single file;<br>2) Never hard-code a numeric value; always declare a constant instead;<br>3) Avoid providing explicit values for enums unless they are integer powers of 2:</p> <div> <p style="margin: 0pt"><span style="color: green">//Correct</span></p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">enum</span> <span style="color: rgb(43,145,175)">Color</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> Red, Green, Blue</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt">Note: Putting all enum types into the specific file.<br>4) Use String.Empty instead of “”;<br>5) When building a long string, use StringBuilder, not String;<br>6) Always have a default case in a switch statement;</p></div></div></div></div></div></div></div></div></div></div> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-26103343436351759682008-07-30T11:43:00.000+08:002010-07-10T11:43:59.905+08:00Common Base Class for LINQ to SQL<div class="main"> <div class="snap_preview"> <div class="main"> <div class="snap_preview"> <p>Language-Integrated Query (LINQ) is a set of features in Visual Studio 2008 that extends powerful query capabilities to the language syntax of C# and Visual Basic. As a part of LINQ, LINQ to SQL provides a run-time architecture for managing relational data as objects. To some extent, it equals to ORM tool or framework such as NHibernate and Castle based on .NET framework. It becomes our preferred choice gradually when we want to access the database.</p> <p>In LINQ to SQL, all variables in the Data Model of a relational database can be strongly typed which provides the benefit of compile-time validation and IntelliSense. We can fetch the data from the database using query expression (it includes query syntax and method syntax.)</p> <p>However, the strongly typed feature is not conducive to abstract the common logic of data operations so the developer has to define a specific class to handle the entity object. It results in a large number of repeated codes. If we can implement the base class which encapsulates the common operations such as Select, Where, Add, Update and Delete, it will be useful for N-Tier application.</p> <p>Fortunately, the generic type will help us to achieve our goal. We can invoke a method called GetTable() in DataContext of LINQ. For example, we can implement the Where method which accepts the Lambda expression to find the result we want to get:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> IList<TEntity> Where(Func<TEntity, <span style="color: blue">bool</span>> predicate)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> <span style="color: blue">return</span> m_context.GetTable<TEntity>().Where(predicate).ToList<TEntity>();</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p></div> <div> <p style="margin: 0pt">It’s simple. Even, we can expose the method which accepts the condition clause using Dynamic Query:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">DynamicQueryable</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: rgb(43,145,175)">IQueryable</span><T> Where<T>(<span style="color: blue">this</span> <span style="color: rgb(43,145,175)">IQueryable</span><T> source, <span style="color: blue">string</span> predicate, <span style="color: blue">params</span> <span style="color: blue">object</span>[] values)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span> (<span style="color: rgb(43,145,175)">IQueryable</span><T>)Where((<span style="color: rgb(43,145,175)">IQueryable</span>)source, predicate, values);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">static</span> <span style="color: rgb(43,145,175)">IQueryable</span> Where(<span style="color: blue">this</span> <span style="color: rgb(43,145,175)">IQueryable</span> source, <span style="color: blue">string</span> predicate, <span style="color: blue">params</span> <span style="color: blue">object</span>[] values)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (source == <span style="color: blue">null</span>) <span style="color: blue">throw</span> <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">ArgumentNullException</span>(<span style="color: rgb(163,21,21)">“source”</span>);</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (predicate == <span style="color: blue">null</span>) <span style="color: blue">throw</span> <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">ArgumentNullException</span>(<span style="color: rgb(163,21,21)">“predicate”</span>);</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">LambdaExpression</span> lambda = DynamicExpression.ParseLambda(source.ElementType, <span style="color: blue">typeof</span>(<span style="color: blue">bool</span>), predicate, values);</p> <p style="margin: 0pt"> <span style="color: blue">return</span> source.Provider.CreateQuery(</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">Expression</span>.Call(</p> <p style="margin: 0pt"> <span style="color: blue">typeof</span>(<span style="color: rgb(43,145,175)">Queryable</span>), <span style="color: rgb(163,21,21)">“Where”</span>,</p> <p style="margin: 0pt"> <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">Type</span>[] { source.ElementType },</p> <p style="margin: 0pt"> source.Expression, <span style="color: rgb(43,145,175)">Expression</span>.Quote(lambda)));</p> <p style="margin: 0pt"> } </p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"><span style="color: blue">public</span> IList<TEntity> Where(<span style="color: blue">string</span> predicate, <span style="color: blue">params</span> <span style="color: blue">object</span>[] values)</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> <span style="color: blue">return</span> m_context.GetTable<TEntity>().Where(predicate, values).ToList<TEntity>();</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Of course, the query function is not a problem because we don’t need the properties of the entity when we invoke these methods and don’t care about the composition of Lambda Expression.</p> <p>The key issue is how to update or delete the record of data table. You know, we must fetch the entity which is going to be operated before updating or deleting it. The keyword to search is often its identity. Furthermore, Object Identity and Change Tracking in Data Context need the object’s identity to track the changing of it. Usually, we would add the Id column which is identity or Guid for each table. Then we can fetch the entity object according to it:</p> <div> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Update(Employee employee)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LinqSampleDataContext context = <span style="color: blue">new</span> LinqSampleDataContext();</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> Employee emp = <span style="color: blue">this</span>.Where(e => e.EmployeeID == employee.EmployeeID);</p> <p style="margin: 0pt"> emp.FirstName = <span style="color: rgb(163,21,21)">“First Name”</span>;</p> <p style="margin: 0pt"> emp.LastName = <span style="color: rgb(163,21,21)">“Last Name”</span>;</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Obviously, we don’t know the entity’s properties if we use the generic type such as TEntity like above. Without the keyword how do we associate the changes with the existing record? LINQ introduces the Attach method which can attach the changed object to the context. There are three overloaded versions as below:<br>Attach(Object entity): Attaches an entity to the DataContext in an unmodified state;<br>Attach(Object entity, bool asModified): Attaches all entities of a collection to the DataContext in either a modified or unmodified state.<br>Attach(Object entity, Object orginal): Attaches an entity to the DataContext in either a modified or unmodified state by specifying both the entity and its original state.</p> <p>Attach method is used to associate the deserialized entities to a new instance of a DataContext. However, we can associate the entity in one DataContext to another DataContext by using it. In update or delete case, this method is very useful. For example, we want to update the record according to a changed entity from another DataContext:</p> <div> <div> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Update(TEntity changedEntity)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_context.GetTable<TEntity>().Attach(changedEntity, <span style="color: blue">true</span>);</p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">ChangeConflictException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_context.ChangeConflicts.ResolveAll(<span style="color: rgb(43,145,175)">RefreshMode</span>.KeepCurrentValues);</p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> } </p></div> <p style="margin: 0pt"> </p> <p style="margin: 0pt">It looks good, but not enough. We can’t attach a changed entity unless the entity has a TimeStamp column in the corresponding table. Therefore, we should add a column whose type is TimeStamp in SQL Server 2005, or set the IsVersion property to true for Id property in LINQ to SQL Designer. My advice is to create a TimeStamp column for your datatable, and it will improve the performance because it won’t check all columns whether they are changed during handling concurrency.</p> <p>In fact, we can pass the original entity with generic type also. The only problem is how to pass the values you want to change. The solution to this problem is using Action delegate. The code snippet is as below:</p> <div> <div> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Update(TEntity originalEntity, <span style="color: rgb(43,145,175)">Action</span><TEntity> update)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_context.GetTable<TEntity>().Attach(originalEntity);</p> <p style="margin: 0pt"> update(originalEntity);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">ChangeConflictException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_context.ChangeConflicts.ResolveAll(<span style="color: rgb(43,145,175)">RefreshMode</span>.KeepCurrentValues);</p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> } </p></div> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Now we can invoke it passing Lambda expression like this:</p> <div> <p style="margin: 0pt"> [<span style="color: rgb(43,145,175)">TestMethod</span>()]</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> UpdateWithAction()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> LinqSampleDataContext context = <span style="color: blue">new</span> LinqSampleDataContext();</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">EmployeeAccessor</span> accessor = <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">EmployeeAccessor</span>();</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">Employee</span> employee = context.Employees.Single(e => e.EmployeeID == 1);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> accessor.Update(employee, t => { t.FirstName = <span style="color: rgb(163,21,21)">“First”</span>; t.LastName = <span style="color: rgb(163,21,21)">“Last”</span>; });</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Unfortunately, the test case can’t pass sometimes. It will throw a NotSupportedException. And the message of exception is:<br>An attempt has been made to Attach or Add an entity that is not new, perhaps having been loaded from another DataContext. This is not supported.</p> <p>Why? What happens? The real reason is the entity we handle has some associations with other entities. Please see figure 1:</p> <p style="margin: 0pt"><img class="aligncenter size-full wp-image-79" title="linqbaseclass01" style="display: block; float: none; margin-left: auto; margin-right: auto" height="293" alt="linqbaseclass01" src="http://brucezhang.files.wordpress.com/2009/05/linqbaseclass01.gif?w=320&h=293&h=293" width="320"></p></div></div></div></div></div></div> <p style="text-align: center">Figure 1 : The entity with association</p> <p>If you remove all relationships in Employee table, and re-generated the data model, the test case would pass.</p> <p>What shall we do? Of course, to remove all relationships of table explicitly is not a good way to solve the issue. It will impact on the whole data model and can’t be accepted when we develop the application. I found one guy, Steve Michelotti, raised one solution to solve it. That was to provide one method called Detach to remove the relationships using partial class:</p> <div> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">partial</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">Contact</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Detach()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">foreach</span> (<span style="color: rgb(43,145,175)">Address</span> address <span style="color: blue">in</span> <span style="color: blue">this</span>.Addresses)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> address.Detach();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">partial</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">Address</span></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Detach()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">this</span>._AddressType = <span style="color: blue">default</span>(EntityRef<AddressType>);</p> <p style="margin: 0pt"> <span style="color: blue">this</span>._State = <span style="color: blue">default</span>(EntityRef<State>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">} </p></div> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Good job! But it is not perfect. First, it’s too complex because we must define the Detach method for every entity which has association with others. Second, we can’t abstract it to the base class in this way. In the base class, we don’t know the specific type of TEntity. In this case, we should turn to the reflection technology. It’s my way:</p> <div> <p style="margin: 0pt"> <span style="color: blue">private</span> <span style="color: blue">void</span> Detach(TEntity entity)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">foreach</span> (<span style="color: rgb(43,145,175)">FieldInfo</span> fi <span style="color: blue">in</span> entity.GetType().GetFields(<span style="color: rgb(43,145,175)">BindingFlags</span>.NonPublic | <span style="color: rgb(43,145,175)">BindingFlags</span>.Instance))</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (fi.FieldType.ToString().Contains(<span style="color: rgb(163,21,21)">“EntityRef”</span>))</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">var</span> value = fi.GetValue(entity);</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (value != <span style="color: blue">null</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> fi.SetValue(entity, <span style="color: blue">null</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (fi.FieldType.ToString().Contains(<span style="color: rgb(163,21,21)">“EntitySet”</span>))</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">var</span> value = fi.GetValue(entity);</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (value != <span style="color: blue">null</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">MethodInfo</span> mi = value.GetType().GetMethod(<span style="color: rgb(163,21,21)">“Clear”</span>);</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (mi != <span style="color: blue">null</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> mi.Invoke(value, <span style="color: blue">null</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> fi.SetValue(entity, value);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">For EntityRef fields, we may set their values to null by calling the SetValue of FieldInfo class to remove the relationship. However, we can’t do EntitySet in the same way because it is a collection. If set to null, it will throw exception. So I get the method information of the field and invoke the Clear method to clear all items in this collection. Finally, my implementation of Update method is as below:</p> <div> <div> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Update(TEntity originalEntity, <span style="color: rgb(43,145,175)">Action</span><TEntity> update, <span style="color: blue">bool</span> hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//Remove the relationship between the entitis</span></p> <p style="margin: 0pt"> Detach(originalEntity);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> m_context.GetTable<TEntity>().Attach(originalEntity);</p> <p style="margin: 0pt"> update(originalEntity);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">ChangeConflictException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_context.ChangeConflicts.ResolveAll(<span style="color: rgb(43,145,175)">RefreshMode</span>.KeepCurrentValues);</p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p></div> <p style="margin: 0pt">Delete operation is similar except we don’t need invoke the second version of Attach (Attach(object entity, bool asModified)). Here is the code snippet:</p> <div> <div> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Delete(TEntity entity, <span style="color: blue">bool</span> hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//Remove the relationship between the entities;</span></p> <p style="margin: 0pt"> Detach(entity);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> m_context.GetTable<TEntity>().Attach(entity);</p> <p style="margin: 0pt"> m_context.GetTable<TEntity>().DeleteOnSubmit(entity);</p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">ChangeConflictException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_context.ChangeConflicts.ResolveAll(<span style="color: rgb(43,145,175)">RefreshMode</span>.KeepCurrentValues);</p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Delete(<span style="color: rgb(43,145,175)">IList</span><TEntity> entities, <span style="color: blue">bool</span> hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//Remove the relationship</span></p> <p style="margin: 0pt"> <span style="color: blue">foreach</span> (TEntity entity <span style="color: blue">in</span> entities)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> Detach(entity);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> m_context.GetTable<TEntity>().AttachAll(entities);</p> <p style="margin: 0pt"> m_context.GetTable<TEntity>().DeleteAllOnSubmit(entities);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">ChangeConflictException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_context.ChangeConflicts.ResolveAll(<span style="color: rgb(43,145,175)">RefreshMode</span>.KeepCurrentValues);</p> <p style="margin: 0pt"> m_context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> } </p></div> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Don’t worry about the correctness of final result when we remove the relationship between the entities. The Attach method is just responsible for associating the entity to a new instance of DataContext to track the change. When you submit the changes, DataContext will check the real value in the mapping database and update or delete the record according to the passed entity. Especially, you should take an action such as Cascade in the database if you want to cascade delete between foreign key table and primary key table, see figure 2.</p> <p style="margin: 0pt"><img class="aligncenter size-full wp-image-80" title="linqbaseclass02" style="display: block; float: none; margin-left: auto; margin-right: auto" height="364" alt="linqbaseclass02" src="http://brucezhang.files.wordpress.com/2009/05/linqbaseclass02.gif?w=563&h=364&h=364" width="563"></p> <div style="text-align: center">Figure 2: Set the delete rule</div> <p style="margin: 0pt">If no action, the System.Data.SqlClient.SqlException will be thrown and the message of it when you delete the entity as Primary Key table, like this:<br>The DELETE statement conflicted with the REFERENCE constraint “FK_Orders_Employees”. The conflict occurred in database “Northwind”, table “dbo.Orders”, column ‘EmployeeID’.</p> <p>Maybe you notice the InitDataContext method is invoked in all methods to access the data. Its implementation like this:</p> <div> <p style="margin: 0pt"> <span style="color: blue">private</span> TContext m_context = <span style="color: blue">null</span>;</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">private</span> TContext CreateContext()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">return</span> <span style="color: rgb(43,145,175)">Activator</span>.CreateInstance<TContext>() <span style="color: blue">as</span> TContext;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">private</span> <span style="color: blue">void</span> InitDataContext()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> m_context = CreateContext();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Why do we need create a new instance of DataContext for each method? The reason is Caching policy in DataContext. If you create a new instance of DataContext and query the data from the database though by it, then change its value and execute the next query though by the same instance, the DataContext will return the data stored in the internal cache rather than remapping the row to the table. For more information, please refer to the Linq in Action.</p> <p>So, the best practice is to create a new instance of DataContext for each operation. Don’t worry about the performance, the DataContext is lightweight resource.</p> <p>Let’s consider about the concurrency issue. The default option is Optimistic Concurrency. When the values are to be saved, the DataContext would check the previous values to see if they have been changed. If conflict occurs, the DataContext would need to know whether to automatically overwrite the previous changes, keep the previous changes, or somehow merge the changes.</p> <p>The concurrency issue is not within the scope of this article. We can’t say which one of three ways is the best or worst, it depends on the business situation. Usually, I will handle concurrency by the rule of last submit win. So I encapsulate the SubmitChanges method and define it as visual method, if necessary, the subclass may override it:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">AccessorBase</span><TEntity, TContext></p> <p style="margin: 0pt"> <span style="color: blue">where</span> TEntity : <span style="color: blue">class</span>, <span style="color: blue">new</span>()</p> <p style="margin: 0pt"> <span style="color: blue">where</span> TContext : <span style="color: rgb(43,145,175)">DataContext</span>, <span style="color: blue">new</span>()</p> <p style="margin: 0pt">{</p> <p style="margin: 0pt"> <span style="color: blue">private</span> TContext m_context = <span style="color: blue">null</span>;</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><summary></span></p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> It provides the default policy to handle the corrency conflict</span></p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"></summary></span></p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><param name=”context”></span><span style="color: green">Data Context</span><span style="color: gray"></param></span></p> <p style="margin: 0pt"> <span style="color: blue">protected</span> <span style="color: blue">virtual</span> <span style="color: blue">void</span> SubmitChanges(TContext context)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> context.SubmitChanges(<span style="color: rgb(43,145,175)">ConflictMode</span>.ContinueOnConflict);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">ChangeConflictException</span>)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> context.ChangeConflicts.ResolveAll(<span style="color: rgb(43,145,175)">RefreshMode</span>.KeepCurrentValues);</p> <p style="margin: 0pt"> context.SubmitChanges();</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">Exception</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> ex;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><summary></span></p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> Update the entity which was passed</span></p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> The changedEntity cann’t have the relationship between the entities</span></p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"></summary></span></p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><param name=”originalEntity”></span><span style="color: green">It must be unchanged entity in another data context</span><span style="color: gray"></param></span><span style="color: green"> </span></p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><param name=”update”></span><span style="color: green">It is Action</span><span style="color: gray"><T></span><span style="color: green">delegate, it can accept Lambda Expression.</span><span style="color: gray"></param></span><span style="color: green"> </span></p> <p style="margin: 0pt"> <span style="color: gray">///</span><span style="color: green"> </span><span style="color: gray"><param name=”hasRelationship”></span><span style="color: green">Has relationship between the entities</span><span style="color: gray"></param></span></p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> Update(TEntity originalEntity, <span style="color: rgb(43,145,175)">Action</span><TEntity> update, <span style="color: blue">bool</span> hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> InitDataContext();</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">try</span></p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">if</span> (hasRelationship)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: green">//Remove the relationship between the entitis</span></p> <p style="margin: 0pt"> Detach(originalEntity);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> m_context.GetTable<TEntity>().Attach(originalEntity);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> update(originalEntity);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> SubmitChanges(m_context);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">InvalidCastException</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> ex;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">NotSupportedException</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> ex;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> <span style="color: blue">catch</span> (<span style="color: rgb(43,145,175)">Exception</span> ex)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: blue">throw</span> ex;</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Now, we have a common base class which can be derived to handle the entity. For example:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">EmployeeAccessor</span> : <span style="color: rgb(43,145,175)">AccessorBase</span><Employee, NorthwindDataContext></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">You don’t need implement any method. It’s more convenient to access the Employee table by using an instance of EmployeeAccessor:</p> <div> <p style="margin: 0pt"> [<span style="color: rgb(43,145,175)">TestMethod</span>()]</p> <p style="margin: 0pt"> <span style="color: blue">public</span> <span style="color: blue">void</span> UpdateEmployee()</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">EmployeeAccessor</span> accessor = <span style="color: blue">new</span> <span style="color: rgb(43,145,175)">EmployeeAccessor</span>();</p> <p style="margin: 0pt"> <span style="color: rgb(43,145,175)">IList</span><<span style="color: rgb(43,145,175)">Employee</span>> entities = accessor.Where(e => e.EmployeeID == 1);</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> <span style="color: blue">if</span> (entities != <span style="color: blue">null</span> && entities.Count > 0)</p> <p style="margin: 0pt"> {</p> <p style="margin: 0pt"> entities[0].FirstName = <span style="color: rgb(163,21,21)">“Bruce”</span>;</p> <p style="margin: 0pt"> entities[0].LastName = <span style="color: rgb(163,21,21)">“Zhang”</span>;</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"> accessor.Update(entities[0], <span style="color: blue">true</span>, <span style="color: blue">true</span>);</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> }</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">You may let Employee entity derive my base class directly even:</p> <div> <p style="margin: 0pt"><span style="color: blue">public</span> <span style="color: blue">partial</span> <span style="color: blue">class</span> <span style="color: rgb(43,145,175)">Employee</span> : <span style="color: rgb(43,145,175)">AccessorBase</span><<span style="color: rgb(43,145,175)">Employee</span>, NorthwindDataContext></p> <p style="margin: 0pt">{</p> <p style="margin: 0pt">}</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Its behavior is very similar with Rich Domain Model like Martin Fowler said in the article which title is Anemic Domain Model.</p> <p style="margin: 0pt"> </p> <p style="margin: 0pt">Download Source Code: <a href="http://www.agiledon.com/upload/LinqSample_Src.zip" target="_blank" rel="#someid0">LinqSample_Src.zip 368KB</a></p> <p style="margin: 0pt"> </p> <p style="margin: 0pt"><strong>Note</strong>: The database which my sample use is Northwind in SQL Server 2005 and I add a new column which type is TimeStamp for each table.</p></div></div></div></div></div></div></div></div></div></div></div></div></div> Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0tag:blogger.com,1999:blog-5903747819026143561.post-85115995661466136942008-07-27T19:15:00.000+08:002008-07-27T20:15:30.389+08:00Sprint #2 not GoodIn our retrospection meeting on Thursday, I pointed out some issues during the Sprint #2 this month.<br /><br />1. Sprint Backlog was not exact. Product Owner in our team was not familiar with Scrum and how to analyze the business functions. So we can't do Product Backlog well, I mean, the category and decomposition of backlog items is not good. We didn't find the best way to describe and find out the backlog items we can handle. It was the source of everything couldn't go on well. Without good Product backlog, it was impossible to have the correct Sprint Backlog.<br /><br />2. The estimate of workload was not exact. In fact, you could never estimate the workload of your project correctly. But you should try your best by using your work experience and skill. If you couldn't make a decision or had no confidence, you should make use of the knowledge of your team members. For example, you should lead your members to estimate the time using planning poker like Henrik Kniberg said in <span style="font-style: italic;">Scrum and XP from the trenches</span>.<br /><br />3. No effective tracking of task. In Sprint Planning meeting, we assigned the backlog items and tasks to everybody in our team. Then we inputted the information into the Sprint backlog file. But Scrum Master involved in too many trivial issues so that he had no time to track the process of development. The only one way is Daily Meeting. The result is not good because we had no visible policy to represent the status of the task whether it was completed or not.<br /><br />Something need to changed! Yes, we have to do.Bruce Zhanghttp://www.blogger.com/profile/09904477016151262988noreply@blogger.com0