<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-3831136297442839246</atom:id><lastBuildDate>Mon, 16 Jan 2012 13:06:08 +0000</lastBuildDate><category>Python</category><category>interop</category><category>SQL</category><category>Enterprise lib</category><category>Prism</category><category>initializer</category><category>ESB</category><category>CAB</category><category>localization</category><category>messaging</category><category>sip</category><category>SOA</category><category>XAML</category><category>OSS</category><category>addin</category><category>RSpec</category><category>facelets</category><category>Caliburn</category><category>powershell</category><category>TopShelf</category><category>git</category><category>Unity</category><category>StructureMap</category><category>LogBook</category><category>Windsor castle</category><category>linq</category><category>wizard</category><category>pjsip4net</category><category>IoC</category><category>patterns</category><category>NoSql</category><category>Rails</category><category>Java</category><category>links</category><category>RichFaces</category><category>SCSF</category><category>config</category><category>misc</category><category>DI</category><category>queue</category><category>C#</category><category>Redis</category><category>VoIP</category><category>ReSharper</category><category>NServiceBus</category><category>OSC</category><category>WCF</category><category>Ruby</category><category>template method</category><category>Django</category><category>DM-V-VM</category><category>NHibernate</category><category>JSF</category><category>VAB</category><category>architecture</category><category>WPF</category><title>Boblog</title><description /><link>http://bobbbloggg.blogspot.com/</link><managingEditor>noreply@blogger.com (RobertT)</managingEditor><generator>Blogger</generator><openSearch:totalResults>58</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/blogspot/Bobbbbloggg" /><feedburner:info uri="blogspot/bobbbbloggg" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-4252407314519937552</guid><pubDate>Mon, 16 Jan 2012 13:06:00 +0000</pubDate><atom:updated>2012-01-16T05:06:08.302-08:00</atom:updated><title>How do you tell a good code?</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;span style="font-family: Verdana, sans-serif;"&gt;Agreed with Ayende:&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Verdana, sans-serif;"&gt;"...&lt;span style="background-color: white; color: #333333; font-size: 16px; line-height: 16px; text-align: -webkit-auto;"&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="background-color: white; color: #333333; font-size: 16px; line-height: 16px; text-align: -webkit-auto;"&gt;most good code bases are actually fairly boring. That is pretty much the definition of a good codebase..."&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; color: #333333; font-size: 16px; line-height: 16px; text-align: -webkit-auto;"&gt;&lt;span style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; color: #333333; font-size: 16px; line-height: 16px; text-align: -webkit-auto;"&gt;&lt;span style="font-family: Verdana, sans-serif;"&gt;&lt;a href="http://ayende.com/blog/153697/a-meta-post-about-negative-code-reviews"&gt;Source&lt;/a&gt;.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; color: #333333; font-size: 16px; line-height: 16px; text-align: -webkit-auto;"&gt;&lt;span style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="background-color: white; color: #333333; font-size: 16px; line-height: 16px; text-align: -webkit-auto;"&gt;&lt;span style="font-family: Verdana, sans-serif;"&gt;Good luck!&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-4252407314519937552?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=p4k4Mcfp6Z4:M2uQFhnvJk8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=p4k4Mcfp6Z4:M2uQFhnvJk8:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=p4k4Mcfp6Z4:M2uQFhnvJk8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=p4k4Mcfp6Z4:M2uQFhnvJk8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/p4k4Mcfp6Z4" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/p4k4Mcfp6Z4/how-do-you-tell-good-code.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2012/01/how-do-you-tell-good-code.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-3718399544413806989</guid><pubDate>Sun, 15 Jan 2012 20:30:00 +0000</pubDate><atom:updated>2012-01-15T12:34:32.986-08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Ruby</category><category domain="http://www.blogger.com/atom/ns#">RSpec</category><category domain="http://www.blogger.com/atom/ns#">Rails</category><title>Speed up rails3 rspec2</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;span style="font-family: Verdana, sans-serif;"&gt;If you've eventually fell asleep while waiting for your test suits to run, here's a good description on how to &lt;a href="http://www.rubyinside.com/how-to-rails-3-and-rspec-2-4336.html"&gt;speed it up&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Verdana, sans-serif;"&gt;PS One little nitpick: all of the spork commands should be executed in bundle exec context as long we use bundler insted of rubygems.&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style="font-family: Verdana, sans-serif;"&gt;Good luck!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-3718399544413806989?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=fYCUz_1XlIg:tN9Q9jFp_rg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=fYCUz_1XlIg:tN9Q9jFp_rg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=fYCUz_1XlIg:tN9Q9jFp_rg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=fYCUz_1XlIg:tN9Q9jFp_rg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/fYCUz_1XlIg" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/fYCUz_1XlIg/speed-up-rails3-rspec2-execution.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2012/01/speed-up-rails3-rspec2-execution.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-4929807970177732389</guid><pubDate>Tue, 13 Sep 2011 07:32:00 +0000</pubDate><atom:updated>2011-09-13T00:33:09.131-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">powershell</category><title>Calculate LOC with one line of code</title><description>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Found a very useful tip on how to quickly estimate the size of a project with only one line of powershell script.&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Navigate to the root directory of your project and in powershell type the following:&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;(dir -include *.cs,*.xaml -recurse | select-string .).Count&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Thats it.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;Good luck!&lt;/span&gt;&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-4929807970177732389?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=FYghOvvQJ88:sA_0TziHsf4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=FYghOvvQJ88:sA_0TziHsf4:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=FYghOvvQJ88:sA_0TziHsf4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=FYghOvvQJ88:sA_0TziHsf4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/FYghOvvQJ88" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/FYghOvvQJ88/calculate-loc-with-one-line-of-code.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2011/09/calculate-loc-with-one-line-of-code.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-2584578385433528772</guid><pubDate>Thu, 11 Aug 2011 18:12:00 +0000</pubDate><atom:updated>2011-08-11T14:23:04.525-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">WPF</category><category domain="http://www.blogger.com/atom/ns#">Caliburn</category><title>Execute Caliburn coroutine in action pipeline without UI trigger</title><description>&lt;span class="Apple-style-span"  &gt;Seems rather easy, isn't it? &lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Just put it into Presenter's Execute method and the did is done. Well, should it be like that I wouldn't wake up in the night and write this stuff!
&lt;br /&gt;Let's see what's there in Execute:
&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_aPBCtYeet9E/TRyBqxFhS7I/AAAAAAAAMPc/fuX2ODzwnj8/s1600/Execute.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor: pointer; width: 400px; height: 114px;" src="http://3.bp.blogspot.com/_aPBCtYeet9E/TRyBqxFhS7I/AAAAAAAAMPc/fuX2ODzwnj8/s400/Execute.png" alt="" id="BLOGGER_PHOTO_ID_5556458611999329202" border="0" /&gt;&lt;/a&gt;
&lt;br /&gt;So, it just packs every single coroutine it has in SequentialResult and execute 'em. No filters pipeline used, no routedMessage. None of your neat filters applied to these coroutines.
&lt;br /&gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;You might ask what is the difference with executing coroutines as a result of some UI action, be it a routed event or a command. The answer is in the Caliburn.PresentationFramework.Actions namespace.
&lt;br /&gt;To be prrecise it is an Action Execute overloaded method that in simple case of SynchronousAction does the following:
&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_aPBCtYeet9E/TRyD11060MI/AAAAAAAAMPs/AlHasxeE4RU/s1600/Action.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}"&gt;&lt;img style="cursor: pointer; width: 400px; height: 164px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/TRyD11060MI/AAAAAAAAMPs/AlHasxeE4RU/s400/Action.png" alt="" id="BLOGGER_PHOTO_ID_5556461001273692354" border="0" /&gt;&lt;/a&gt;
&lt;br /&gt;namely calls preprocessor filters, delegates a call to method that might be returning coroutine, handles errors with rescue filters, calls postprocessor filters. That is a filter pipeline I am talking about.
&lt;br /&gt;Well, seems that Caliburn has everything I need. And all I have to do is just use it. &lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;As header states there is no UI trigger, i.e. I want to execute a coroutine when nobody clicked a button, but rather on some external trigger. As an example, consider model update with call to any data storage during Presenter initialization stage.
&lt;br /&gt;
&lt;br /&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Enter DegenerateMessage. This intellectual piece of code is a data container that is being handed to participants on courutine call pipeline in order to hint what was the original method name called.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;img src="http://2.bp.blogspot.com/-u6-xGewWtwI/TkPUu3TFvlI/AAAAAAAAMWE/RUPA_VSn6Z0/s400/DegenerateMessage.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5639585059981082194" style="cursor: pointer; width: 332px; height: 400px; " /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Another intellectual piece of code is DegenerateMessageTrigger. It is so damn smart that it knows that in order to trigger an action it has to pass a message to message handler!  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;img src="http://1.bp.blogspot.com/-jUrePoV1ek8/TkPUu0y4iwI/AAAAAAAAMWM/cIFQj4aL6zU/s400/DegenerateTrigger.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5639585059309128450" style="cursor: pointer; width: 400px; height: 211px; " /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;And yet another piece is a DegenerateMessageHandler. It really shouldn't be called that way as it performs really complicated things. Namely, it creates an ActionHost and when Process is called converts DegenerateMessage to an ActionMessage and put it into the standard Caliburn action pipeline.  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;img src="http://2.bp.blogspot.com/-4sxOZ2gQhKM/TkPUujZiknI/AAAAAAAAMV8/0u8x1086KmU/s400/DegenerateHandler.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5639585054639428210" style="cursor: pointer; width: 397px; height: 400px; " /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;If it seems like dancing on your head, then know that you are not alone. But wait, there is another part I forgot to mention. It is a simple interface IResultExecutor aimed to hide all that smart code under two methods accepting Expressions with lambdas calling methods that return coroutines.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Oh, and there is yet another thing. With &lt;a href="http://caliburnmicro.codeplex.com/"&gt;Caliburn Micro&lt;/a&gt; you can accomplish the same with &lt;a href="http://mikaelkoskinen.net/post/caliburn-micro-wp7-coroutines-without-user-input.aspx"&gt;only one line of code&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;
&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Cheers! &lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-2584578385433528772?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=qI9Ekj9mRF0:AgCi0zvSFqk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=qI9Ekj9mRF0:AgCi0zvSFqk:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=qI9Ekj9mRF0:AgCi0zvSFqk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=qI9Ekj9mRF0:AgCi0zvSFqk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/qI9Ekj9mRF0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/qI9Ekj9mRF0/execute-caliburn-coroutine-in-action.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_aPBCtYeet9E/TRyBqxFhS7I/AAAAAAAAMPc/fuX2ODzwnj8/s72-c/Execute.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2011/08/execute-caliburn-coroutine-in-action.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-7679726914922495397</guid><pubDate>Thu, 04 Aug 2011 06:56:00 +0000</pubDate><atom:updated>2011-08-04T00:01:13.819-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">queue</category><category domain="http://www.blogger.com/atom/ns#">messaging</category><category domain="http://www.blogger.com/atom/ns#">ESB</category><title>The best explanation to ESB ever.</title><description>&lt;span class="Apple-style-span"  &gt;I've finally managed to reread some of old Udi's &lt;a href="http://www.udidahan.com/2007/04/28/the-enterprise-service-bus-and-your-soa/"&gt;articles&lt;/a&gt; and suddenly realized that following few lines are the best explanation of what ESB is all about, ever.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;I never want to miss it again that is why I repost it right here in my blog.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;i&gt;"&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51); "&gt;it’s all in the message. Forget about remote method invocations and pub-subbing events—down on the wire it’s all just messages. The trick is to think of your system as passing messages at the application level as well.&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51); "&gt;&lt;span class="Apple-style-span"  &gt;&lt;i&gt;&lt;p&gt;Asynchronous message passing over queues. It’s really quite simple.&lt;/p&gt;&lt;p&gt;Once you’ve packaged everything into the message, that message can be dynamically routed anywhere, and so can its responses. The application doesn’t need to bind against any specific endpoint—it just drops a message addressed to some logical location. Infrastructure can make sure that messages get to the logical recipient, even if they change physical locations.&lt;/p&gt;&lt;/i&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;i&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51); "&gt;That infrastructure is what brings about the “Bus” architectural style between your distributed components.&lt;/span&gt;"&lt;/i&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;As Udi says, you have to reread it several dozens of times, until it strikes to you.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Good luck!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-7679726914922495397?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=SSvXp3pMJWc:ooCPuueiNOw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=SSvXp3pMJWc:ooCPuueiNOw:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=SSvXp3pMJWc:ooCPuueiNOw:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=SSvXp3pMJWc:ooCPuueiNOw:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/SSvXp3pMJWc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/SSvXp3pMJWc/best-explanation-to-esb-ever.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2011/08/best-explanation-to-esb-ever.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-7142209846565496465</guid><pubDate>Tue, 19 Jul 2011 20:50:00 +0000</pubDate><atom:updated>2011-07-19T13:51:04.836-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">git</category><title>Git ftp deploy</title><description>&lt;span class="Apple-style-span"  &gt;With tools like git, NServiceBus, RoR and the rest, life seams to be better then ever.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;With git I've managed to setup deployment with a matter of minutes. Just like this: &lt;a href="http://blog.wekeroad.com/2009/11/23/deploying-a-web-application-with-git-and-ftp"&gt;http://blog.wekeroad.com/2009/11/23/deploying-a-web-application-with-git-and-ftp&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;There are other ways, probably even simplier: &lt;a href="http://ayende.com/blog/4836/primitive-git-auto-deploy"&gt;http://ayende.com/blog/4836/primitive-git-auto-deploy&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Good luck!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-7142209846565496465?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=QvRjzAZRc-0:mCCLrrDUnUk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=QvRjzAZRc-0:mCCLrrDUnUk:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=QvRjzAZRc-0:mCCLrrDUnUk:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=QvRjzAZRc-0:mCCLrrDUnUk:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/QvRjzAZRc-0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/QvRjzAZRc-0/git-ftp-deploy.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2011/07/git-ftp-deploy.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-5423510205923939311</guid><pubDate>Sun, 05 Jun 2011 19:12:00 +0000</pubDate><atom:updated>2011-06-05T12:17:12.517-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Django</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>Django newby frustrations.</title><description>&lt;span class="Apple-style-span"  &gt;As you might already guessed, I am currently in a process of discovering two technologies I had no experience with before. &lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;This time I met a strange error running a Django tutorial web application: UnicodeDecodeError: 'ascii' codec can't decode byte 0xe0...&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;The simplest solution to this can be found here: &lt;a href="http://victor-k-development.blogspot.com/2010/07/unicodedecodeerror-django.html"&gt;http://victor-k-development.blogspot.com/2010/07/unicodedecodeerror-django.html&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;But the roots of the problem and an ultimate solution are to be found here: &lt;a href="http://stackoverflow.com/questions/4237898/unicodedecodeerror-ascii-codec-cant-decode-byte-0xe0-in-position-0-ordinal"&gt;http://stackoverflow.com/questions/4237898/unicodedecodeerror-ascii-codec-cant-decode-byte-0xe0-in-position-0-ordinal&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Good luck!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-5423510205923939311?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=oSM0nUGnJ4Q:n_-FR62RWuE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=oSM0nUGnJ4Q:n_-FR62RWuE:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=oSM0nUGnJ4Q:n_-FR62RWuE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=oSM0nUGnJ4Q:n_-FR62RWuE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/oSM0nUGnJ4Q" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/oSM0nUGnJ4Q/django-newby-frustrations.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2011/06/django-newby-frustrations.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-5522067290708019563</guid><pubDate>Sun, 05 Jun 2011 12:51:00 +0000</pubDate><atom:updated>2011-06-05T06:02:17.138-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Ruby</category><category domain="http://www.blogger.com/atom/ns#">Rails</category><title>RoR newby frustrations</title><description>&lt;span class="Apple-style-span"  &gt;As usual, trying to adopt something new is really is a frustration. And though Rails is about to be "&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51); line-height: 22px; "&gt;a breakthrough in lowering the barriers of entry to programming&lt;/span&gt;" you will defenitely meet some errors that might stop you on your way.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;First thing I met was: "[rake --tasks] rake aborted! no such file to load -- sqlite3/sqlite3_native".&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;The solution is really simple. Rake is telling you that it can't find a native library for sqlite. Well, just do what you've been told. Give it a sqlite.dll/.so (depends on OS you are). Put it in $ruby_home\bin.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Next thing to immedeately pop up, after I gave it what it wanted was: "[rake --tasks] WARNING: Global access to Rake DSL methods is deprecated." This one is not as obvious as former. Solution to this one is desribed here: &lt;a href="http://benwoodall.com/2011/06/rails-global-access-to-rake-dsl-methods-is-deprecated/"&gt;http://benwoodall.com/2011/06/rails-global-access-to-rake-dsl-methods-is-deprecated/&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;That's it for now.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;a href="http://benwoodall.com/2011/06/rails-global-access-to-rake-dsl-methods-is-deprecated/"&gt;&lt;/a&gt;Good luck! &lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-5522067290708019563?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=xPw_cIWmh3I:DiVVoprFdcs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=xPw_cIWmh3I:DiVVoprFdcs:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=xPw_cIWmh3I:DiVVoprFdcs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=xPw_cIWmh3I:DiVVoprFdcs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/xPw_cIWmh3I" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/xPw_cIWmh3I/ror-newby-frustrations.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2011/06/ror-newby-frustrations.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-6072408125846789544</guid><pubDate>Wed, 01 Jun 2011 16:23:00 +0000</pubDate><atom:updated>2011-06-01T09:26:07.332-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Ruby</category><category domain="http://www.blogger.com/atom/ns#">Rails</category><title>Installing rails on windows</title><description>&lt;span class="Apple-style-span"  &gt;If you tried to install rails with gems and failed with message "...No such file or directory" - dont woly be hapy. Just folllow these instructions: &lt;a href="http://stackoverflow.com/questions/849660/how-to-stop-the-gem-utility-from-accessing-my-home-directory"&gt;http://stackoverflow.com/questions/849660/how-to-stop-the-gem-utility-from-accessing-my-home-directory&lt;/a&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Good luck!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-6072408125846789544?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=D_aetOe4H0Y:Mx2eusPar5s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=D_aetOe4H0Y:Mx2eusPar5s:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=D_aetOe4H0Y:Mx2eusPar5s:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=D_aetOe4H0Y:Mx2eusPar5s:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/D_aetOe4H0Y" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/D_aetOe4H0Y/installing-rails-on-windows.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2011/06/installing-rails-on-windows.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-8190482116662498396</guid><pubDate>Tue, 24 May 2011 13:31:00 +0000</pubDate><atom:updated>2011-05-24T06:39:27.249-07:00</atom:updated><title>JetBrains dotPeek to rescue.</title><description>&lt;span class="Apple-style-span"  &gt;I don't know how you faced the fact that Reflector is no longer free, but I for one was very-very dissapointed. Now, our favorite JetBrains team comes to rescue with their brand new tool called dotPeek.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Go and get it &lt;a href="http://www.jetbrains.com/decompiler/"&gt;here&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;PS. Five minutes later I found another tool that will compete to take Reflector's place - JustDecompile from Telerik. It is &lt;a href="http://www.telerik.com/products/decompiling.aspx"&gt;here&lt;/a&gt;. &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;PPS. Also, there is a work being done for Silverlight by &lt;a href="http://denisvuyka.wordpress.com/2011/04/27/il-view-net-reflector-oss-alternative-in-silverlight/"&gt;Denis Vuyka&lt;/a&gt; and there is another OSS tool to compete for our souls - &lt;a href="http://wiki.sharpdevelop.net/ilspy.ashx"&gt;ILSpy&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;PPPS. Life is good again.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  &gt;Good luck.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-8190482116662498396?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=UlfUXw3e9zE:j6SzspwtRYg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=UlfUXw3e9zE:j6SzspwtRYg:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=UlfUXw3e9zE:j6SzspwtRYg:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=UlfUXw3e9zE:j6SzspwtRYg:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/UlfUXw3e9zE" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/UlfUXw3e9zE/jetbrains-dotpeek-to-rescue.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>1</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2011/05/jetbrains-dotpeek-to-rescue.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-2916865725534338666</guid><pubDate>Mon, 16 May 2011 08:15:00 +0000</pubDate><atom:updated>2011-05-16T02:42:40.210-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">NServiceBus</category><title>NServiceBus Saga Idempotency</title><description>&lt;span class="Apple-style-span"&gt;Should your business entities had a natural identifier (I think even a surrogate one would do in this case), it would be trivial to ensure idempotency of sagas, that drive their processing.&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Just store that Id in a temporal saga storage and enqueue a handler that will guard your sagas as the first handler in NServiceBus endpoint pipe. Something like this one:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;img src="http://4.bp.blogspot.com/-hgpPcrcN7h8/TdDkNUJUMJI/AAAAAAAAMSs/xRXy3duW9PM/s400/handler.png" style="cursor:pointer; cursor:hand;width: 400px; height: 98px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5607232453473480850" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;And don't forget to specify message handling order:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;img src="http://1.bp.blogspot.com/-tnFca_FaAro/TdDkNYFpZXI/AAAAAAAAMSk/jrx1um0MNWc/s400/config.png" style="cursor:pointer; cursor:hand;width: 400px; height: 98px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5607232454531835250" /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;Good luck!&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-2916865725534338666?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=7r_NONP-wMU:-oCZMehwKLE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=7r_NONP-wMU:-oCZMehwKLE:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=7r_NONP-wMU:-oCZMehwKLE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=7r_NONP-wMU:-oCZMehwKLE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/7r_NONP-wMU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/7r_NONP-wMU/nservicebus-saga-idempotency.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-hgpPcrcN7h8/TdDkNUJUMJI/AAAAAAAAMSs/xRXy3duW9PM/s72-c/handler.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2011/05/nservicebus-saga-idempotency.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-7624213709050057041</guid><pubDate>Mon, 11 Oct 2010 07:58:00 +0000</pubDate><atom:updated>2010-10-11T01:03:38.866-07:00</atom:updated><title>Applying monadic combinators to build simple parser</title><description>&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;After reading &lt;a href="http://blogs.msdn.com/b/lukeh/archive/2007/08/19/monadic-parser-combinators-using-c-3-0.aspx"&gt;this article&lt;/a&gt;, it dawned on me, how easy it might be to write parsers using internal dsl syntax. Looks a bit clumsy in C#, yet rather expressive.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;I've used wonderful &lt;a href="http://www.ohloh.net/p/magnum"&gt;Magnum&lt;/a&gt; &lt;a href="http://code.google.com/p/magnum/"&gt;library &lt;/a&gt;built by &lt;a href="http://drusellers.com/"&gt;Dru Sellers&lt;/a&gt; and &lt;a href="http://code.google.com/p/magnum/people/detail?u=ChrisFromTulsa"&gt;Chris&lt;/a&gt; (creators of open source service bus MassTransit project) as a foundation, since it already contains a base for monadic parsers.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;As an example, look how easy it is to write a parser for following simple grammar, describing file version structure:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:verdana;"&gt;&amp;lt;version&amp;gt; ::= &amp;lt;part&amp;gt;{&amp;lt;delim&amp;gt;&amp;lt;part&amp;gt;|&amp;lt;part&amp;gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&amp;lt;part&amp;gt; ::= &amp;lt;positive integer&amp;gt;+ | &amp;lt;letter&amp;gt;+&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&amp;lt;delim&amp;gt; ::= “.” | “,” | “(” | “)” | “ “&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;And parser in mere 10 lines of code:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" href="http://2.bp.blogspot.com/_aPBCtYeet9E/TLLAp466AGI/AAAAAAAAMN4/iN-IYloqHEI/s1600/versionparser.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 259px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/TLLAp466AGI/AAAAAAAAMN4/iN-IYloqHEI/s400/versionparser.png" alt="" id="BLOGGER_PHOTO_ID_5526691518623645794" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Good luck!&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-7624213709050057041?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=uquyXQabGs0:21UHzkX_4l8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=uquyXQabGs0:21UHzkX_4l8:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=uquyXQabGs0:21UHzkX_4l8:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=uquyXQabGs0:21UHzkX_4l8:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/uquyXQabGs0" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/uquyXQabGs0/applying-monadic-combinators-to-build.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_aPBCtYeet9E/TLLAp466AGI/AAAAAAAAMN4/iN-IYloqHEI/s72-c/versionparser.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2010/10/applying-monadic-combinators-to-build.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-1795330405174241357</guid><pubDate>Wed, 29 Sep 2010 07:20:00 +0000</pubDate><atom:updated>2010-09-29T00:23:52.033-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Unity</category><category domain="http://www.blogger.com/atom/ns#">Windsor castle</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">IoC</category><category domain="http://www.blogger.com/atom/ns#">StructureMap</category><category domain="http://www.blogger.com/atom/ns#">DI</category><title>Dependency injection Presentation</title><description>&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: verdana;"&gt;На слайдах ниже вы найдете презентацию, которую недавно я провел для своих коллег. Цель ее - завлечь в свою религию, шутка, продемонстрировать наглядно преимущества применения DI вживую. Для оживления презентации, используйте код, выложенный &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://rapidshare.com/files/420416655/DI.rar"&gt;здесь&lt;/a&gt;&lt;span style="font-family: verdana;"&gt;.&lt;/span&gt;&lt;/span&gt;&lt;div style="width: 425px; font-family: verdana;" id="__ss_5250166"&gt;&lt;span style="font-size:85%;"&gt;&lt;strong style="margin: 12px 0pt 4px; display: block;"&gt;&lt;a href="http://www.slideshare.net/siniypin/dependency-injection" title="Dependency injection"&gt;Dependency injection&lt;/a&gt;&lt;/strong&gt;&lt;object id="__sse5250166" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=dependencyinjectiondi-100921100133-phpapp02&amp;amp;stripped_title=dependency-injection&amp;amp;userName=siniypin"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed name="__sse5250166" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=dependencyinjectiondi-100921100133-phpapp02&amp;amp;stripped_title=dependency-injection&amp;amp;userName=siniypin" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/span&gt;&lt;div style="padding: 5px 0pt 12px;"&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;P.S. В английской версии блога, я &lt;a href="http://robbbloggg.blogspot.com/2010/09/dependency-injection.html"&gt;немного порассуждал &lt;/a&gt;на тему того, какие "умницы" и как я рад видеть их новые инструменты, но повторяться мне лень . =)&lt;br /&gt;&lt;br /&gt;Удачи!&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-1795330405174241357?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=Q14LUP4SlMk:1Ha16yqZ37M:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=Q14LUP4SlMk:1Ha16yqZ37M:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=Q14LUP4SlMk:1Ha16yqZ37M:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=Q14LUP4SlMk:1Ha16yqZ37M:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/Q14LUP4SlMk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/Q14LUP4SlMk/dependency-injection-presentation.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2010/09/dependency-injection-presentation.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-2374688479097360674</guid><pubDate>Sun, 29 Aug 2010 16:52:00 +0000</pubDate><atom:updated>2010-08-30T12:10:06.371-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sip</category><category domain="http://www.blogger.com/atom/ns#">OSS</category><category domain="http://www.blogger.com/atom/ns#">VoIP</category><category domain="http://www.blogger.com/atom/ns#">pjsip4net</category><title>My two cents in OSS. Free VOIP .Net library!</title><description>&lt;span style=";font-family:verdana;font-size:85%;"  &gt;Мои поздравления всем! Только что в сфере .Net стало одной бесплатной VoIP библиотекой больше. Эта библиотека - моя обертка над C-библиотекой &lt;a href="http://www.pjsip.org/"&gt;pjsip&lt;/a&gt;, точнее над ее высокоуровнем API &lt;a href="http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB.htm"&gt;pjsua&lt;/a&gt; (user agent).&lt;br /&gt;&lt;br /&gt;Работа над ней еще продолжается, но код используется в проектах компании &lt;a href="http://www.doxwox.com/"&gt;DoxWox&lt;/a&gt;, которой выражается отдельное спасибо за возможность опубликовать его. В частности, эта библиотека используется для реализации голосовых конференций в приложении для online общения.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;Прошу любить и жаловать&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;: &lt;a href="http://code.google.com/p/pjsip4net/"&gt;http://code.google.com/p/pjsip4net/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Введение можно почитать здесь:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;a style="font-family: verdana;" href="http://bobbbloggg.blogspot.com/2009/04/designing-managed-api-over-flat-native.html"&gt;http://bobbbloggg.blogspot.com/2009/04/designing-managed-api-over-flat-native.html&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;Частично я уже описывал решения, которыми я руководствовался при создании этой библиотеки, но я планирую более подробно описать здесь внутренности библиотеки, одновременно проводя ее рефакторинг (я, кажется уже упоминал, что работа над ней продолжается ;). Ниже можно почитать о некоторых решениях, примененных в коде:&lt;br /&gt;&lt;a href="http://bobbbloggg.blogspot.com/2009/10/detached-template-method-pattern.html"&gt;http://bobbbloggg.blogspot.com/2009/10/detached-template-method-pattern.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://bobbbloggg.blogspot.com/2009/09/fluent-builder.html"&gt;http://bobbbloggg.blogspot.com/2009/09/fluent-builder.html&lt;/a&gt;&lt;br /&gt;&lt;a href="http://bobbbloggg.blogspot.com/2009/03/initializable-pattern.html"&gt;http://bobbbloggg.blogspot.com/2009/03/initializable-pattern.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Удачи!&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-2374688479097360674?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=AvYXTtJvzdo:hRDdxTx1GDc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=AvYXTtJvzdo:hRDdxTx1GDc:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=AvYXTtJvzdo:hRDdxTx1GDc:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=AvYXTtJvzdo:hRDdxTx1GDc:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/AvYXTtJvzdo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/AvYXTtJvzdo/my-two-cents-in-oss-free-voip-net.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2010/08/my-two-cents-in-oss-free-voip-net.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-9079945278930355875</guid><pubDate>Mon, 09 Aug 2010 09:59:00 +0000</pubDate><atom:updated>2010-08-09T05:16:06.305-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Windsor castle</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">IoC</category><category domain="http://www.blogger.com/atom/ns#">DI</category><title>Windsor Castle BuildUp</title><description>&lt;span style="font-family: verdana;font-size:85%;" &gt;Некоторое время назад я обнаружил, что в лучшем DI-контейнере в .Net сфере Windsor Castle (это мое мнение не подтвержденное никакими фактами, кроме моих высказываний) нет такой простой функциональности как BuildUp. Некоторые из существующих DI-контейнеров, &lt;a href="http://msdn.microsoft.com/en-us/library/ff649576.aspx"&gt;имеют такой метод&lt;/a&gt;, а Castle нет. Это неспроста. Я считаю, что BuildUp - это костыль для ситуаций, имеющих более элегантное решение, но бывают случаи, когда он оправдывает себя. Например, когда скорость решения проблемы важна. Под более элегантным решением я понимаю интеграцию с DI-framework, как, например, &lt;a href="http://using.castleproject.org/display/IoC/Windsor+WCF+integration+facility"&gt;Castle WCF facility&lt;/a&gt;, но понимаете сами, сколько времени и ресурсов нужно для создания полноценного решения.&lt;br /&gt;&lt;br /&gt;Должен признаться, что решение оказалось настолько простым, что я в недоумении, почему раньше этого никто не сделал. Хотя чего там, уже написано выше - костыль. Никто не признается просто.&lt;br /&gt;&lt;br /&gt;Итак, прежде всего нужно ознакомиться с &lt;a href="http://using.castleproject.org/display/IoC/Extension+points"&gt;возможностями расширения&lt;/a&gt; Castle. Лазейка для BuildUp - это &lt;a href="http://www.tunatoksoz.com/post/Castle-Custom-Component-Activators.aspx"&gt;ComponentActivator&lt;/a&gt;. Активаторы вызываются при необходимости создать объект LifetimeManager'ами. Отсюда ограничение решения - с SingletonLifetimeManager оно работать не будет, но и не должно, если подумать. Устанавливая время жизни Singleton вы таким образом явно декларируете, что объектом (коего будет только один экземпляр) владеет контейнер, и создает его он же. А потому BuildUp для такого объекта - вещь бессмысленная.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/TF_qdgcGqJI/AAAAAAAAMMQ/LI-7xh6IiJw/s1600/BuildUpActivator.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 178px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/TF_qdgcGqJI/AAAAAAAAMMQ/LI-7xh6IiJw/s400/BuildUpActivator.png" alt="" id="BLOGGER_PHOTO_ID_5503375062314952850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;BuildUpComponentActivator наследуется от DefaultComponentActivator и переопределяет только один метод - Instantiate. В этом методе мы извлекаем уже существующий и созданный вне контейнера экземпляр из контекста. Если в контексте его нет, то мы делегируем работу по созданию объекта базовому классу.&lt;br /&gt;&lt;br /&gt;В контекст он помещается в методе расширении контейнера BuildUp как дополнительный параметр в IDictionary:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/TF_qd3zbkEI/AAAAAAAAMMY/wp7I6xB6IVM/s1600/BuildUpContainerExt.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 117px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/TF_qd3zbkEI/AAAAAAAAMMY/wp7I6xB6IVM/s400/BuildUpContainerExt.png" alt="" id="BLOGGER_PHOTO_ID_5503375068586807362" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Для того, чтобы объект мог быть пропущен через BuildUp, в компонентной модели для него следует установить ComponentActivator. CanBeBuiltUp оборачивает такой вызов для &lt;a href="http://using.castleproject.org/display/IoC/Fluent+Registration+API"&gt;castle Fluent registration API.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Я говорил, что решение удивительно простое? Это результат работы &lt;a href="http://www.castleproject.org/community/team.html"&gt;коллектива очень талантливых людей&lt;/a&gt;, к коим я не принадлежу, если чо. =)&lt;br /&gt;&lt;br /&gt;Удачи!&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-9079945278930355875?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=NqJ0_als-Lo:KLNjIWkq5uE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=NqJ0_als-Lo:KLNjIWkq5uE:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=NqJ0_als-Lo:KLNjIWkq5uE:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=NqJ0_als-Lo:KLNjIWkq5uE:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/NqJ0_als-Lo" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/NqJ0_als-Lo/windsor-castle-buildup.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_aPBCtYeet9E/TF_qdgcGqJI/AAAAAAAAMMQ/LI-7xh6IiJw/s72-c/BuildUpActivator.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2010/08/windsor-castle-buildup.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-944478386477972021</guid><pubDate>Thu, 24 Jun 2010 07:00:00 +0000</pubDate><atom:updated>2010-06-24T02:16:54.656-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">WPF</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">Prism</category><category domain="http://www.blogger.com/atom/ns#">Caliburn</category><title>Trigger Caliburn action status update through Prism's IEventAggregator</title><description>&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;И Caliburn и Prism, в принципе решают одни и те же задачи - создание композитных приложений на WPF. Но, вот Роб Эйзенберг (создатель Caliburn) не считает, что они друг друга взаимоисключают, а я и подавно с ним согласен.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Я использую следующие "фичи" Prism'a:&lt;/span&gt;&lt;/span&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;modularity;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;region manager;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;event aggregator;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;, а из Caliburn следующие:&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;actions engine;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;application &amp;amp; model framework, даже не смотря на то, что с первого взгляда model framework кажется "overarchitected";&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;convention over configuration;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Вот сейчас я вам расскажу как расширить actions в Caliburn, при помощи Event Aggregator из Prism.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Главный способ расширения - это написание фильтров, которые вставляются в последовательность выполнения action. С их помощью можно проверять предусловия или состояние данных (к примеру можно проверить обладает ли Principal достаточными правами для выполнения действия), дабы определить статус action и обновить эффекты, применяющиеся к UI элементам. Примером такого фильтра является поставляющийся с framework фильтр Dependencies, который вызывает исполнение всей последовательности фильтров, на основании изменения какого-либо свойства, имя которого передается в качестве параметра ему. Но что, если вам нужно просто обновлять статус action, не связанный ни с каким полем в объекте, на основании какого-либо события/условия. Вы можете завести специальное поле и передергивать его значение или даже еще лучше - не заводите никакого поля, а просто кидайте нотификацию с именем несуществующего поля, переданного фильтру. Не знаю как вам, а у меня от таких решений зудит в одном месте.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Так вот зуд мой унялся только когда я написал фильтр, запускающий всю цепочку обработки статуса события по получению уведомления от EventAggregator сервиса Prism.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;DependsOnEvent&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/TCMaqoUQqYI/AAAAAAAAMLE/fQC-jxBr7Pg/s1600/dependsonevent.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 333px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/TCMaqoUQqYI/AAAAAAAAMLE/fQC-jxBr7Pg/s400/dependsonevent.png" alt="" id="BLOGGER_PHOTO_ID_5486258090746620290" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;br /&gt;Фильтр применяется как атрибут, которому передается тип события. Тут есть одно ограничение - событие должно быть унаследовано от generic типа CompositePresentationEvent закрытого типом object, т.е. CompositePresentationEvent_Of_Object. В методе Initialize происходит магия с помощью reflection. Дело в том, что IEventAggregator Prism имеет исключительно generic интерфейс, за что можно разработчиков его только поругать. Мы получаем событие переданного типа и&lt;/span&gt; подписываемся на него. Вот именно для этого и приходится колдовать с волшебным зеркальцем, т.к. заранее тип события не известен. Часть, относящуюся к запуску обработки action, я содрал из кода упомянутого выше Dependencies фильтра.&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/TCMfPb2HAJI/AAAAAAAAMLU/VMCQnGnPBI8/s1600/ihandleraware.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 203px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/TCMfPb2HAJI/AAAAAAAAMLU/VMCQnGnPBI8/s400/ihandleraware.png" alt="" id="BLOGGER_PHOTO_ID_5486263121100603538" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Здесь мы создаем &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://en.wikipedia.org/wiki/Observer_pattern"&gt;Observer&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;, который будет следить за изменениями зависимых свойств. Т.к. реально никакие свойства не меняются я просто использую трюк с несуществующим свойством - в Initialize при подписке на событие я передаю делегат, который кидает событие обновления свойства Update, которого-то как раз и нет. Observer, поймав это событие запускает всю цепочку обновления статуса action.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_aPBCtYeet9E/TCMg9CtxR7I/AAAAAAAAMLc/8qE1WfjeSjk/s1600/dependencyobserver.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 145px;" src="http://3.bp.blogspot.com/_aPBCtYeet9E/TCMg9CtxR7I/AAAAAAAAMLc/8qE1WfjeSjk/s400/dependencyobserver.png" alt="" id="BLOGGER_PHOTO_ID_5486265004140349362" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-weight: bold;"&gt;PublishEventAfter&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Ну и напоследок, фильтр, выполняющий все ровно наоборот, после выполнения action он кидает событие, которое обрабатывает EventAggregator.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_aPBCtYeet9E/TCMg9q-P53I/AAAAAAAAMLk/pZ1h98d21NE/s1600/after.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 299px;" src="http://3.bp.blogspot.com/_aPBCtYeet9E/TCMg9q-P53I/AAAAAAAAMLk/pZ1h98d21NE/s400/after.png" alt="" id="BLOGGER_PHOTO_ID_5486265014946883442" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Удачи!&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-944478386477972021?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=ghewS4Un4Us:BHBB8w8VAO4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=ghewS4Un4Us:BHBB8w8VAO4:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=ghewS4Un4Us:BHBB8w8VAO4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=ghewS4Un4Us:BHBB8w8VAO4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/ghewS4Un4Us" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/ghewS4Un4Us/trigger-caliburn-action-status-update.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_aPBCtYeet9E/TCMaqoUQqYI/AAAAAAAAMLE/fQC-jxBr7Pg/s72-c/dependsonevent.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2010/01/trigger-caliburn-action-status-update.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-1668321676203744678</guid><pubDate>Fri, 07 May 2010 07:57:00 +0000</pubDate><atom:updated>2010-05-07T04:01:04.373-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">TopShelf</category><category domain="http://www.blogger.com/atom/ns#">OSC</category><category domain="http://www.blogger.com/atom/ns#">NoSql</category><category domain="http://www.blogger.com/atom/ns#">Redis</category><title>Plant your Redis into Windows.</title><description>&lt;span style="font-size:85%;"&gt;&lt;a style="font-family: verdana;" href="http://code.google.com/p/redis/"&gt;Redis&lt;/a&gt;&lt;span style="font-family:verdana;"&gt; - это OSC проект, представляющий собой высокопроизводительное key-value хранилище данных. Это вполне зрелый проект, используемый в реальных проектах в production. Написан он на Си, и основные целевые платформы - Linux, *BSD, Mac OS X, Solaris. Казалось бы такой хороший и такой недоступный (для Windows)? Ан нет, мало того что &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://code.google.com/p/servicestack/"&gt;ServiceStack&lt;/a&gt;&lt;span style="font-family:verdana;"&gt; собрали и распространяют дистрибутив под Windows (работает через &lt;a href="http://www.cygwin.com/"&gt;cygwin&lt;/a&gt;), так они еще и &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://code.google.com/p/servicestack/wiki/ServiceStackRedis"&gt;клиентскую .Net библиотеку&lt;/a&gt;&lt;span style="font-family:verdana;"&gt; написали! Но опять есть одно но - сервер работает в виде консольного приложения, что не очень-то подходит для сервера баз данных. Нужно захостить его в Win32 сервисе, но как?&lt;/span&gt;&lt;span style="font-family:verdana;"&gt;&lt;br /&gt;&lt;br /&gt;Очень просто:&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Берем OSC проект &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://code.google.com/p/topshelf/"&gt;TopShelf&lt;/a&gt;&lt;span style="font-family:verdana;"&gt; - легкий framework для создания Win32 сервисов, берущий все сложности на себя, и пишем хост-сервис, который будет запускать и останавливать наш сервер.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/S-PERxDf9AI/AAAAAAAAMJc/1IkRdIm8Ugw/s1600/redishost.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 332px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/S-PERxDf9AI/AAAAAAAAMJc/1IkRdIm8Ugw/s400/redishost.png" alt="" id="BLOGGER_PHOTO_ID_5468430182062748674" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Посмотрите, win32 сервис буквально в 10 строк кода.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Но, а как же насчет консольного окна? А просто - обратите внимание на аргумент передаваемый процессу сервера Redis (redis.conf). Это имя &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://github.com/antirez/redis/blob/master/redis.conf"&gt;конфигурационного файла&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;. В нем можно изменять любые настройки сервера. В частности там есть пункт daemonize, который на Linux запускает сервер в виде демона, на Windows же запуск с этим параметром приводит к созданию процесса без окна. И еще одно - x.RunAsLocalSystem();&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Вот и все. Теперь запускаем собранный проект из командной строки с аргументами: {project.exe} service install, - и смотрим как все по волшебству происходит само. Теперь это полноценный Win32 сервис, можно запускать.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Удачи!&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-1668321676203744678?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=abYzihMjrC8:NxIJBMhUmjQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=abYzihMjrC8:NxIJBMhUmjQ:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=abYzihMjrC8:NxIJBMhUmjQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=abYzihMjrC8:NxIJBMhUmjQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/abYzihMjrC8" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/abYzihMjrC8/plant-your-redis-into-windows.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_aPBCtYeet9E/S-PERxDf9AI/AAAAAAAAMJc/1IkRdIm8Ugw/s72-c/redishost.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2010/05/plant-your-redis-into-windows.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-6419066258394594457</guid><pubDate>Fri, 25 Dec 2009 10:07:00 +0000</pubDate><atom:updated>2009-12-27T23:47:04.465-08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">NHibernate</category><category domain="http://www.blogger.com/atom/ns#">SQL</category><title>ORM-style IdentityGenerator or impossible is nothing</title><description>&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;То, что я сейчас собираюсь описать, иначе как грязный хак назвать нельзя. Но жизнь сложная штука, и иногда приходится изворачиваться как уж, чтобы добиться своего.&lt;/span&gt;  &lt;span style="font-family:verdana;"&gt;А добиться я пытаюсь вот чего: чтобы NHibernate не ломал семантику Unit of Work при работе  с классами, Id которых генерится Identity счетчиком в SQL Server.&lt;/span&gt; &lt;span style="font-family:verdana;"&gt;&lt;br /&gt;&lt;br /&gt;Прежде всего, советую ознакомиться с историей вопроса: &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://devlicio.us/blogs/tuna_toksoz/archive/2009/03/20/nhibernate-poid-generators-revealed.aspx"&gt;о вреде Identity генераторов&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;, &lt;a href="http://fabiomaulo.blogspot.com/2008/12/identity-never-ending-story.html"&gt;еще о вреде&lt;/a&gt; и &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://ayende.com/Blog/archive/2009/03/20/nhibernate-avoid-identity-generator-when-possible.aspx"&gt;мнение в законе&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;.&lt;/span&gt; &lt;span style="font-family:verdana;"&gt;Проблема Identyity генератора в том, что он не может получить Id, не вставив запись в таблицу, а без Id сущность нельза ассоциировать с NHibernate сессией, поэтому как только мы пытаемся связать объект с сессией, он тут же попадает в базу. Отсюда вырастают огромные проблемы в длинных бизнес транзакциях, когда все действия с БД атомарны и выполняются в отдельных БД транзакциях, а сама бизнес операция растянута по времени. Так вот откат бизнес транзакции будет невозможен в случае использования Identity генератора. А это как раз мой случай.&lt;/span&gt;  &lt;span style="font-family:verdana;"&gt;Но, как я уже написал выше решение есть, но это грязный хак.&lt;br /&gt;&lt;br /&gt;Итак. &lt;span style="font-family:verdana;"&gt;Прекратив ныть, про хак, перехожу к сути. Мне надо:&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;вставлять свои значения в поля Identity;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;получать адекватные значения для Identity поля;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-family:verdana;"&gt;В SQL Server можно отключить автоинкрементацию Identity поля и &lt;a href="http://mysoftskill.blogspot.com/2009/11/cannot-insert-explicit-value-for.html"&gt;вставить свое значение&lt;/a&gt;, например, пропущенное в последовательности (при удалении). А получить его можно, вставив в таблицу запись и удалив ее. Это возможно, потому что при откате тра&lt;/span&gt;нзакции значение счетчика &lt;a href="http://msdn.microsoft.com/en-us/library/ms190315.aspx"&gt;Identity&lt;/a&gt; назад не откатывается, таким образом, изменив таблицу, мы перекидываем счетчик, а затем откатив транзакцию, убираем изменения.&lt;br /&gt;&lt;br /&gt;Вооружившись этим знанием я нарисовал следующую схему:&lt;br /&gt;&lt;/span&gt; &lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SzSWllrpopI/AAAAAAAAMBo/aIAbOjWF0Zg/s1600-h/ORMIdGenFlow.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 206px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SzSWllrpopI/AAAAAAAAMBo/aIAbOjWF0Zg/s400/ORMIdGenFlow.png" alt="" id="BLOGGER_PHOTO_ID_5419121824148071058" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Решение, как следует из картинки состоит из 3х частей:&lt;/span&gt; &lt;/span&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://nhforge.org/wikis/howtonh/creating-a-custom-id-generator-for-nhibernate.aspx"&gt;Custom Id generator&lt;/a&gt;, который я назвал ORMIdentityGenerator;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;PreInsert listener, для отключения автоинкрементного поля;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;PostInsert listener, для его включения назад;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-weight: bold;font-family:verdana;" &gt;ORMIdentityGenerator&lt;br /&gt;&lt;/span&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_aPBCtYeet9E/SzTeNAjKYUI/AAAAAAAAMBw/SktSuv0WGNc/s1600-h/ORMIdGen.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 249px;" src="http://1.bp.blogspot.com/_aPBCtYeet9E/SzTeNAjKYUI/AAAAAAAAMBw/SktSuv0WGNc/s400/ORMIdGen.png" alt="" id="BLOGGER_PHOTO_ID_5419200566700695874" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Следуя agile принципу KISS&lt;/span&gt; - &lt;b style="font-family: verdana;"&gt;keep it simple, stupid!&lt;/b&gt;&lt;span style="font-family:verdana;"&gt; я в&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;сего лишь конфигурирую его минимальным INSERT выражением, которое можно исполнить, не повредив базу и не вызвав нарушений целостности.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;  &lt;span style="font-weight: bold;font-family:verdana;" &gt;PreInsert&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SzTeNZrmYuI/AAAAAAAAMB4/Ksm_BUTovCY/s1600-h/PreInsert.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 241px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SzTeNZrmYuI/AAAAAAAAMB4/Ksm_BUTovCY/s400/PreInsert.png" alt="" id="BLOGGER_PHOTO_ID_5419200573446972130" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:verdana;" &gt;PostInsert&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SzTeNi7RAPI/AAAAAAAAMCA/5rxVplBtj34/s1600-h/PostInsert.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 226px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SzTeNi7RAPI/AAAAAAAAMCA/5rxVplBtj34/s400/PostInsert.png" alt="" id="BLOGGER_PHOTO_ID_5419200575928598770" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Вот и все. Теперь я могу спокойно редактировать объект &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://fabiomaulo.blogspot.com/2008/12/conversation-per-business-transaction.html"&gt;в длинной сессии&lt;/a&gt;&lt;span style="font-family:verdana;"&gt; и откатывать изменения, когда потребуется.&lt;/span&gt;  &lt;span style="font-family:verdana;"&gt;PS Простите ребята, гаджетом для вставки кода пока не обзавелся.&lt;/span&gt;  &lt;span style="font-family:verdana;"&gt;Удачи!&lt;/span&gt; &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-6419066258394594457?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=SQMHxFXiinU:bC3i5klZfgs:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=SQMHxFXiinU:bC3i5klZfgs:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=SQMHxFXiinU:bC3i5klZfgs:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=SQMHxFXiinU:bC3i5klZfgs:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/SQMHxFXiinU" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/SQMHxFXiinU/orm-style-identitygenerator-or-when.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_aPBCtYeet9E/SzSWllrpopI/AAAAAAAAMBo/aIAbOjWF0Zg/s72-c/ORMIdGenFlow.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2009/12/orm-style-identitygenerator-or-when.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-2007520180969598599</guid><pubDate>Fri, 02 Oct 2009 16:47:00 +0000</pubDate><atom:updated>2009-10-04T12:51:44.339-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">template method</category><title>Detached Template Method pattern</title><description>&lt;span style=";font-family:verdana;font-size:85%;"  &gt;Идея  не нова, ее я встретил впервые в  &lt;a href="http://www.springsource.org/"&gt;Spring framework&lt;/a&gt;, в части интеграции с ORM framework’ами.  Так для упрощения написания своих &lt;a href="http://martinfowler.com/eaaCatalog/repository.html"&gt;Repository&lt;/a&gt;  или &lt;a href="http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html"&gt;DAO&lt;/a&gt; (Как назвать дело вкуса. Я предпочитаю  термин Repository, т.к. с точки зрения &lt;a href="http://domaindrivendesign.org/"&gt;DDD&lt;/a&gt; он  более точно описывает свое назначение.)  Spring предлагает 2 опции:&lt;/span&gt; &lt;ul  type="disc" style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;передать    своему DAO XXXTemplate и пользоваться предоставляемыми    им методами, инкапсулирующими последовательность    работы с конкретным ORM;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Унаследоваться    от XXXDaoSupport, в котором XXXTemplate будет подставлен    без вашего &lt;/span&gt;&lt;span style="font-size:85%;"&gt;участия IoC контейнером;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;Так что  же это такое? Давайте обратимся  к классикам [GoF]:&lt;/span&gt; &lt;ul  style="font-family:verdana;"&gt;&lt;p align="justify"&gt;&lt;span style="font-size:85%;"&gt;&lt;i&gt;«&lt;/i&gt;&lt;a href="http://en.wikipedia.org/wiki/Template_method_pattern"&gt;&lt;b&gt;&lt;i&gt;Template  Method&lt;/i&gt;&lt;/b&gt;&lt;/a&gt;&lt;i&gt; – паттерн  поведения [классов]. &lt;/i&gt; &lt;b&gt;&lt;i&gt;Template Method &lt;/i&gt;&lt;/b&gt;&lt;i&gt;определяет&lt;/i&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;i&gt;  основу алгоритма и  позволяет подклассам  переопределить некоторые  шаги алгоритма, не изменяя  его структуру в целом.»&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;&lt;/ul&gt; &lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;Почему  Detached? Ну, вот так я придумал. Потому что  это не предполагающая наследования реализация  идеи &lt;b&gt;Template Method &lt;/b&gt;в отдельном классе.  Методы класса определяют последовательность  действий, которые должны быть выполнены,  скрывая детали реализации &lt;/span&gt;&lt;span style="font-size:85%;"&gt;алгоритма  и нижележащих ресурсов. Переопределение  же некоторых шагов возможно при помощи&lt;/span&gt;&lt;span style="font-size:85%;"&gt;  callback’ов. &lt;/span&gt;&lt;/p&gt; &lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;К примеру,  под капотом у всех XXXTemplate в Spring происходит  следующее (упрощенно):&lt;/span&gt;&lt;/p&gt; &lt;ol  type="1" style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;выделение    ресурсов (создание connection и т.д.); (фиксированная    часть алгоритма)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;начало транзакции;    (фиксированная часть алгоритма)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;вызов callback    executeInTransaction; (изменяемая часть алгоритма)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;возврат данных;    (изменяемая часть алгоритма)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;подтверждение/откат    транзакции; (фиксированная часть алгоритма)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;освобождение    ресурсов; (фиксированная часть алгоритма)&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt; &lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;Все эти  шаги вам пришлось бы реализовывать  самим в каждом месте, где предполагался  бы код &lt;/span&gt;&lt;span style="font-size:85%;"&gt;доступа к данным. Кроме того XXXTemplate  скрывают детали реализации и отвязывают  от лишних &lt;/span&gt;&lt;span style="font-size:85%;"&gt;зависимостей. Например, HibernateTemplate  конвертирует hibernate-специфичные exception’ы &lt;/span&gt;&lt;span style="font-size:85%;"&gt; в Spring  DataAccessException.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt; &lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;Я использовал  этот прием для обхода ограничения  языка C# - запрета множественного наследования.  Представьте иерархию классов, в которой  некоторые классы наследники базового  класса должны обладать еще и дополнительными  данными/поведением. А чтобы усложнить  ситуацию, представьте, что в системе есть  еще классы, не принадлежащие этой иерархии,  но которые тоже должны обладать теми  же данными/поведением. Интерфейс тут  единственное возможное решение. Теперь  более конкретно, чтобы обосновать применимость. &lt;/span&gt;&lt;/p&gt; &lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;У меня  есть базовый класс Resource, реализующий  &lt;a href="http://geekswithblogs.net/robp/archive/2008/02/03/looking-at-.net-the-disposable-pattern.aspx"&gt;disposable pattern&lt;/a&gt;. Многие из его наследников  – объекты системы, хранящие данные о  состоянии системы и идентифицирующие  конкретные &lt;/span&gt;&lt;span style="font-size:85%;"&gt;экземпляры по Id. &lt;/span&gt;&lt;/p&gt; &lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;Идентифицируемость  объектов вынесена в интерфейс, т.к.  в системе есть классы, которые должны&lt;/span&gt;&lt;span style="font-size:85%;"&gt;  уметь идентифицировать экземпляры и  не наследуют Resource. Просто не нужна им  такая функциональность, хотя могли бы.  Но я предпочитаю, чтобы мои классы говорили  сами за себя и не ввожу ненужных допущений,  запутывающих модель.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SsYxL3Ia_FI/AAAAAAAAL6U/AcTVgISm67Q/s1600-h/iident.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 63px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SsYxL3Ia_FI/AAAAAAAAL6U/AcTVgISm67Q/s400/iident.png" alt="" id="BLOGGER_PHOTO_ID_5388048084042972242" border="0" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;Как видите,  IIdentifiable наследует интерфейс &lt;a href="http://msdn.microsoft.com/en-us/library/ms131187.aspx"&gt;IEquatable&lt;/a&gt;, т.е.  объекты должны сами определять является  ли переданным им экземпляр идентичным.  И, наконец, тождественность объектов  должна определяться не только на основании  Id, но и на основании других полей данных.  Чувствуете к чему это идет? Мне придется  реализовывать логику сравнения по Id и  по значим&lt;/span&gt;&lt;span style="font-size:85%;"&gt;ым полям в каждом классе, многократно  дублируя код! Я такую личную неприязнь  к дублированию чувствую, что аж кушать  не могу. &lt;/span&gt;&lt;/p&gt; &lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;Поэтому  давайте разберемся а что же я должен  сделать? Я должен реализовать алгоритм  установления тождественности, который  содержит фиксированную часть (сравнение  ссылок &lt;/span&gt;&lt;/p&gt;&lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;объектов, сравнение Id) и переменную  часть (сравнение значимых данных, которые  в каждом классе, вообще говоря, свои).&lt;/span&gt;&lt;/p&gt; &lt;span style=";font-family:verdana;font-size:85%;"  &gt;Потому  в IIdentifiable я ввел метод DataEquals – это изменяемая  часть алгоритма и, как мне кажется наименьшее  из зол (но все-таки зло, потому что он публичный  и засоряет интерфейс (один из способов уменьшения этого зла - explicit implementation)), а в каждом реализуемом  методе Equals интерфейса IEquatable я делегирую  выполнение алгоритма моей реализации  Detached Template &lt;/span&gt;&lt;span style=";font-family:Times New Roman;font-size:85%;"  &gt;&lt;span style="font-family:verdana;"&gt;Metod – EqualsTemplate.&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;/span&gt;&lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SsYxx8HOglI/AAAAAAAAL6c/HFWXkREweBk/s1600-h/eqtmpl.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 80px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SsYxx8HOglI/AAAAAAAAL6c/HFWXkREweBk/s400/eqtmpl.png" alt="" id="BLOGGER_PHOTO_ID_5388048738215166546" border="0" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;&lt;p  align="justify" style="font-family:verdana;"&gt;&lt;span style="font-size:85%;"&gt;Я знаю,  знаю, что в .Net есть IEqualityComparer, но  мне мое решение нравится больше по 3м  причинам:&lt;/span&gt;&lt;/p&gt; &lt;ol  type="1" style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;мне не придется    «заставлять» пользователей моих классов    использовать IEqualityCompar&lt;/span&gt;&lt;span style="font-size:85%;"&gt;er;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;мне кажется,    что реализовать один метод проще, чем    написать новый класс;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;оно мое;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;Посмотрите как просто реализуется теперь этот алгоритм:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_aPBCtYeet9E/SsYyDRKJLaI/AAAAAAAAL6k/BuWyEvuab-U/s1600-h/iident_ex.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 315px;" src="http://3.bp.blogspot.com/_aPBCtYeet9E/SsYyDRKJLaI/AAAAAAAAL6k/BuWyEvuab-U/s400/iident_ex.png" alt="" id="BLOGGER_PHOTO_ID_5388049035922320802" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Удачи!&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-2007520180969598599?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=TGhCPeffZqc:z-ca5n-0SA4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=TGhCPeffZqc:z-ca5n-0SA4:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=TGhCPeffZqc:z-ca5n-0SA4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=TGhCPeffZqc:z-ca5n-0SA4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/TGhCPeffZqc" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/TGhCPeffZqc/detached-template-method-pattern.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_aPBCtYeet9E/SsYxL3Ia_FI/AAAAAAAAL6U/AcTVgISm67Q/s72-c/iident.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2009/10/detached-template-method-pattern.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-6728246627868340465</guid><pubDate>Sun, 27 Sep 2009 18:37:00 +0000</pubDate><atom:updated>2009-09-27T12:39:41.705-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Java</category><category domain="http://www.blogger.com/atom/ns#">facelets</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">JSF</category><category domain="http://www.blogger.com/atom/ns#">RichFaces</category><title>Select object rather then string in JSF</title><description>&lt;span style=";font-family:verdana;font-size:85%;"  &gt;Сначала хотел написать, что пост кардинально отличается от предыдущих, потому что про Java и связанные технологии, а потом подумал и понял, что основное-то предназначение блога - делиться опытом применения паттернов и методологий, а не описывать "фичи" языка, который всего лишь инструмент в данном случае. А потому начну так: Этот пост не сильно отличается от предыдущих, но он про Java и связанные технологии.&lt;br /&gt;&lt;br /&gt;Все еще здесь? Тогда продолжим! (отлично, спер клише, молодец)&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;Проект, на котором я работал, своей целью ставил исследование возможностей платформы Java&lt;/span&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt; в разработке Web-решений для компании, давно занимающейся разработкой на .Net, &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;следовательно, не имеющей такого опыта и таких специалистов. Так вот, нашей задачей было получение такого опыта и становление такими специалистами за максимально короткий срок – сэкономили, короче.&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;Проект – небольшой сайт с frontend на &lt;a href="http://java.sun.com/javaee/javaserverfaces/index.jsp"&gt;JSF&lt;/a&gt; 1.2, &lt;a href="https://facelets.dev.java.net/"&gt;facelets&lt;/a&gt;, &lt;a href="http://www.jboss.org/richfaces"&gt;RichFaces&lt;/a&gt; и инфраструктурой с использованием &lt;a href="http://www.springsource.org/"&gt;Spring&lt;/a&gt; и &lt;a href="https://www.hibernate.org/"&gt;Hibernate ORM&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Так вот заметка моя касается представления списков выбора в JSF, которая сделана, на мой взгляд, весьма коряво. Вкратце – сущности, из которых ведется выбор, вы должны представить в виде строк, завернув в класс SelectItem. Назад вместо объекта вы, естественно получите строку, а вовсе не объект, т.к. последний не путешествовал от сервера к клиенту и обратно. Так вот мое решение призвано обойти данную шероховатость JSF. &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;Кстати сказать, я не один такой умный и решений этой задачи есть как минимум несколько: &lt;a href="http://jsf-comp.sourceforge.net/components/easysi/index.html"&gt;http://jsf-comp.sourceforge.net/components/easysi/index.html&lt;/a&gt;, &lt;a href="http://balusc.blogspot.com/2007/09/objects-in-hselectonemenu.html"&gt;http://balusc.blogspot.com/2007/09/objects-in-hselectonemenu.html&lt;/a&gt;, - но… Первое не работает с RichFaces, а второе я нашел уже &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;после того как написал свое.&lt;/span&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;На решение натолкнула меня тоска. Ага, тоска по счастливым временам когда GUI я «творил» на WPF. Я тогда сильно упростил себе жизнь, написав &lt;a href="http://robbbloggg.blogspot.com/2008/06/how-josh-saved-my-day-or-power-of-model.html"&gt;SelectorCollectionPresenter&lt;/a&gt;. И я подумал &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;–почему бы не использовать похожий подход в Java? Сказано – сделано. Я написал класс CollectionPresenter =).&lt;br /&gt;&lt;br /&gt;Основная идея – это объект, который хранит карту ассоциаций строковых представлений с объектами и текущую выбранную строку, по которой, собственно, из карты выбирается объект.&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_aPBCtYeet9E/Sr-8MvHT0bI/AAAAAAAAL5E/-50nlkpc7WE/s1600-h/CollectionPresenter.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 367px;" src="http://3.bp.blogspot.com/_aPBCtYeet9E/Sr-8MvHT0bI/AAAAAAAAL5E/-50nlkpc7WE/s400/CollectionPresenter.png" alt="" id="BLOGGER_PHOTO_ID_5386230606349980082" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;Для Generic коллекций в Java я использовал реализацию apache &lt;a href="http://sourceforge.net/projects/collections/"&gt;Generic common-collections&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Теперь, имея возможность получить ссылку на объект, можно написать facelet,&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_aPBCtYeet9E/Sr-8hh5XlLI/AAAAAAAAL5U/2VzNBOuUUtI/s1600-h/cmbFacelet2.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 103px;" src="http://3.bp.blogspot.com/_aPBCtYeet9E/Sr-8hh5XlLI/AAAAAAAAL5U/2VzNBOuUUtI/s400/cmbFacelet2.png" alt="" id="BLOGGER_PHOTO_ID_5386230963579098290" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;&lt;br /&gt;который получает на вход список SelectItem’ов, которые создал Presenter, и возвращает выбранную строку, по которой Presenter вернет соответствующий объект.&lt;br /&gt;В принципе этот процесс можно отдать на откуп facelet’у целиком:&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/Sr-8W3lDAXI/AAAAAAAAL5M/mXlRdSxRVMg/s1600-h/cmbFacelet.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 97px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/Sr-8W3lDAXI/AAAAAAAAL5M/mXlRdSxRVMg/s400/cmbFacelet.png" alt="" id="BLOGGER_PHOTO_ID_5386230780420882802" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;И вот как выглядит использование первой версии facelet’а в разметке страницы:&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_aPBCtYeet9E/Sr-8uGmXRYI/AAAAAAAAL5c/XFBgZUShys8/s1600-h/faceletUsage.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 41px;" src="http://1.bp.blogspot.com/_aPBCtYeet9E/Sr-8uGmXRYI/AAAAAAAAL5c/XFBgZUShys8/s400/faceletUsage.png" alt="" id="BLOGGER_PHOTO_ID_5386231179589928322" border="0" /&gt;&lt;/a&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;&lt;br /&gt;Поверх presenter’а я навернул еще generic контроллер, который выбирает список объектов из &lt;/span&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;Repository и подставляет их presenter’у.&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_aPBCtYeet9E/Sr-87q1ff0I/AAAAAAAAL5k/Ws6KkFRCcpQ/s1600-h/dictCtrlr.png"&gt;&lt;img style="cursor: pointer; width: 388px; height: 400px;" src="http://3.bp.blogspot.com/_aPBCtYeet9E/Sr-87q1ff0I/AAAAAAAAL5k/Ws6KkFRCcpQ/s400/dictCtrlr.png" alt="" id="BLOGGER_PHOTO_ID_5386231412655357762" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;Важно заметить, что работать будет с контроллером, с любым временем жизни (стратегией времени жизни в Spring контейнере).&lt;br /&gt;&lt;br /&gt;Объекты, для выбора в моем случае – строки справочника, представляемые наследниками класса DictionaryEntry, что в общем случае необязательно, просто тогда надо будет написать соответствующий контроллер.&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/Sr-9Ju7KqMI/AAAAAAAAL5s/q678sqNk8DU/s1600-h/dictEntry.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 310px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/Sr-9Ju7KqMI/AAAAAAAAL5s/q678sqNk8DU/s400/dictEntry.png" alt="" id="BLOGGER_PHOTO_ID_5386231654271068354" border="0" /&gt;&lt;/a&gt;&lt;span style=";font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;&lt;br /&gt;Вот и все решение, в общих чертах!&lt;br /&gt;&lt;br /&gt;Удачи!&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-6728246627868340465?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=nBWtiaNlnk4:sF3G3r7AYU4:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=nBWtiaNlnk4:sF3G3r7AYU4:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=nBWtiaNlnk4:sF3G3r7AYU4:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=nBWtiaNlnk4:sF3G3r7AYU4:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/nBWtiaNlnk4" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/nBWtiaNlnk4/select-object-rather-then-string-in-jsf.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_aPBCtYeet9E/Sr-8MvHT0bI/AAAAAAAAL5E/-50nlkpc7WE/s72-c/CollectionPresenter.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2009/09/select-object-rather-then-string-in-jsf.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-430430220987864240</guid><pubDate>Thu, 03 Sep 2009 19:26:00 +0000</pubDate><atom:updated>2009-09-03T12:49:38.457-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sip</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">VoIP</category><category domain="http://www.blogger.com/atom/ns#">C#</category><title>Fluent Builder</title><description>&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: verdana;"&gt;&lt;a href="http://en.wikipedia.org/wiki/Fluent_interface"&gt;Fluent Interface&lt;/a&gt; и &lt;a href="http://en.wikipedia.org/wiki/Builder_pattern"&gt;Builder&lt;/a&gt; - идеальное сочетание для декларативного создания объектов.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;На самом деле примеры такого выгодного симбиоза давно у нас под носом, например: &lt;a href="http://msdn.microsoft.com/en-us/library/system.text.stringbuilder.aspx"&gt;StringBuilder&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;Я использовал такой симбиоз для декларативного создания &lt;a href="http://www.voip-info.org/wiki/view/SIP"&gt;SIP&lt;/a&gt; аккаунтов и звонков.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;Решение состоит из внутренних Builder-классов, которые предоставляют декларативный&lt;/span&gt; интерфейс для создания объектов и скрывают детали типа суффиксов транспорта, схемы и пр., о которых не надо задумываться.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_aPBCtYeet9E/SqAbbkbkEVI/AAAAAAAAL2s/E6XTFpVyWKE/s1600-h/k1.PNG"&gt;&lt;img style="cursor: pointer; width: 326px; height: 400px;" src="http://1.bp.blogspot.com/_aPBCtYeet9E/SqAbbkbkEVI/AAAAAAAAL2s/E6XTFpVyWKE/s400/k1.PNG" alt="" id="BLOGGER_PHOTO_ID_5377328115530076498" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_aPBCtYeet9E/SqAbbINeOiI/AAAAAAAAL2k/q9gYIyXnhgU/s1600-h/k2.PNG"&gt;&lt;img style="cursor: pointer; width: 381px; height: 400px;" src="http://1.bp.blogspot.com/_aPBCtYeet9E/SqAbbINeOiI/AAAAAAAAL2k/q9gYIyXnhgU/s400/k2.PNG" alt="" id="BLOGGER_PHOTO_ID_5377328107954780706" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SqAbavnZOOI/AAAAAAAAL2c/IRaU2f5AMEc/s1600-h/k3.PNG"&gt;&lt;img style="cursor: pointer; width: 313px; height: 400px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SqAbavnZOOI/AAAAAAAAL2c/IRaU2f5AMEc/s400/k3.PNG" alt="" id="BLOGGER_PHOTO_ID_5377328101352618210" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;Оба этих класса опираются на вспомогательный Builder – SIPUriBuilder. Этот класс настолько интуитивен, что я удивлен, что я не написал его первым делом.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_aPBCtYeet9E/SqAbaHgGw4I/AAAAAAAAL2U/fITuZWlVHeg/s1600-h/k4.PNG"&gt;&lt;img style="cursor: pointer; width: 381px; height: 400px;" src="http://1.bp.blogspot.com/_aPBCtYeet9E/SqAbaHgGw4I/AAAAAAAAL2U/fITuZWlVHeg/s400/k4.PNG" alt="" id="BLOGGER_PHOTO_ID_5377328090584630146" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;Результат на лицо:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;&lt;span style="font-weight: bold;"&gt;Было&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;string remote = "sip:";&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;         remote += txbURI.Text == "00"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;                                     ? "127.0.0.1"&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                             &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;                                     &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;: (txbURI.Text + "@" + SIPUserAgent.SIPUserAgent.Instance&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;.AccountManager.DefaultAccount.RegistrarUri.Split(new[]{':'})[1]);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;         remote += SIPUserAgent.SIPUserAgent.Instance.SIPTransport is TCPTransport&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                                     &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;                                     &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;? ":5061;transport=TCP"&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                                     &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;                                     &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;: "";&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;         SIPUserAgent.SIPUserAgent.Instance.CallManager.MakeCall(remote);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;&lt;span style="font-weight: bold;"&gt;Стало&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;Call c = Call.ConstructCall().SetAccount(acc).SetExtension(txbURI.Text).SetDomain(txbURID.Text).Call();&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Было&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;var acc = new Account(false);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;             using (acc.CreateInitializationSession())&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;             {&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                  acc.Credential = new NamePasswordCredential&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                                       {&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                                            Password = txbPass.Text,&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                                            Realm = txbRegistrar.Text,&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                                            UserName = txbLogin.Text&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                                       };&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                  acc.AccountId = "sip:" + txbLogin.Text + "@" + txbRegistrar.Text;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                  acc.RegistrarUri = "sip:" + txbRegistrar.Text;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                  if (ua.SIPTransport is TCPTransport)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                  {&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                       acc.AccountId += "5061;transport=TCP";&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                       acc.RegistrarUri += "5061;transport=TCP";&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;                  }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;             }&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;             ua.AccountManager.RegisterAccount(acc, true);&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;&lt;span style="font-weight: bold;"&gt;Стало&lt;/span&gt;:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: courier new;"&gt;var acc = Account.ConstructAccount().SetLogin(txbLogin.Text).SetPassword(txbPass.Text)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;          .SetRegistrarDomain(txbRegistrar.Text).Register();&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;Комментарии я думаю излишни. Просто сравните число строк.&lt;br /&gt;&lt;br /&gt;Удачи!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-430430220987864240?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=wdivgxu9rCg:TioDq53dPto:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=wdivgxu9rCg:TioDq53dPto:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=wdivgxu9rCg:TioDq53dPto:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=wdivgxu9rCg:TioDq53dPto:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/wdivgxu9rCg" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/wdivgxu9rCg/fluent-builder.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_aPBCtYeet9E/SqAbbkbkEVI/AAAAAAAAL2s/E6XTFpVyWKE/s72-c/k1.PNG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2009/09/fluent-builder.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-3696884317013025938</guid><pubDate>Wed, 15 Apr 2009 07:28:00 +0000</pubDate><atom:updated>2009-04-16T03:27:24.761-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">sip</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">VoIP</category><category domain="http://www.blogger.com/atom/ns#">interop</category><title>Designing managed API over "flat" native one or .Net SIP library</title><description>&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Попробую описать процесс проекции плоского API, написанного в процедурном стиле, в многомерное ООП пространство, на примере работы, которой было занято почти все мое свободное время за последний месяц.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Возможно многим эта заметка покажется интересной не с точки зрения содержания, сколько с точки зрения результата работы, которым я готов поделиться со всеми, а именно - .Net обертка над замечательной SIP библиотекой &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://www.pjsip.org/"&gt;pjsip&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;, но для меня она ценна именно как описание процесса. Можно сказать мемуар.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Конечно обертка эта не покрывает все то богатство возможностей управления процессом, которое предоставляют различные модули pjsip, но предоставляет высокоуровневый .Net интерфейс к pjsua (user agent) API, необходимый для быстрого создания SIP клиентов.&lt;/span&gt;&lt;/span&gt;&lt;ol style="font-family: verdana;font-family:verdana;" &gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;P/Invoke или как не утонуть в тоннах кода;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Designing API;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Testing API;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="font-weight: bold;"&gt;1. P/Invoke.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family:verdana;"&gt;&lt;p&gt;Я пропустил очень важную часть - выбор подходящей библиотеки, т.к. считаю, что к теме заметки это имеет мало отношения, но все-таки немного опишу мотивацию, которая диктовала выбор SIP библиотеки pjsip. Мне нужна библиотека:&lt;/p&gt;&lt;/span&gt;&lt;/span&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li style="font-family: verdana;"&gt;&lt;span style="font-size:85%;"&gt;реализующая последние RFC в наиболее полном объеме;&lt;/span&gt;&lt;/li&gt;&lt;li style="font-family: verdana;"&gt;&lt;span style="font-size:85%;"&gt;с поддержкой различных кодеков, в том числе широкополосных;&lt;/span&gt;&lt;/li&gt;&lt;li style="font-family: verdana;"&gt;&lt;span style="font-size:85%;"&gt;портируемая на разные платформы (на будущее);&lt;/span&gt;&lt;/li&gt;&lt;li style="font-family: verdana;"&gt;&lt;span style="font-size:85%;"&gt;с возможностью передачи видео-потока (на будущее);&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: verdana;font-size:85%;" &gt;open source с разумной лицензией, которая позволила бы использовать ее в коммерческих приложениях. (&lt;span style="font-weight: bold;"&gt;UPD3: &lt;/span&gt;GPL, под которой распространяется эта библиотека не такая уж и разумная, а, как сказал мой друг: "&lt;/span&gt;детище неадекватного проповедника Столмена&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: verdana;"&gt;". &lt;span style="font-family: verdana;"&gt;Следует заметить, что исходное выражение подверглось жесткой цензуре =). &lt;/span&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;pjsip удовлетворяет всем этим условиям, и многим другим, неперечисленным здесь. Замечательная вобщем библиотека.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Итак, прежде всего нам надо скачать исходные коды и собрать dll. Скачать pjsip можно из SVN хранилища, как стабильную версию, так и текущий закоммиченый код.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Далее, забегая вперед, сразу же скажу, что при генерации interop-кода возникла проблема с callback функциями, т.к. C# поддерживает только &lt;span style="font-family:courier new;"&gt;stdcall&lt;/span&gt; callback функции (UPD: врешь ты все =) ), т.е. делегаты будут вызываться как &lt;span style="font-family:courier new;"&gt;stdcall&lt;/span&gt;, тогда как pjsip декларирует свои callback'и как &lt;span style="font-family:courier new;"&gt;cdecl&lt;/span&gt;, это проблема! Путей решения у нее несколько.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Если бы у нас не было доступа к исходному коду pjsip - у нас была бы проблема, которую пришлось бы решать нетривиальным образом, изменяя IL код, сгенерированный для interop кода. Этот хак описан &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://groups.google.com/group/microsoft.public.dotnet.framework.interop/msg/eaf7bd2549f5a3a3?pli=1"&gt;здесь&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;UPD: Да, и пока я искал ссылку, нашлось более простое решение, поставляемое самой платформой .Net - &lt;/span&gt;&lt;/span&gt;&lt;span style=";font-family:courier new;font-size:85%;"  &gt;UnmanagedFunctionPointer&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-family:courier new;"&gt; &lt;/span&gt;атрибут, с помощью которого можно пометить делегат и обозначить calling convention.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Последнее же решение, к которому прибегнул я, - пометил все нужные мне callback функции в pjsua &lt;span style="font-family:courier new;"&gt;__stdcall&lt;/span&gt;, благо их немного.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Итак, dll, экспортирующую функции высокоуровневого pjsua API я собрал, но даже для этого интерфейса (довольно скромного по сравнению с более низкоуровневыми) я бы писал interop код вручную недели две. Столько времени у меня нет, да это еще к тому же ужасно скучно, поэтому я нашел средство автоматической генерации interop кода - &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://www.codeplex.com/clrinterop/Release/ProjectReleases.aspx?ReleaseId=14120"&gt;PInvoke Assistant&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;. Достаточно лишь указать этой замечательной утилите всю необходимую информацию, и вуаля - 90% кода сгенерились автоматически. Надо сказать, что 10% недостающего кода эта_замечательная_утилита все-таки не осилила, но винить ее в этом я не намерен, т.к. код был действительно очень сложный для автоматического разбора. Вобщем 10%, написанные вручную, все-таки лучше, чем 100%.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;UPD2:&lt;/span&gt; нашел еще одну утилиту для генерации interop кода: &lt;a href="http://www.swig.org/"&gt;SWIG&lt;/a&gt;&lt;/span&gt;. &lt;span style="font-family:verdana;"&gt;Выглядит она намного мощнее той, которую я использовал, достаточно посмотреть на &lt;a href="http://www.swig.org/compat.html#SupportedLanguages"&gt;список поддерживаемых языков&lt;/a&gt;. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;На этой стадии у меня уже был готов рабочий .Net интерфейс к pjsip, но вот только одна беда - в процедурном стиле, что впрочем не помешало мне написать тестовое консольное приложение, которое регистрировалось на SIP сервере.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-family:verdana;font-size:100%;"  &gt;2. Designing API.&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Дизайн ООП обертки во многом продиктован структурой pjsua API (больше половины работы уже сделано за нас). pjsua логически и очень интуитивно разделяется на следующие группы:&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a class="el" href="http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__BASE.htm"&gt;PJSUA-API Basic API&lt;/a&gt; Создание/инициализация, конфигурирование, логирование и пр.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a class="el" href="http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__TRANSPORT.htm"&gt;PJSUA-API Signaling Transport&lt;/a&gt; Управление SIP транспортами;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a class="el" href="http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__ACC.htm"&gt;PJSUA-API Accounts Management&lt;/a&gt; Управление аккаунтами;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a class="el" href="http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__CALL.htm"&gt;PJSUA-API Calls Management&lt;/a&gt; Управление звонками;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a class="el" href="http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__BUDDY.htm"&gt;PJSUA-API Buddy, Presence, and Instant Messaging&lt;/a&gt; Управление списками контактов, информацией о доступности и IM;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a class="el" href="http://www.pjsip.org/pjsip/docs/html/group__PJSUA__LIB__MEDIA.htm"&gt;PJSUA-API Media Manipulation&lt;/a&gt; Манипуляция медиа-данными;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Также логически и интуитивно я выделил следующие сущности:&lt;/span&gt;&lt;/span&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;SIPUserAgent - центральная фигура и главная точка доступа к API, отвечающая за создание/конфигурирование клиента;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Account Manager - интерфейс для управления аккаунтами (аналог - телефонный номер);&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Call Manager - интерфейс для управления звонками (&lt;/span&gt;&lt;span style="font-size:85%;"&gt;прием/&lt;/span&gt;&lt;span style="font-size:85%;"&gt;создание новых звонков, управление состоянием);&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Media Manager - интерфейс для управления медиа-параметрами системы (кодеки, звуковые устройства, конференция);&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Conference Bridge - жалкое отражение мощного &lt;a href="http://www.pjsip.org/pjmedia/docs/html/group__PJMEDIA__CONF.htm"&gt;медиа-микшера pjmedia&lt;/a&gt;;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Итак вот он взгляд на систему с высоты:&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/SeWwM5wpKiI/AAAAAAAAKYI/_IAzS_Ucakk/s1600-h/sipua.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 333px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/SeWwM5wpKiI/AAAAAAAAKYI/_IAzS_Ucakk/s400/sipua.png" alt="" id="BLOGGER_PHOTO_ID_5324855870145243682" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Поскольку большинство объектов являются обертками над нативными структурами, выделяющимися в неуправляемой памяти, то нам нужен механизм управления освобождением последних. Такой механизм в .Net изобретен давно и называется он &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://msdn.microsoft.com/en-us/magazine/cc163392.aspx"&gt;Disposable pattern&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;. Очень кстати полезно помнить про этот паттерн, так как он .Net specific, а про такие MS любит спрашивать на собеседовании. Фундамент для &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://msdn.microsoft.com/en-us/magazine/cc163392.aspx"&gt;Disposable pattern&lt;/a&gt;&lt;span style="font-family:verdana;"&gt; - базовый класс &lt;span style="font-family:courier new;"&gt;Resource&lt;/span&gt;, с одной лишь разницей, что он не реализует &lt;span style="font-family:courier new;"&gt;IDisposable&lt;/span&gt;, т.к. я не хочу отдавать контроль над временем жизни всех объектов, потому что это может нарушить работу системы. Например: нельзя дать пользователю этого API освободить ресурсы &lt;span style="font-family:courier new;"&gt;VoIPTransport&lt;/span&gt;'а во время звонка, или даже пока в системе есть зарегистрированные аккаунты. Следить же за всеми зависимостями просто невозможно, и вообще это есть нарушение всех принципов хорошего дизайна. Поэтому в &lt;span style="font-family:courier new;"&gt;Resource &lt;/span&gt;вместо публичной реализации &lt;span style="font-family:courier new;"&gt;IDisposable &lt;/span&gt;есть &lt;span style="font-family:courier new;"&gt;internal &lt;/span&gt;метод &lt;span style="font-family:courier new;"&gt;InternalDispose&lt;/span&gt;. В случае, когда время жизни объекта может управляться извне, то класс наследник &lt;span style="font-family:courier new;"&gt;Resource &lt;/span&gt;явно реализует интерфейс &lt;span style="font-family:courier new;"&gt;IDisposable&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Одна из основ дизайна - инициализируемые объекты. В pjsip прежде чем что-то использовать, это что-то сначала надо сконфигурировать и проинициализировать. Причем некоторые объекты поддерживают повторную реинициализацию, а некоторые - нет. О проблемах и решениях инициализации объектов я писал в &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://bobbbloggg.blogspot.com/2009/03/initializable-pattern.html"&gt;предыдущей заметке&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;, как раз в то время, когда создавался дизайн всей системы. Каждый инициализируемый класс, проводит валидацию установленных параметров по окончании сессии инициализации.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;SIPUserAgent &lt;/span&gt;&lt;span style="font-weight: bold;"&gt;(UA)&lt;/span&gt; - центральная точка доступа к API. UA - инициализируемый объект и прежде чем вы получите доступ к различным частям системы, его необходимо... правильно! проинициализировать. По окончании сессии UA проверит все введенные данные на валидность и, если все в порядке, создаст необходимые структуры pjsua. UA поддерживает конфигурирование в config файле, но по умолчанию не использует его, хотя и имеет для этого явный интерфейс - метод &lt;span style="font-family:courier new;"&gt;ReadConfiguration()&lt;/span&gt;, который может быть вызван только во время сессии инициализации. Имеется и зеркальный метод &lt;span style="font-family:courier new;"&gt;WriteConfiguration()&lt;/span&gt;, который следует вызвать до того, как UA будет уничтожен. Кстати, UA это пример объекта, временем жизни которого можно управлять пользователям API, поэтому он реализует интерфейс &lt;span style="font-family:courier new;"&gt;IDisposable &lt;/span&gt;и как дополнение, для большей наглядности метод &lt;span style="font-family:courier new;"&gt;Destroy()&lt;/span&gt;, который по смыслу ничем не отличается от &lt;span style="font-family:courier new;"&gt;Dispose()&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-family:courier new;"&gt;SIPUserAgent&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;AccountManager&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;CallManager&lt;/span&gt;, &lt;span style="font-family:courier new;"&gt;MediaManager &lt;/span&gt;- &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://en.wikipedia.org/wiki/Singleton_pattern"&gt;singleton&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;'ы и они существуют всегда в единичном экземпляре. Это означает, что в приложении вы не сможете создать больше одного &lt;span style="font-family:courier new;"&gt;SIPUserAgent&lt;/span&gt;'а, да оно и не требуется, т.к. в системе есть понятие аккаунтов.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-weight: bold;"&gt;Transport &lt;/span&gt;интерфейс pjsua инкапсулирован в классе &lt;span style="font-family:courier new;"&gt;VoIPTransport&lt;/span&gt;.&lt;/span&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/SeXFVOEsFQI/AAAAAAAAKYY/UJMOucc04ZA/s1600-h/transport.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 343px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/SeXFVOEsFQI/AAAAAAAAKYY/UJMOucc04ZA/s400/transport.png" alt="" id="BLOGGER_PHOTO_ID_5324879102781166850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Это пожалуй самая маленькая часть системы, предоставляющая интерфейс для создания и конфигурирования конкретного типа SIP транспорта (UDP, TCP или TLS). В UA поумолчанию создается &lt;span style="font-family:courier new;"&gt;UDPTransport &lt;/span&gt;для SIP, который может быть заменен либо при загрузке конфигурации, либо явно одним из наследников &lt;span style="font-family:courier new;"&gt;VoIPTransport &lt;/span&gt;во время сессии инициаллизации. К сожалению в текущем релизе pjsip поддерживает только UDP транспорт для RTP, но в дальнейших планах стоит TCP транспорт для RTP, что авторы сопровождают пометкой "анекдот", им виднее. Поэтому на всякий случай &lt;span style="font-family:courier new;"&gt;VoIPTransport&lt;/span&gt;, а не &lt;span style="font-family:courier new;"&gt;SIPTransport&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Многие объекты системы имеют различные состояния, которые прекрасно описываются &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://en.wikipedia.org/wiki/State_pattern"&gt;state machine&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;. Состояния эти передаются через callback'и из pjsip и обрабатываются соответствующими менеджерами, так за обработку callback'ов сессии регистрации аккаунта отвечает &lt;span style="font-family:courier new;"&gt;AccountManager&lt;/span&gt;, который затем сообщает state machine, что ее состояние изменилось. Поначалу state machines были частью сущности, состояние которой они описывали, но при более детальном взгляде оказалось, что объект (например звонок [&lt;span style="font-family:courier new;"&gt;Call&lt;/span&gt;] имеет Invite-сессию и медиа-сессию) может иметь несколько никак не связанных состояний, которые лучше даже назвать сессиями. Поэтому для моделирования этих сессий я написал малюсенький набор классов, состоящий из &lt;span style="font-family:courier new;"&gt;StateMachine &lt;/span&gt;- базового класса для сессии; и &lt;span style="font-family:courier new;"&gt;AbstractState &lt;/span&gt;- базового класса для состояния. Классы состояний управляют логикой обработки событий (этакий workflow), а классы сессий просто хранят атрибуты состояния. Я даже рассматривал возможность использования WF движка для моделирования сессий, но понял, что это был бы overkill для задачи такого масштаба.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:verdana;" &gt;Accounts&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/SeW_4adn1EI/AAAAAAAAKYQ/sHxAzp-91Ms/s1600-h/accounts.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 271px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/SeW_4adn1EI/AAAAAAAAKYQ/sHxAzp-91Ms/s400/accounts.png" alt="" id="BLOGGER_PHOTO_ID_5324873110332625986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Тут все просто - пользователь создает аккаунт, инициализирует, передает &lt;span style="font-family:courier new;"&gt;AccountManager&lt;/span&gt;'у, который позаботится о его дальнейшей судьбе. В принципе уже здесь можно выкинуть ссылку на аккаунт, т.к. он автоматически попадает в коллекцию аккаунтов &lt;span style="font-family:courier new;"&gt;AccountManager&lt;/span&gt;'ов, из которой будет удален только когда будет вызван метод &lt;span style="font-family:courier new;"&gt;AccountManager&lt;/span&gt;'а &lt;span style="font-family:courier new;"&gt;UnregisterAccount(account)&lt;/span&gt;. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;&lt;span style="font-family:courier new;"&gt;AccountManager &lt;/span&gt;при старте системы создает внутренний локальный аккаунт, так что система сразу готова к приему и отправке звонков.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;У аккаунта есть сессия регистрации, управляющая его состоянием. В принципе число возможных состояний аккаунта равно числу кодов статуса SIP протокола (около 100). Поэтому, чтобы не плодить кучу классов, описывающих состояния, в которые аккаунт неизвестно может ли перейти вообще, я описал лишь те состояния, в которых при тестировании аккаунт побывал однозначно (registering, timedout, registered), а для всех остальных написал общий класс &lt;span style="font-family:courier new;"&gt;UnknownStatusState&lt;/span&gt;, который, получая код статуса, пишет в &lt;span style="font-family:courier new;"&gt;Trace &lt;/span&gt;строку с описанием этого статуса.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Об изменениях в состоянии и &lt;span style="font-family:courier new;"&gt;Account &lt;/span&gt;и &lt;span style="font-family:courier new;"&gt;AccountManager &lt;/span&gt;информируют пользователей генерируя соответствующие события.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;В классе &lt;span style="font-family:courier new;"&gt;Account &lt;/span&gt;великое множество свойств, из которых можно почерпнуть информацию о текущем состоянии аккаунта.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:verdana;" &gt;Calls&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SeXHwbXtJkI/AAAAAAAAKYg/rJ4mcg0sj0k/s1600-h/calls.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 299px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SeXHwbXtJkI/AAAAAAAAKYg/rJ4mcg0sj0k/s400/calls.png" alt="" id="BLOGGER_PHOTO_ID_5324881769230313026" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Здесь, конечно, дела обстоят посложнее, но не для пользователя системы, разумеется. С его точки зрения все также просто: чтобы позвонить куда-то нужно лишь вызвать метод &lt;span style="font-family:courier new;"&gt;MakeCall()&lt;/span&gt; &lt;span style="font-family:courier new;"&gt;CallManager&lt;/span&gt;'а, указав последнему куда позвонить и с какого аккаунта, чтобы принять звонок - надо подписаться на событие &lt;span style="font-family:courier new;"&gt;IncomingCall &lt;/span&gt;и вызвать метод &lt;span style="font-family:courier new;"&gt;Answer()&lt;/span&gt; переданного звонка, и все. Звонок также будет помещен в коллекцию звонков, и дальнейшей его судьбой будет управлять &lt;span style="font-family:courier new;"&gt;CallManager&lt;/span&gt;, ну и конечно же пользователь может явно закончить звонок, вызвав &lt;span style="font-family:courier new;"&gt;Call.Hangup()&lt;/span&gt;. Под капотом же все намного сложнее.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Начнем с того, что у звонка две сессии: Invite сессия, управляемая SIP протоколом, и медиа сессия, управляемая RTP протоколом.&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SeXJoinwxkI/AAAAAAAAKYo/GnheZ4H3m80/s1600-h/call+sessions.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 267px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SeXJoinwxkI/AAAAAAAAKYo/GnheZ4H3m80/s400/call+sessions.png" alt="" id="BLOGGER_PHOTO_ID_5324883832761009730" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;С Invite сессией все более менее понятно - все через нее проходят каждый раз как набирают номер на мобильном и ждут соединения, а вот медиа-сессия более интересная тема. Дело в том, что звонок может иметь более одного слушателя, равно как и вещателя, т.е. быть частью конференции. Но здесь возникает небольшое расхождение с плоской иерархией классов состояний, описывающих эту сессию, т.к. звонок может быть активным и не участвовать в конференции, или участвовать, но не может быть неактивным и участвовать в конференции, т.к. это абсурд. Для описания этой ситуации я применил &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://en.wikipedia.org/wiki/Decorator_pattern"&gt;Decorator&lt;/a&gt;&lt;span style="font-family:verdana;"&gt; - &lt;span style="font-family:courier new;"&gt;ConferenceMediaStateDecorator&lt;/span&gt;, оборачивающий &lt;span style="font-family:courier new;"&gt;ActiveMediaState&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Между аккаунтом и звонками есть зависимость один-ко-многим, т.е. несколько звонков могут использовать один и тот же аккаунт. Следовательнго система должна каким-то образом следить за этими зависимостями. Можно создать множество и хранить в нем ассоциации, а можно воспользоваться механизмом подсчета ссылок, как это было сделано в COM. Именно этой техникой в сочетании с описанным приемом &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://bobbbloggg.blogspot.com/2009/03/initializable-pattern.html"&gt;smart-pointer для .Net&lt;/a&gt;&lt;span style="font-family:verdana;"&gt; я и воспользовался для реализации это й задачи в loosely-coupled манере.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/SeXNyb7b_zI/AAAAAAAAKYw/4w58M3npu8E/s1600-h/account_lock.png"&gt;&lt;img style="cursor: pointer; width: 276px; height: 400px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/SeXNyb7b_zI/AAAAAAAAKYw/4w58M3npu8E/s400/account_lock.png" alt="" id="BLOGGER_PHOTO_ID_5324888400809688882" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Каждый звонок при создании получает ссылку на аккаунт, с которым он ассоциирован. Он не хранит ее, а блокирует аккаунт (его невозможно будет удалить) вызовом метода &lt;span style="font-family:courier new;"&gt;Lock()&lt;/span&gt;, который возвращает &lt;span style="font-family:courier new;"&gt;IDisposable &lt;/span&gt;(smart-pointer), который при создании увеличивает число ссылок на аккаунт, а при явном уничтожении (&lt;span style="font-family:courier new;"&gt;Dispose&lt;/span&gt;) уменьшает. Этот smart-pointer освобождается при очистке ресурсов звонка.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:verdana;" &gt;Media&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SeXPRotAaiI/AAAAAAAAKY4/iLTcnQEUrg4/s1600-h/media.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 338px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SeXPRotAaiI/AAAAAAAAKY4/iLTcnQEUrg4/s400/media.png" alt="" id="BLOGGER_PHOTO_ID_5324890036326394402" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Медиа менеджер позволяет установить устройства воспроизведения и захвата звука, посмотреть коллекцию кодеков и посмотреть состояние конференц-моста. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Конференц-мост - это часть системы, выполняющая роль микшера медиа потоков. Звонки, подключающиеся к конференции, соединяются со всеми узлами двунаправленного графа, уже участвующих в конференции звонков. В системе может быть только одна активная конференция.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Подключение к конференции может происходить как автоматически - если установлен флаг UA &lt;span style="font-family:courier new;"&gt;AutoConference &lt;/span&gt;(тогда &lt;span style="font-family:courier new;"&gt;ActiveMediaState &lt;/span&gt;будет автоматически оборачиваться &lt;span style="font-family:courier new;"&gt;ConferenceStateDecorator&lt;/span&gt;'ом, который и подключает звонок к конференц мосту), либо явно при помощи метода &lt;span style="font-family:courier new;"&gt;Call.ConnectToConference() &lt;/span&gt;(в этом случае сначала будет произведена проверка активна ли медиа сессия и, если да, то &lt;span style="font-family:courier new;"&gt;ActiveMedaiState &lt;/span&gt;будет обернут &lt;span style="font-family:courier new;"&gt;ConferenceStateDecorator&lt;/span&gt;'ом с тем же результатом). За подключение звонков между собой отвечает &lt;span style="font-family:courier new;"&gt;ConferenceBridge&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:100%;" &gt;&lt;span style="font-family:verdana;"&gt;3. Testing API.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Сейчас скажу крамолу - очень важно тестировать код! Поэтому в процессе разработки постоянно писалось тестовое консольное приложение. Оно позволило вычистить API, найти частично ошибки. Далее я решил залезть в чужую шкуру - стать пользователем своей же библиотеки и написать GUI приложение. И в процессе этой работы выловил еще несколько проблем. Например при уничтожении UA возникали racing conditions, связанные с отсутствием синхронизации между процессом уничтожения всех звонков и очисткой аккаунтов, или ошибки связанные с публикацией событий не в UI потоке, т.к. pjsip обрабатывает различные транзакции в различных потоках, то для упрощения клиентского кода, все менеджеры публикуют события через &lt;span style="font-family:courier new;"&gt;SyncronizationContext&lt;/span&gt;, буде таковой существует. Их как правило устанавливают GUI framework'и WinForms или WPF.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Возможно вы заметили, что я покрыл не все части pjsua API и не все возможности уже покрытых групп реализованы - это потому что моя обертка все еще в разработке! &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Надеюсь чтение про мои страдания было интересным и поучительным. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;PS: Код будет выложен позже.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Всем удачи!&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-3696884317013025938?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=C4QPDgWktIk:sGIr12zAq6A:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=C4QPDgWktIk:sGIr12zAq6A:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=C4QPDgWktIk:sGIr12zAq6A:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=C4QPDgWktIk:sGIr12zAq6A:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/C4QPDgWktIk" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/C4QPDgWktIk/designing-managed-api-over-flat-native.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_aPBCtYeet9E/SeWwM5wpKiI/AAAAAAAAKYI/_IAzS_Ucakk/s72-c/sipua.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2009/04/designing-managed-api-over-flat-native.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-724228426864675072</guid><pubDate>Mon, 16 Mar 2009 08:16:00 +0000</pubDate><atom:updated>2009-03-18T09:49:12.934-07:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">initializer</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><title>Initializable pattern</title><description>&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt;Представьте, что вы разрабатываете API, в котором объекты, являющиеся частью системы, должны быть проинициализированы перед использованием.&lt;br /&gt;Есть несколько способов простимулировать будущих пользователей этого API завершать инициализацию перед использованием:&lt;br /&gt;&lt;/span&gt;&lt;ol style="font-family: verdana;font-family:verdana;" &gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Ввести метод Initialize в каждом объекте, который нужно проинициаллизировать;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Более "правильный" и следующий дизайну .Net framework - реализовать в классе &lt;/span&gt;&lt;span style="font-size:85%;"&gt;ISupportInitialize;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;Пойти еще дальше и автоматизировать запуск и закрытие сессии инициализации;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt;Что значит автоматизировать запуск и закрытие сессии инициализации? Скажем, возложит&lt;/span&gt;&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt;ь эту&lt;/span&gt;&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt; обязанность на framerwork. Как это сделать? Об этом и заметка!  Вспомните мой &lt;a href="http://bobbbloggg.blogspot.com/2008/06/handy-monitor-wrapper.html"&gt;пост про удобную обертку над Monitor'ом&lt;/a&gt;, с помощью которой можно узнать есть ли в очереди на доступ к ресурсу заблокированные потоки? Так вот для пущего удобства и сохранения стиля &lt;/span&gt;&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt;выполнения блокировок с поддержкой языковых конструкций (скобочек =) ) там использовался &lt;a href="http://geekswithblogs.net/robp/archive/2008/02/03/looking-at-.net-the-disposable-pattern.aspx"&gt;.Net-специфичный паттерн Disposable&lt;/a&gt;. Почему бы не воспользоваться тем же приемом для обрамления сессии инициализации? Сказано, сделано. Прошу любить и жаловать - .Net-specific Initializable pattern.  Состоит это решение из 2х частей: &lt;/span&gt;&lt;ul style="font-family: verdana;font-family:verdana;" &gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;собственно объект, который необходимо проинициаллизировать (реализует ISupportInitialize);&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;обертка, с помощью которой и происходит неявное управление сессией инициаллизации;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt;Давайте взглянем на эту обертку поближе:&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/Sb4SS0qaWdI/AAAAAAAAKV4/5_KSpvyc9a0/s1600-h/initializer.png"&gt;&lt;img style="cursor: pointer; width: 302px; height: 400px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/Sb4SS0qaWdI/AAAAAAAAKV4/5_KSpvyc9a0/s400/initializer.png" alt="" id="BLOGGER_PHOTO_ID_5313704724927240658" border="0" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt; &lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt;Это маленькая обертка, которая при создании получает ссылку на инициаллизируемый объект и запускает сессию, вызовом метода ISupportInitialize.BeginInit(). И при детерминированном освобождении закрывает сессию вызовом метода ISupportInitialize.EndInit(). Я намеренно не стал реализовывать в этом классе Disposable паттерн целиком с тем, чтобы сессия закрывалась только явно, либо вызовом Dispose() обертки, либо EndInit() самого объекта.&lt;br /&gt;&lt;br /&gt;Вот как может выглядеть API:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-size:85%;" &gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/Sb4WEhAr8rI/AAAAAAAAKWA/6n3H6A3tW9U/s1600-h/init_api.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 45px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/Sb4WEhAr8rI/AAAAAAAAKWA/6n3H6A3tW9U/s400/init_api.png" alt="" id="BLOGGER_PHOTO_ID_5313708877180302002" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt; и использование его в коде:&lt;/span&gt;&lt;span style="font-family: verdana;font-size:85%;" &gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-size:85%;" &gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/Sb4WFhDHKXI/AAAAAAAAKWI/umuCd-LhU-o/s1600-h/init_usage.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 52px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/Sb4WFhDHKXI/AAAAAAAAKWI/umuCd-LhU-o/s400/init_usage.png" alt="" id="BLOGGER_PHOTO_ID_5313708894370343282" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-family:verdana;font-size:85%;"  &gt;&lt;br /&gt;Easy-peasy&lt;/span&gt;&lt;span style="font-family: verdana;font-size:85%;" &gt;!&lt;br /&gt;А вот как выглядел бы код без Initializer:&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_aPBCtYeet9E/Sb41VWIlwEI/AAAAAAAAKWQ/G_GQRLIwPow/s1600-h/init_usage_old.png"&gt;&lt;img style="cursor: pointer; width: 378px; height: 77px;" src="http://3.bp.blogspot.com/_aPBCtYeet9E/Sb41VWIlwEI/AAAAAAAAKWQ/G_GQRLIwPow/s400/init_usage_old.png" alt="" id="BLOGGER_PHOTO_ID_5313743251178897474" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-size:85%;" &gt;мое чувство прекрасного плачет =).&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-size:85%;" &gt;Все это конечно не отменяет проверок на наличие сессии в самом объекте, т.к. он должен разрешать редактировать себя только на протяжение последней, а в остальном мне кажется несколько упрощает код, избавляя его от 2х строчек =), зато визуально ограничивает рамки сессии, что на мой взгляд весьма удобно и лаконично.&lt;br /&gt;&lt;br /&gt;UPD: поступила вполне обоснованная критика - трудно читаемый код,  тяжело разобраться зачем создавать аккаунт и сразу же "диспозить" его. На это могу лишь ответить, что API в данном случае (и вообще, если применяется этот паттерн) должно подсказывать ЧТО оно возвращает, другими словами метод называется не AddAccount, a InitializeAndAddAccount. А еще лучше если бы он назывался CreateAccountInitializer =).&lt;br /&gt;&lt;br /&gt;UPD#2:&lt;br /&gt;Придумал как избавиться от неразберихи и нарушения принципов, сохранив красоту идеи.&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-size:85%;" &gt;Не надо делать никаких "conventions" в API. Надо дать возможность желающим писать так как они хотят и привыкли, а извращенцам вроде меня дать возможность "юзать" такие "извраты":&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_aPBCtYeet9E/ScElIGqNzeI/AAAAAAAAKWY/3jnxW7r6dM4/s1600-h/initializable.png"&gt;&lt;img style="cursor: pointer; width: 382px; height: 400px;" src="http://1.bp.blogspot.com/_aPBCtYeet9E/ScElIGqNzeI/AAAAAAAAKWY/3jnxW7r6dM4/s400/initializable.png" alt="" id="BLOGGER_PHOTO_ID_5314569856430755298" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;&lt;br /&gt;и пример:&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/ScElIeHj_DI/AAAAAAAAKWg/6xWXlHCHH0M/s1600-h/initsession_ex.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 111px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/ScElIeHj_DI/AAAAAAAAKWg/6xWXlHCHH0M/s400/initsession_ex.png" alt="" id="BLOGGER_PHOTO_ID_5314569862727859250" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family: verdana;"&gt;&lt;br /&gt;как видите API ничуть не пострадало и осталось читабельным и ясным, и ничьи принципы не нарушены.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-size:85%;" &gt;PS: И еще одно дополнение. Вся эта возня вокруг Disposable паттерна - это ничто иное как smart pointer для .Net! Те из вас, кто писал на С++ поймут о чем я.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: verdana;font-size:85%;" &gt;&lt;br /&gt;Удачи!&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-724228426864675072?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=SelJ5asfSjM:LbVezxRzWgQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=SelJ5asfSjM:LbVezxRzWgQ:63t7Ie-LG7Y"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?d=63t7Ie-LG7Y" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?a=SelJ5asfSjM:LbVezxRzWgQ:F7zBnMyn0Lo"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/Bobbbbloggg?i=SelJ5asfSjM:LbVezxRzWgQ:F7zBnMyn0Lo" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/SelJ5asfSjM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/SelJ5asfSjM/initializable-pattern.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_aPBCtYeet9E/Sb4SS0qaWdI/AAAAAAAAKV4/5_KSpvyc9a0/s72-c/initializer.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2009/03/initializable-pattern.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-7000640570044430342</guid><pubDate>Mon, 02 Feb 2009 08:11:00 +0000</pubDate><atom:updated>2009-02-02T00:23:25.562-08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">addin</category><title>Much of muchness. Other readings.</title><description>&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;This is a short note on other possible solutions of forementioned scenarios that these series of articles were devoted to. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Actually there is only one writer that had discovered the same theme. His name is &lt;/span&gt;&lt;a href="http://kentb.blogspot.com/"&gt;&lt;span style="font-family:verdana;"&gt;Kent Boogaart&lt;/span&gt;&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;. You might know him for his &lt;a href="http://www.codeplex.com/wpfcab"&gt;SCSF.WPF Contrib&lt;/a&gt; project, that I for one actively use in my projects.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Discovering MAF-enabled solution he breakes it to following pieces:&lt;/span&gt;&lt;/span&gt;&lt;a href="http://kentb.blogspot.com/2008/06/maf-gymnastics-event-hub.html"&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/a&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://kentb.blogspot.com/2008/06/maf-gymnastics-skeletal-solution.html"&gt;Skeletal solution&lt;/a&gt;;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://kentb.blogspot.com/2008/06/maf-gymnastics-event-hub.html"&gt;Event Hub&lt;/a&gt;;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://kentb.blogspot.com/2008/06/maf-gymnastics-service-provider.html"&gt;Service Provider&lt;/a&gt;;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt; &lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;The most interesting parts here are Event Hub and Service Provider implementations.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Kent's techinque is fully based on MAF advantages (it means he doesn't use any other .Net libraries as I did with WCF in my &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://bobbbloggg.blogspot.com/2009/01/much-of-muchness-part-6-xappdomain.html"&gt;EventBroker&lt;/a&gt;&lt;span style="font-family:verdana;"&gt; implementation) finishing with the fully independent addins and hosts, that is not true in my case, where host and addin are coupled by service contracts and service provider libraries.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;P.S. other articles in this series&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://bobbbloggg.blogspot.com/2008/06/addins-in-plugins-or-much-of-muchness.html"&gt;Part 1. Overview.&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://bobbbloggg.blogspot.com/2008/03/addins-in-plugins-or-much-of-muchness.html"&gt;Part 2. MAF addin UI - gadget. Object model.&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://bobbbloggg.blogspot.com/2008/09/much-of-muchness-part-3-wpf-interop-and.html"&gt;Part 3. WPF-interop and "airspace" notion - hosting gadgets in complex shape windows.&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://bobbbloggg.blogspot.com/2008/09/much-of-muchness-part-4-publishing-maf.html"&gt;Part 4. Publishing MAF addin settings.&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://bobbbloggg.blogspot.com/2008/12/much-of-muchness-part-5-handling.html"&gt;Part 5. Handling unhandled exceptions in isolated addin domains, gadget host.&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://bobbbloggg.blogspot.com/2009/01/much-of-muchness-part-6-xappdomain.html"&gt;&lt;span style="font-size:85%;"&gt;Part 6. Cross-AppDomain events propagation powered by Juval Lowy's WCF Pub-Sub &lt;/span&gt;&lt;span style="font-size:85%;"&gt;framework.&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;P.P.S. Actually there is nothing preventing you from generating proxies to subscription and publication services in addin's and host's projects separately, so there is only one dependency left - my ServiceProvider library.&lt;/span&gt;&lt;/span&gt; &lt;span style="font-size:78%;"&gt;&lt;span style="font-family:verdana;"&gt;Not a big deal =)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Good luck!&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-7000640570044430342?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?a=3uRjEw7g"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?a=z58atfYI"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?d=42" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?a=2fybURro"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?i=2fybURro" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/CCmkRH3-4wM" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/CCmkRH3-4wM/much-of-muchness-other-readings.html</link><author>noreply@blogger.com (RobertT)</author><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2009/02/much-of-muchness-other-readings.html</feedburner:origLink></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-3831136297442839246.post-2014638351375677453</guid><pubDate>Tue, 27 Jan 2009 08:46:00 +0000</pubDate><atom:updated>2009-01-27T00:57:27.885-08:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">WPF</category><category domain="http://www.blogger.com/atom/ns#">patterns</category><category domain="http://www.blogger.com/atom/ns#">addin</category><category domain="http://www.blogger.com/atom/ns#">WCF</category><title>Much of muchness. Part 6. XAppDomain EventBroker.</title><description>&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Алилуйя! Мы добрались до заключительной (и самой интересной) части.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Здесь я расскажу, свой подход к реализации кросс-доменного EventAgregator'а.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Необходимость создания этого монстра диктует плагинная архитектура - различные изолированные модули, ничего не знающие об остальных плагинах, должны уметь оповещать окружающих о каком-то важном событии, причем получатели сообщения, обязательно будут жить в другом, изолированном домене.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Фундаментом моей платформы является CAB - composite application block, содержащим реализацию EventAggregator'а. Как сделать так, чтобы он не был ограничен одним доменом? Никак. Дело в том, что в CAB композиты публикуют события и подписываются на них при помощи ObjectBuilder pipeline, в котором специальная стратегия EventAggregator'а аккумулирует всю эту информацию. В нашем же случае все объекты плагинов будут создаваться MAF pipeline'ом, и доступа к ним у нас не будет. Так как же быть? Использовать WCF - Windows Communication Foundation.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;В WCF из коробки нет реализации механизма Publish-Subscribe, но есть все средства для его реализации. Подходов может быть несколько:&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms752254.aspx"&gt;Подписка на основании контракта&lt;/a&gt; (contract based);&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://www.codeproject.com/KB/WCF/WSEventing.aspx"&gt;реализовать стандарт&lt;/a&gt; &lt;a href="http://www.w3.org/Submission/WS-Eventing/"&gt;WS-Eventing&lt;/a&gt; (topic based);&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://msdn.microsoft.com/en-us/magazine/cc163537.aspx"&gt;Pub-Sub framework by Juval Lowy&lt;/a&gt; from IDesign (contract based);&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;За основу решения я взял последний framework от Juval Lowy и расширил его, сделав его contract&amp;amp;topic based, с тем, чтобы интегрировать его с CAB EventAggregator (topic based). Но обо всем по порядку.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;font-family:verdana;font-size:85%;"  &gt;Publish-Subscribe framework (С) Juval Lowy IDesign.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Дабы не повторяться, не буду описывать механизмы работы последнего, посему настоятельно рекомендую ознакомиться со &lt;/span&gt;&lt;a style="font-family: verdana;" href="http://msdn.microsoft.com/en-us/magazine/cc163537.aspx"&gt;статьей&lt;/a&gt;&lt;span style="font-family:verdana;"&gt;, в которой он описан.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Прежде всего небольшим изменениям подвергся контракт сервиса подписки. Теперь ему передается не имя метода, которое надо вызвать у подписчика, а некий объект, выражающий интерес в подписке, который содержит имя метода (contract based) и имя topic (topic based), по которым EventAggregator сможет определить заинтересованность того или иного подписчика в неком событии.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SW81xRIHAwI/AAAAAAAAJXs/RO96SG6dtCw/s1600-h/ISubscrSvc.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 83px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SW81xRIHAwI/AAAAAAAAJXs/RO96SG6dtCw/s400/ISubscrSvc.png" alt="" id="BLOGGER_PHOTO_ID_5291507207710900994" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/SW81xqbwkfI/AAAAAAAAJX0/aOkAoLv5YBs/s1600-h/Subscr.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 197px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/SW81xqbwkfI/AAAAAAAAJX0/aOkAoLv5YBs/s400/Subscr.png" alt="" id="BLOGGER_PHOTO_ID_5291507214504202738" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Интерфейс сервиса подписки кросс-доменного EventAggregator'а для моей платформы выглядит следующим образом:&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_aPBCtYeet9E/SW84BdL-htI/AAAAAAAAJYE/BF_MzwrYp1U/s1600-h/IXAppEA.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 86px;" src="http://1.bp.blogspot.com/_aPBCtYeet9E/SW84BdL-htI/AAAAAAAAJYE/BF_MzwrYp1U/s400/IXAppEA.png" alt="" id="BLOGGER_PHOTO_ID_5291509684849510098" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;основное его назначение - сообщать WCF инфраструктуре о том, что IEventNotifyCallback - это callback contract для нашего кросс-доменного EventAggregator'а. DomainDTO - это суперкласс для моих DTO.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Сам сервис реализован в классе XAppDomainEventBrokerSubscription.&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SX7C_JtlEoI/AAAAAAAAJcs/sGLpqZ9r6OY/s1600-h/XAppEBStrat.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 193px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SX7C_JtlEoI/AAAAAAAAJcs/sGLpqZ9r6OY/s400/XAppEBStrat.png" alt="" id="BLOGGER_PHOTO_ID_5295884602028921474" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Он выполняет функции сервиса подписки и связывает инфраструктуру CAB с нашим механизмом. Последнее осуществляется аналогичным CAB'овскому образом - поиск публикаторов событий (по соответствующим аттрибутам) и аккумуляция этих публикаторов в CAB EventAggregator с одной лишь разницой, что вместо подписчика подставляется суррогатный объект, который при получении события опубликует его в нашей кросс-доменной системе (фактически просто пробросит дальше). Интегрируется этот сервис в CAB при помощи специальной стратегии ObjectBuilder'а XAppDomainEventBrokerStrategy.&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_aPBCtYeet9E/SX7C_AX4s2I/AAAAAAAAJck/EzPXfos3lKw/s1600-h/XApppEBSubscrSvc.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 123px;" src="http://1.bp.blogspot.com/_aPBCtYeet9E/SX7C_AX4s2I/AAAAAAAAJck/EzPXfos3lKw/s400/XApppEBSubscrSvc.png" alt="" id="BLOGGER_PHOTO_ID_5295884599522014050" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Публикацией ведает XAppDomainEventBrokerPublication - наследник слегка измененного PublicationService&lt;/span&gt;&lt;t style="font-family: verdana;"&gt; сервиса из framework'а Juval Lowy. Первый реализует callback контракт как контракт сервиса, а последний на основании вызываемого метода и topic находит и вызывает соответствующий метод у соответствующего подписчика.&lt;br /&gt;&lt;/t&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SX7EspmPyKI/AAAAAAAAJc0/i_Tu7fWcXkk/s1600-h/XAppEBPubSvc.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 64px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SX7EspmPyKI/AAAAAAAAJc0/i_Tu7fWcXkk/s400/XAppEBPubSvc.png" alt="" id="BLOGGER_PHOTO_ID_5295886483193841826" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;t style="font-family: verdana;"&gt;&lt;br /&gt;Но возникает резонный вопрос - а где, собственно, этому сервису передается topic? И куда его вообще воткнуть, если это contract-based framework? Ответ прост. Засунуть в заголовок &lt;/t&gt;&lt;t style="font-family: verdana;"&gt;сообщения и занимаются этим клиенты сервиса. Их только надо унаследовать от &lt;/t&gt;&lt;t style="font-family: verdana;"&gt;PublisherServiceClient - часть моей инфраструктуры WCF (может быть опишу попозже).&lt;br /&gt;&lt;br /&gt;&lt;/t&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_aPBCtYeet9E/SX7GpZ1K7AI/AAAAAAAAJc8/WHRklONiJg8/s1600-h/XAppEBPubClients.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 299px;" src="http://4.bp.blogspot.com/_aPBCtYeet9E/SX7GpZ1K7AI/AAAAAAAAJc8/WHRklONiJg8/s400/XAppEBPubClients.png" alt="" id="BLOGGER_PHOTO_ID_5295888626445118466" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Обратите внимание - у базового клиента сервиса подписки есть свойство EventTopic, с помощью которого мы можем передать это значение в WCF pipeline через расширение канала EventTopicChannelExtension, с одним единственным свойством - EventTopic.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Помните суррогатные объекты, добавлявшиеся в EventBroker CAB? Так вот они публикуют события через EventPublisherClient, передавая ему значение EventTopic из аттрибута.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Как &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;EventTopicChannelExtension &lt;/span&gt;&lt;/span&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;попал в канал? Все тот же базовый клиент при создании фабрики каналов добавляет EventTopicFlowBehavior, выполняющий всю работу. &lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SX7Gpd_ANmI/AAAAAAAAJdE/tKrclDYMZqA/s1600-h/XAppEBPubClientsGetSvc.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 17px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SX7Gpd_ANmI/AAAAAAAAJdE/tKrclDYMZqA/s400/XAppEBPubClientsGetSvc.png" alt="" id="BLOGGER_PHOTO_ID_5295888627560101474" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_aPBCtYeet9E/SX7H2j8MDwI/AAAAAAAAJdM/-qi_6JllqjY/s1600-h/EventTopicBeh.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 134px;" src="http://3.bp.blogspot.com/_aPBCtYeet9E/SX7H2j8MDwI/AAAAAAAAJdM/-qi_6JllqjY/s400/EventTopicBeh.png" alt="" id="BLOGGER_PHOTO_ID_5295889952008834818" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Собственно всю работу делает даже не он, а следующие два джентельмена:&lt;/span&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_aPBCtYeet9E/SX7I4X-dZDI/AAAAAAAAJdk/rRFkGUHGTDs/s1600-h/EventTopicInitial.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 88px;" src="http://3.bp.blogspot.com/_aPBCtYeet9E/SX7I4X-dZDI/AAAAAAAAJdk/rRFkGUHGTDs/s400/EventTopicInitial.png" alt="" id="BLOGGER_PHOTO_ID_5295891082668500018" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a style="font-family: verdana;" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_aPBCtYeet9E/SX7IcErdoTI/AAAAAAAAJdc/K8yrH9bS17o/s1600-h/EventTopicInsp.png"&gt;&lt;img style="cursor: pointer; width: 400px; height: 138px;" src="http://2.bp.blogspot.com/_aPBCtYeet9E/SX7IcErdoTI/AAAAAAAAJdc/K8yrH9bS17o/s400/EventTopicInsp.png" alt="" id="BLOGGER_PHOTO_ID_5295890596452213042" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Первый, как следует из его названия, инициаллизирует канал, добавляя в него уже упоминавшееся выше расширение EventTopicChannelExtension для передачи EventTopic второму джентельмену, который собственно добавляет этот topic в заголовок передаваемого сообщения.&lt;br /&gt;Из этого самого заголовка, слегка модифицированный мной, PublicationService вычленяет EventTopic и фильтрует по нему подписчиков.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Вот и все! Теперь все, что нужно сделать по шагам:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;1. Создать прокси к сервису подписки и подписаться на интересуемое событие, указав при  желании метод контракта, который следует вызвать.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;2. Создать прокси к сервису публикации и вызвать, мимикрирующий под контракт подписчика сервис публикации, передав при желании topic.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;Не очень надеюсь вы не запутались, потому что сам запутывался не раз.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:verdana;"&gt;P.S. ссылки на предыдущие посты в этой серии&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul  style="font-family:verdana;"&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://bobbbloggg.blogspot.com/2008/06/addins-in-plugins-or-much-of-muchness.html"&gt;Part 1. Overview.&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://bobbbloggg.blogspot.com/2008/03/addins-in-plugins-or-much-of-muchness.html"&gt;Part 2. MAF addin UI - gadget. Object model.&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://bobbbloggg.blogspot.com/2008/09/much-of-muchness-part-3-wpf-interop-and.html"&gt;Part 3. WPF-interop and "airspace" notion - hosting gadgets in complex shape windows.&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://bobbbloggg.blogspot.com/2008/09/much-of-muchness-part-4-publishing-maf.html"&gt;Part 4. Publishing MAF addin settings.&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size:85%;"&gt;&lt;a href="http://bobbbloggg.blogspot.com/2008/12/much-of-muchness-part-5-handling.html"&gt;Part 5. Handling unhandled exceptions in isolated addin domains, gadget host.&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li style="font-weight: bold;"&gt;&lt;span style="font-size:85%;"&gt;Part 6. Cross-AppDomain events propagation powered by Juval Lowy's WCF Pub-Sub &lt;/span&gt;&lt;span style="font-size:85%;"&gt;framework.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:verdana;"&gt;Удачи!&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3831136297442839246-2014638351375677453?l=bobbbloggg.blogspot.com' alt='' /&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?a=Am4iEPJj"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?d=41" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?a=7DGmfHgZ"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?d=42" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?a=dJfbGOJX"&gt;&lt;img src="http://feeds.feedburner.com/~f/blogspot/Bobbbbloggg?i=dJfbGOJX" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/Bobbbbloggg/~4/onGe7vKt6ps" height="1" width="1"/&gt;</description><link>http://feedproxy.google.com/~r/blogspot/Bobbbbloggg/~3/onGe7vKt6ps/much-of-muchness-part-6-xappdomain.html</link><author>noreply@blogger.com (RobertT)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_aPBCtYeet9E/SW81xRIHAwI/AAAAAAAAJXs/RO96SG6dtCw/s72-c/ISubscrSvc.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://bobbbloggg.blogspot.com/2009/01/much-of-muchness-part-6-xappdomain.html</feedburner:origLink></item></channel></rss>

