tag:blogger.com,1999:blog-7120771064439426472024-03-13T03:03:27.897-07:00have funMarcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.comBlogger35125tag:blogger.com,1999:blog-712077106443942647.post-28047372032738289872012-10-26T02:18:00.001-07:002012-10-26T02:18:18.446-07:00TypeScript declaration files for popular JavaScript libraries<p>If you write code in <a href="http://www.typescriptlang.org/">TypeScript</a> and you need declaration files for some popular JavaScript libraries check <a href="https://github.com/marcinnajder/TypeScript-declaration-files">my repository</a>. I wrote almost complete declaration files for <a href="http://linqjs.codeplex.com/">linqjs</a>, <a href="https://github.com/pivotal/jasmine">jasmine</a> and <a href="http://angularjs.org/">angularjs</a> libraries so far.</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com8tag:blogger.com,1999:blog-712077106443942647.post-29135921865441209202012-10-06T03:59:00.001-07:002012-10-06T03:59:16.293-07:00TypeScript Interactive in Visual Studio (TypeScript REPL)<p>Last time I have been writing about <a href="http://mnajder.blogspot.com/2012/09/javascript-interactive-in-visual-studio.html">JavaScript Interactive</a><u>.</u> After announcement of a new language called <a href="http://www.typescriptlang.org/">TypeScript</a> last Monday (2012.10. 01) I have upgraded my solution to work also with TypeScript language. Everything works exactly the same as <a href="http://mnajder.blogspot.com/2012/09/javascript-interactive-in-visual-studio.html">previously</a> but instead of calling <em>Generate </em>method at the end of the file we need to call TypeScript’s counterpart <em>GenerateFromTS</em>. This method takes 3 parameters: two optional parameters already described (<em>useClipboard</em> , <em>history </em>– here TS file) and one new optional parameter <em>jsFile</em>. TypeScript language is compiled into JavaScript so parameter <em>jsFile</em> specifies the path where generated JavaScript code is stored. Let’s look at the sample usage of TypeScript Interactive:</p> <p><a href="http://lh3.ggpht.com/-m69N2R37Mik/UHAO_nPUDSI/AAAAAAAAAdM/dn1RcZzRN5Q/s1600-h/image4.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-hJK8VqfvtPQ/UHAPAoe1BqI/AAAAAAAAAdQ/iHmqdA8WzgM/image_thumb2.png?imgmax=800" width="1104" height="361" /></a></p> <p>New JS/TS Interactive implementation looks like this:</p> <div> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><#@ template hostspecific=<span style="color: #006080">"true"</span>#><br /><#@ output extension=<span style="color: #006080">".txt"</span>#><br /><#@ assembly name=<span style="color: #006080">"System.Windows.Forms"</span> #><br /><#@ assembly name=<span style="color: #006080">"System.Core"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.Diagnostics"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.Text"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.Windows.Forms"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.IO"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.Linq"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.Threading"</span> #><br /><br /><#+<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Generate(<span style="color: #0000ff">bool</span> useClipboard = <span style="color: #0000ff">false</span>, <span style="color: #0000ff">string</span> historyFile = <span style="color: #0000ff">null</span>, Func<<span style="color: #0000ff">string</span>, <span style="color: #0000ff">string</span>> convertFileContent = <span style="color: #0000ff">null</span>) <br /> {<br /> var fileContent = useClipboard ? GetClipboardText() : File.ReadAllText(Host.TemplateFile);<br /> convertFileContent = convertFileContent ?? (s => s);<br /> <br /> GenerationEnvironment.Clear();<br /> <br /> var tempFile = Path.GetTempFileName();<br /> <br /> <span style="color: #0000ff">if</span>(<span style="color: #0000ff">string</span>.IsNullOrEmpty(historyFile))<br /> { <br /> File.WriteAllText(tempFile, convertFileContent(fileContent));<br /> RunProcess(<span style="color: #006080">"node"</span>, tempFile, WriteLine, WriteLine);<br /> File.Delete(tempFile);<br /> }<br /> <span style="color: #0000ff">else</span><br /> { <br /> var historyFilePath = Host.ResolvePath(historyFile);<br /> <span style="color: #0000ff">if</span>(!File.Exists(historyFilePath))<br /> {<br /> WriteLine(<span style="color: #006080">"Specified history file path '{0}' does not exist."</span>, historyFilePath);<br /> }<br /> <span style="color: #0000ff">else</span><br /> { <br /> var historyLines = File.ReadAllLines(historyFilePath);<br /> <span style="color: #0000ff">int</span>? printedOutputLinesCount = ExtractOutputLinesCount(historyLines);<br /> <span style="color: #0000ff">long</span> i = 0, max = printedOutputLinesCount ?? 0;<br /> var tempFileLines = <br /> (printedOutputLinesCount == <span style="color: #0000ff">null</span> ? <span style="color: #0000ff">new</span> [] {<span style="color: #006080">"//0"</span>} : <span style="color: #0000ff">new</span> <span style="color: #0000ff">string</span>[0])<br /> .Concat(historyLines) <br /> .Concat(fileContent.Split(<span style="color: #0000ff">new</span> <span style="color: #0000ff">string</span>[] {Environment.NewLine},StringSplitOptions.None))<br /> .Concat(<span style="color: #0000ff">new</span> [] {<span style="color: #0000ff">new</span> <span style="color: #0000ff">string</span>(<span style="color: #006080">'/'</span>,100)}) <br /> .ToArray();<br /><br /> var content = convertFileContent(<span style="color: #0000ff">string</span>.Join(Environment.NewLine, tempFileLines));<br /> <span style="color: #0000ff">if</span>(content == <span style="color: #0000ff">null</span>)<br /> <span style="color: #0000ff">return</span>;<br /><br /> File.WriteAllText(tempFile, content);<br /> var result = RunProcess(<span style="color: #006080">"node"</span>, tempFile, s => { <span style="color: #0000ff">if</span>(++i >= max) WriteLine(s); }, WriteLine );<br /> File.Delete(tempFile);<br /><br /> <span style="color: #0000ff">if</span>(result == 0) <span style="color: #008000">// ok</span><br /> {<br /> tempFileLines[0] = <span style="color: #006080">@"//"</span> + i;<br /> File.WriteAllLines(historyFilePath, tempFileLines);<br /> }<br /> }<br /> } <br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> GenerateFromTS(<span style="color: #0000ff">string</span> jsFile = <span style="color: #0000ff">null</span>, <span style="color: #0000ff">bool</span> useClipboard = <span style="color: #0000ff">false</span>, <span style="color: #0000ff">string</span> historyFile = <span style="color: #0000ff">null</span>) <br /> {<br /> Generate(useClipboard, historyFile,<br /> tsContent => <br /> {<br /> var tsTempFile = Path.ChangeExtension(Path.GetTempFileName(), <span style="color: #006080">"ts"</span>);<br /> var jsTempFile = Path.GetTempFileName();<br /> File.WriteAllText(tsTempFile, tsContent);<br /> var result = RunProcess(<span style="color: #006080">@"tsc"</span>, <span style="color: #0000ff">string</span>.Format(<span style="color: #006080">"--out \"{0}\" \"{1}\" "</span>,jsTempFile, tsTempFile), WriteLine, WriteLine);<br /> File.Delete(tsTempFile);<br /><br /> <span style="color: #0000ff">if</span>(result != 0) <span style="color: #008000">// !ok</span><br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;<br /> <br /> var jsContent = File.ReadAllText(jsTempFile);<br /><br /> <span style="color: #0000ff">if</span>(!<span style="color: #0000ff">string</span>.IsNullOrEmpty(jsFile))<br /> { <br /> var jsFilePath = Host.ResolvePath(jsFile); <br /> <span style="color: #0000ff">if</span>(!File.Exists(jsFilePath))<br /> WriteLine(<span style="color: #006080">"Specified JavaScript file path '{0}' does not exist."</span>, jsFilePath);<br /> <span style="color: #0000ff">else</span><br /> File.WriteAllText(jsFilePath, jsContent);<br /> }<br /> <br /> File.Delete(jsTempFile);<br /> <span style="color: #0000ff">return</span> jsContent;<br /> } );<br /> }<br /><br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">int</span>? ExtractOutputLinesCount(<span style="color: #0000ff">string</span>[] allLines)<br /> {<br /> <span style="color: #0000ff">int</span> count;<br /> <span style="color: #0000ff">string</span> firstLine = <span style="color: #0000ff">null</span>;<br /><br /> <span style="color: #0000ff">return</span> (allLines != <span style="color: #0000ff">null</span>) && ((firstLine = allLines.FirstOrDefault()) != <span style="color: #0000ff">null</span>) && <span style="color: #0000ff">int</span>.TryParse(firstLine.Replace(<span style="color: #006080">@"//"</span>,<span style="color: #006080">""</span>), <span style="color: #0000ff">out</span> count) ?<br /> (<span style="color: #0000ff">int</span>?)count : <span style="color: #0000ff">null</span>;<br /> }<br /><br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">int</span> RunProcess(<span style="color: #0000ff">string</span> processName, <span style="color: #0000ff">string</span> processArguments, Action<<span style="color: #0000ff">string</span>> onOutputDataReceived = <span style="color: #0000ff">null</span>, Action<<span style="color: #0000ff">string</span>> onErrorDataReceived = <span style="color: #0000ff">null</span>)<br /> {<br /> onOutputDataReceived = onOutputDataReceived ?? (s => {});<br /> onErrorDataReceived = onErrorDataReceived ?? (s => {});<br /><br /> var processStartInfo = <span style="color: #0000ff">new</span> ProcessStartInfo(processName, processArguments);<br /><br /> processStartInfo.RedirectStandardInput = <span style="color: #0000ff">true</span>;<br /> processStartInfo.RedirectStandardOutput = <span style="color: #0000ff">true</span>;<br /> processStartInfo.RedirectStandardError = <span style="color: #0000ff">true</span>;<br /> processStartInfo.CreateNoWindow = <span style="color: #0000ff">true</span>;<br /> processStartInfo.UseShellExecute = <span style="color: #0000ff">false</span>;<br /><br /> var process = Process.Start(processStartInfo);<br /><br /> process.OutputDataReceived += (sender, args) => onOutputDataReceived(args.Data); <br /> process.ErrorDataReceived += (sender, args) => { <span style="color: #0000ff">if</span>(args.Data!=<span style="color: #0000ff">null</span>) onErrorDataReceived(args.Data); };<br /> process.BeginOutputReadLine();<br /> process.BeginErrorReadLine();<br /> process.WaitForExit(); <br /> <span style="color: #0000ff">return</span> process.ExitCode;<br /> }<br /> <br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">string</span> GetClipboardText()<br /> {<br /> <span style="color: #0000ff">try</span><br /> {<br /> <span style="color: #0000ff">return</span> Clipboard.GetDataObject().GetData(DataFormats.Text) <span style="color: #0000ff">as</span> <span style="color: #0000ff">string</span>; <br /> }<br /> <span style="color: #0000ff">catch</span><br /> {<br /> <span style="color: #0000ff">return</span> <span style="color: #006080">""</span>;<br /> }<br /> }<br />#></pre>
</div>
<div> </div>
<div>There is one thing worth mentioning about executing TS Interactive using REPL session state stored inside history file. If we copy <em>Greeter</em> class definition to the clipboard and save the file twice we will get the error “Duplicate identifier ‘Greeter'”. It’s because the history file contains all successfully executed code snippets and this file as a whole needs to be correct. In TypeScript we cannot define two classes with the same name.</div> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com1tag:blogger.com,1999:blog-712077106443942647.post-59121289475593869972012-09-28T03:32:00.001-07:002012-09-28T03:32:56.801-07:00JavaScript Interactive in Visual Studio (JavaScript REPL)<p>The time has come. The time to learn JavaScript :) As usually when I‘m learning some new technology, I spent most of my time inside IDE like Visual Studio.  I’ve opened some good resources on the tab (this time it’s a book: <a href="http://shop.oreilly.com/product/9780596101992.do">JavaScript: The Definitive Guide</a>), a raw text file with my notes on the other . You may ask: why inside IDE ? Because I always try to use new technologies I’m reading about in practice. The problem with JavaScript is that in most cases it runs inside web browser. But I don’t want to make any web pages to test some feature of JavaScript language. I just want to write a few lines of JavaScript code and execute them. So I need something called <a href="http://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a> for JavaScript. REPL works very similar to Windows command line but it usually provides one great feature, the session state. In case of JavaScript that means that every time we execute some code we have access to all state - like variables, functions, etc. defined by previous executions. Each modern web browser has a tool called console where we can execute any piece of JavaScript code and its result is retuned immediately. Some tools like <a href="https://getfirebug.com/">Firebug</a> go even further providing a nice code editor with syntax highlighting and intellisense support where we can select part of script and “send it to REPL”. Image below shows how we use such a tool.<a href="http://lh6.ggpht.com/-GsZB2A9Loj8/UGV8xIzIZuI/AAAAAAAAAcU/DDjFzQcDZWg/s1600-h/image16.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/-hwIIyLDbEv0/UGV8x559DGI/AAAAAAAAAcc/TFiVoMrPv4U/image_thumb9.png?imgmax=800" width="631" height="283" /></a></p> <p>If we work with F# we can do the same thing directly from Visual Studio via F# Interactive windows. If we work with C# we have to install <a href="http://msdn.microsoft.com/en-us/vstudio/roslyn.aspx">Roslyn</a> and we will get C# Interactive window. Unfortunately we don’t have anything similar for JavaScript (at least so far ;) ).</p> <p>In this post I will show you how we can accomplish very similar behavior to that presented above with JavaScript language. Here is the full list of steps that need to be done:</p> <ol> <li>Install <a href="http://nodejs.org/">nodejs</a> (don’t be afraid, It’s free and very light - just a “single” exe file) </li> <li>Create a new project in Visual Studio, for example “ASP.NET Empty Web Application” (my solution doesn’t work with Web Site projects) </li> <li>Add a new template file called JsRepl.tt and copy its content from code below (this template doesn’t generate any output text so we optionally clear its default Custom Tool property using property grid) </li> <li>Add a new JS file next to JsRepl.tt and set its Custom Tool property to TextTemplatingFileGenerator. A new file will be automatically added to the project under JS file. Open those two files one above the other, JS file is our input windows and generated file is our output window. Each time we save JS file, its content will be executed immediately. </li> <li>Now we can write any JavaScript code in JS file except the first and the last line. The first line should look like this <strong>//<#@ include file="JsRepl.tt"#></strong> . It’s a T4 directive that includes (pastes) template file we just added to the project. The last line specifies how we want to execute JS code: </li> </ol> <ul> <ul> <li><strong>//<# Generate();#></strong> – executes the whole JS file </li> <li><strong>//<# Generate(useClipboard:true);#></strong> – executes code from the clipboard so selecting the code and pressing Ctrl+C, Ctrl+S simulates sending code to REPL :) </li> <li><strong>//<# Generate(useClipboard:true, historyFile:"history.js");#> </strong>– works the same as code above but additionally stores all previous successfully executed code inside specified helper JS file (here history.js). Every time we try to execute code from the clipboard, the one big file is created underneath and executed. This file combines the content of history file with the code from the clipboard. This is how we can easily simulate REPL session state mechanism :) </li> </ul> </ul> <p>Let’s look at a sample usage:</p> <p><a href="http://lh3.ggpht.com/-j8cgwuLDhr4/UGV8ykuHESI/AAAAAAAAAck/8kMOhVarpVI/s1600-h/image15.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/-1UpyW8-G8Dk/UGV8zqmThdI/AAAAAAAAAcs/-MQArY-eaAk/image_thumb8.png?imgmax=800" width="885" height="588" /></a></p> <p>The output window (ReplSample.txt file) displays the result of calling selected text from input windows (ReplSample.js file). Before that I did two additional executions, first one with text declaring <em>count</em> variable, the second one with definition of the function <em>printNumber</em>. The history file looks like this:</p> <p><a href="http://lh5.ggpht.com/-21Qr5ONBX6s/UGV80VcuMnI/AAAAAAAAAc0/WhxRsei9pVM/s1600-h/image14.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/-LZO64Osn-ew/UGV81GZ4wGI/AAAAAAAAAc4/VfNK3NOjeIM/image_thumb7.png?imgmax=800" width="752" height="253" /></a></p> <p>Now it’s time to reveal the secret how the JS REPL in Visual Studio was implemented. JsRepl.tt file is the whole implementation:</p> <div id="codeSnippetWrapper"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><#@ template hostspecific=<span style="color: #006080">"true"</span>#><br /><#@ output extension=<span style="color: #006080">".txt"</span>#><br /><#@ assembly name=<span style="color: #006080">"System.Windows.Forms"</span> #><br /><#@ assembly name=<span style="color: #006080">"System.Core"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.Diagnostics"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.Text"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.Windows.Forms"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.IO"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.Linq"</span> #><br /><#@ import <span style="color: #0000ff">namespace</span>=<span style="color: #006080">"System.Threading"</span> #><br /><br /><#+<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Generate(<span style="color: #0000ff">bool</span> useClipboard = <span style="color: #0000ff">false</span>, <span style="color: #0000ff">string</span> historyFile = <span style="color: #0000ff">null</span>) <br /> {<br /> GenerationEnvironment.Clear();<br /> <br /> <span style="color: #0000ff">if</span>(!useClipboard)<br /> { <br /> RunNode(Host.TemplateFile, WriteLine, WriteLine);<br /> }<br /> <span style="color: #0000ff">else</span><br /> {<br /> var text = GetClipboardText();<br /> var tempFile = Path.GetTempFileName();<br /><br /> <span style="color: #0000ff">if</span>(<span style="color: #0000ff">string</span>.IsNullOrEmpty(historyFile))<br /> { <br /> File.WriteAllText(tempFile,text);<br /> RunNode(tempFile, WriteLine, WriteLine);<br /> }<br /> <span style="color: #0000ff">else</span><br /> {<br /> var historyFilePath = Host.ResolvePath(historyFile);<br /> <span style="color: #0000ff">if</span>(!File.Exists(historyFilePath))<br /> {<br /> WriteLine(<span style="color: #006080">"Specified history file path '{0}' does not exist."</span>, historyFilePath);<br /> }<br /> <span style="color: #0000ff">else</span><br /> { <br /> var historyLines = File.ReadAllLines(historyFilePath);<br /> <span style="color: #0000ff">int</span>? printedOutputLinesCount = ExtractOutputLinesCount(historyLines);<br /> <span style="color: #0000ff">long</span> i = 0, max = printedOutputLinesCount ?? 0;<br /> var tempFileLines = <br /> (printedOutputLinesCount == <span style="color: #0000ff">null</span> ? <span style="color: #0000ff">new</span> [] {<span style="color: #006080">"//0"</span>} : <span style="color: #0000ff">new</span> <span style="color: #0000ff">string</span>[0])<br /> .Concat(historyLines) <br /> .Concat(text.Split(<span style="color: #0000ff">new</span> <span style="color: #0000ff">string</span>[] {Environment.NewLine},StringSplitOptions.None))<br /> .Concat(<span style="color: #0000ff">new</span> [] {<span style="color: #0000ff">new</span> <span style="color: #0000ff">string</span>(<span style="color: #006080">'/'</span>,100)}) <br /> .ToArray();<br /><br /> File.WriteAllLines(tempFile, tempFileLines);<br /><br /> var result = RunNode(tempFile, s => { <span style="color: #0000ff">if</span>(++i >= max) WriteLine(s); }, WriteLine );<br /> <br /> <span style="color: #0000ff">if</span>(result == 0) <span style="color: #008000">// ok</span><br /> {<br /> tempFileLines[0] = <span style="color: #006080">@"//"</span> + i;<br /> File.WriteAllLines(historyFilePath, tempFileLines);<br /> }<br /> }<br /> }<br /><br /> <span style="color: #0000ff">if</span>(File.Exists(tempFile))<br /> File.Delete(tempFile);<br /> }<br /> }<br /><br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">int</span>? ExtractOutputLinesCount(<span style="color: #0000ff">string</span>[] allLines)<br /> {<br /> <span style="color: #0000ff">int</span> count;<br /> <span style="color: #0000ff">string</span> firstLine = <span style="color: #0000ff">null</span>;<br /><br /> <span style="color: #0000ff">return</span> (allLines != <span style="color: #0000ff">null</span>) && ((firstLine = allLines.FirstOrDefault()) != <span style="color: #0000ff">null</span>) && <span style="color: #0000ff">int</span>.TryParse(firstLine.Replace(<span style="color: #006080">@"//"</span>,<span style="color: #006080">""</span>), <span style="color: #0000ff">out</span> count) ?<br /> (<span style="color: #0000ff">int</span>?)count : <span style="color: #0000ff">null</span>;<br /> }<br /><br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">int</span> RunNode(<span style="color: #0000ff">string</span> jsFile, Action<<span style="color: #0000ff">string</span>> onOutputDataReceived, Action<<span style="color: #0000ff">string</span>> onErrorDataReceived)<br /> {<br /> var processStartInfo = <span style="color: #0000ff">new</span> ProcessStartInfo(<span style="color: #006080">@"node"</span>, jsFile);<br /><br /> processStartInfo.RedirectStandardInput = <span style="color: #0000ff">true</span>;<br /> processStartInfo.RedirectStandardOutput = <span style="color: #0000ff">true</span>;<br /> processStartInfo.RedirectStandardError = <span style="color: #0000ff">true</span>;<br /> processStartInfo.CreateNoWindow = <span style="color: #0000ff">true</span>;<br /> processStartInfo.UseShellExecute = <span style="color: #0000ff">false</span>;<br /><br /> var process = Process.Start(processStartInfo);<br /><br /> process.OutputDataReceived += (sender, args) => onOutputDataReceived(args.Data);<br /> process.ErrorDataReceived += (sender, args) => { <span style="color: #0000ff">if</span>(args.Data!=<span style="color: #0000ff">null</span>) onErrorDataReceived(args.Data); };<br /> process.BeginOutputReadLine();<br /> process.BeginErrorReadLine();<br /> process.WaitForExit();<br /> <span style="color: #0000ff">return</span> process.ExitCode;<br /> }<br /> <br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">string</span> GetClipboardText()<br /> {<br /> <span style="color: #0000ff">try</span><br /> {<br /> <span style="color: #0000ff">return</span> Clipboard.GetDataObject().GetData(DataFormats.Text) <span style="color: #0000ff">as</span> <span style="color: #0000ff">string</span>; <br /> }<br /> <span style="color: #0000ff">catch</span><br /> {<br /> <span style="color: #0000ff">return</span> <span style="color: #006080">""</span>;<br /> }<br /> }<br />#></pre>
<br /></div>
<p>There are a couple of things worth explanation here. You may be wondering how I actually execute JavaScript code outside of the browser ? I use node.exe console application passing JavaScript file path as an argument and I listen what result is printed. T4 template mechanism use <em>WriteLine</em> method to write something to the input file. This method appends passed string argument to the internal StringBuilder object stored in property called <em>GenerationEnvironment</em>. By default each line of the template file (JS file in this case) which is not a directive or control flow statement (code inside regions <#, <#+ or <#= ) is passed to the <em>WriteLine</em> method. That’s why the main method called <em>Generate</em> is placed at the end of template file and clears everything that was written before its execution by calling StringBuilder <em>Clear</em> method. Because the whole history file is executed from the beginning to the end but we want to see results only of the latest part (that from the clipboard) I use special counter stored in the first line in history file. This counter represents a number of lines printed during history file execution and it’s used to suspend printing process till the appropriate moment when the code from the clipboard is executed.</p>
<p>And that’s all. Simple as it is I hope you find it useful like I did :)</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0tag:blogger.com,1999:blog-712077106443942647.post-38265124334865804652012-05-06T13:51:00.001-07:002012-05-06T13:51:34.471-07:00Running RIA Services on the top of Raven DB<p>In this post I will describe how to integrate <a href="http://www.silverlight.net/learn/advanced-techniques/wcf-ria-services/get-started-with-wcf-ria-services">RIA Services</a> with document database called <a href="http://ravendb.net/">Raven DB</a>. If you are not familiar with those frameworks watch <a href="http://mnajder.blogspot.com/2012/02/ria-services-and-raven-db-presentation.html">this</a> video and <a href="http://mnajder.blogspot.com/2012/02/raven-db-presentation.html">this</a> one (my 2 presentations in polish). RIA Services integrates very easily with relational database by providing base implementations of domain services out of the box. Using the same pattern I have created the base implementation for services working with Raven DB. We will see later in this post what exactly the domain service is and how we can use it to build n-tier business application, but now let’s look at the Raven DB API. Let’s say we have the following data model:</p> <div id="codeSnippetWrapper"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">partial</span> <span style="color: #0000ff">class</span> Person <br />{ <br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Id { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Name { get; set; }<br /> <br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Biography { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Photos { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">double</span> AverageRating { get; set; }<br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">partial</span> <span style="color: #0000ff">class</span> Movie<br />{ <br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Id { get; set; }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Name { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Synopsis { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">double</span> AverageRating { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span>? ReleaseYear { get; set; }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> ImageUrl { get; set; }<br /> <br /> <span style="color: #0000ff">public</span> List<<span style="color: #0000ff">string</span>> Genres { get; set; }<br /> <span style="color: #0000ff">public</span> List<<span style="color: #0000ff">string</span>> Languages { get; set; }<br /><br /> <span style="color: #0000ff">public</span> List<PersonReference> Cast { get; set; }<br /> <span style="color: #0000ff">public</span> List<PersonReference> Directors { get; set; }<br /> <br /> <span style="color: #0000ff">public</span> List<Award> Awards { get; set; }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span> CommentsCount { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> CommentsId { get; set; }<br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> PersonReference<br />{<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> PersonId { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> PersonName { get; set; }<br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Award<br />{ <br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Type { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Category { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span>? Year { get; set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">bool</span> Won { get; set; }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> PersonId { get; set; }<br />}</pre>
<br /></div>
<p>With this we can do some base CRUD operation:</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">using</span> (var store = <span style="color: #0000ff">new</span> DocumentStore() { Url = <span style="color: #006080">"http://localhost:8080"</span>, }.Initialize())<br />{ <br /> <span style="color: #0000ff">using</span> (var session = store.OpenSession())<br /> {<br /> var davidDuchowny = <span style="color: #0000ff">new</span> Person() { Name = <span style="color: #006080">"David Duchovny"</span> };<br /> var demiMoore = <span style="color: #0000ff">new</span> Person() { Name = <span style="color: #006080">"Demi Moore"</span> };<br /> session.Store(davidDuchowny); <span style="color: #008000">// Id property is set here</span><br /> session.Store(demiMoore); <span style="color: #008000">// Id property is set here</span><br /><br /> var theJoneses = <span style="color: #0000ff">new</span> Movie()<br /> {<br /> Name = <span style="color: #006080">"The Joneses"</span>,<br /> Synopsis = <span style="color: #006080">"A seemingly perfect family moves into a suburban neighborhood, but when it comes to the "</span> +<br /> <span style="color: #006080">"truth as to why they're living there, they don't exactly come clean with their neighbors."</span>,<br /> ReleaseYear = 2009,<br /> AverageRating = 6.5,<br /> Genres = <span style="color: #0000ff">new</span> List<<span style="color: #0000ff">string</span>>() { <span style="color: #006080">"Comedy"</span>, <span style="color: #006080">"Drama"</span> },<br /> Cast = <span style="color: #0000ff">new</span> List<PersonReference>()<br /> {<br /> <span style="color: #0000ff">new</span> PersonReference() { PersonId = davidDuchowny.Id, PersonName = davidDuchowny.Name},<br /> <span style="color: #0000ff">new</span> PersonReference() { PersonId = demiMoore.Id, PersonName = demiMoore.Name},<br /> }<br /> };<br /> session.Store(theJoneses); <span style="color: #008000">// Id property is set here</span><br /><br /> session.SaveChanges(); <br /> }<br /> <br /> <span style="color: #0000ff">using</span> (var session = store.OpenSession())<br /> { <br /> var movie = (from m <span style="color: #0000ff">in</span> session.Query<Movie>()<br /> <span style="color: #0000ff">where</span> m.Name == <span style="color: #006080">"The Joneses"</span><br /> select m).FirstOrDefault();<br /> var people = session.Load<Person>(movie.Cast[0].PersonId, movie.Cast[1].PersonId);<br /> <br /> session.Delete(movie);<br /> session.Delete(people[0]); <br /> session.Delete(people[1]);<br /><br /> session.SaveChanges();<br /> }<br />}</pre>
<br /></div>
<p>Raven DB stores data as a JSON documents:</p>
<p><a href="http://lh5.ggpht.com/-8qv3rSdPADk/T6bkPm6AuEI/AAAAAAAAAYM/IR122B7KzNM/s1600-h/image8.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-BiMvrFr_zhw/T6bkSlH4QRI/AAAAAAAAAYU/LK9lyaQA7g4/image_thumb4.png?imgmax=800" width="648" height="513" /></a></p>
<p>Once we know how the Raven DB works we can look at the RIA Services. RIA Services gives us tools (Visual Studio extensions) and libraries that allow us to build n-tier business solution with the Silverlight or JavaScript application as a client and .Net Web Service as a server. We start building RIA Services solution from the domain service which is just a class deriving directly from DomainService or any other derived class depending on the type of a data store. </p>
<p><a href="http://lh4.ggpht.com/-snbXwoLrz-o/T6bkTdlsVEI/AAAAAAAAAYc/jCZx5166TRw/s1600-h/image3.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/-Ie8wvEWsutM/T6bkVKsbiZI/AAAAAAAAAYk/5ixYVn3WZ5Y/image_thumb1.png?imgmax=800" width="515" height="338" /></a></p>
<p>If the relation database is a data store then we can use <u>LinqToSqlDomainService</u>, <u>LinqToEntitesDomainService</u> or <u>DbDomainService</u> (LINQ to Entities Code First approach). <u>TableDomainService</u> class allows us to store data inside Windows Azure Table. If we want to store data inside any other kind of data source we have to derive directly from the DomainService class. My base service called RavenDomainService derives from DomainService and it encapsulates the logic of initializing and saving the data inside Raven DB. Let’s look at the sample usage of this class:</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet">[EnableClientAccess]<br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> NetflixDomainService : RavenDomainService<br />{<br /> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> IDocumentSession CreateSession()<br /> {<br /> var session = <span style="color: #0000ff">base</span>.CreateSession();<br /> session.Advanced.UseOptimisticConcurrency = <span style="color: #0000ff">true</span>;<br /> <span style="color: #0000ff">return</span> session;<br /> }<br /><br /> <span style="color: #0000ff">public</span> IQueryable<Person> GetPeople()<br /> {<br /> <span style="color: #0000ff">return</span> Session.Query<Person>();<br /> }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> InsertPerson(Person entity)<br /> {<br /> Session.Store(entity);<br /> }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> UpdatePerson(Person entity)<br /> {<br /> var original = ChangeSet.GetOriginal(entity);<br /> Session.Store(entity, original.Etag.Value); <span style="color: #008000">// optimistic concurrency </span><br /> }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> DeletePerson(Person entity)<br /> {<br /> var original = ChangeSet.GetOriginal(entity);<br /> Session.Store(entity, original != <span style="color: #0000ff">null</span> ? original.Etag.Value : entity.Etag.Value); <span style="color: #008000">// optimistic concurrency</span><br /> Session.Delete(entity);<br /> }<br /><br /> <span style="color: #0000ff">public</span> IQueryable<Movie> GetMovies()<br /> {<br /> <span style="color: #0000ff">return</span> Session.Query<Movie>();<br /> }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> InsertMovie(Movie entity)<br /> {<br /> Session.Store(entity);<br /> }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> UpdateMovie(Movie entity)<br /> {<br /> var original = ChangeSet.GetOriginal(entity);<br /> Session.Store(entity, original.Etag.Value); <span style="color: #008000">// optimistic concurrency </span><br /> }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> DeleteMovie(Movie entity)<br /> {<br /> var original = ChangeSet.GetOriginal(entity);<br /> Session.Store(entity, original != <span style="color: #0000ff">null</span> ? original.Etag.Value : entity.Etag.Value); <span style="color: #008000">// optimistic concurrency</span><br /> Session.Delete(entity);<br /> }<br />}</pre>
<br /></div>
<p>After adding “WCF RIA Services link” from the Silverlight project to projects containing domain service implemented above and rebuilding the whole solution, Visual Studio will generate appropriate code on the client side and we are ready to write code very similar to that presented earlier:</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet">async <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> BlogPost()<br />{<br /> var context = <span style="color: #0000ff">new</span> NetflixDomainContext();<br /> <br /> var davidDuchowny = <span style="color: #0000ff">new</span> Person() { Name = <span style="color: #006080">"David Duchovny"</span> };<br /> var demiMoore = <span style="color: #0000ff">new</span> Person() { Name = <span style="color: #006080">"Demi Moore"</span> };<br /> context.Persons.Add(davidDuchowny);<br /> context.Persons.Add(demiMoore);<br /><br /> await context.SubmitChanges().AsTask(); <span style="color: #008000">// Id property is set here</span><br /><br /> var theJoneses = <span style="color: #0000ff">new</span> Movie()<br /> {<br /> Name = <span style="color: #006080">"The Joneses"</span>,<br /> Synopsis = <span style="color: #006080">"A seemingly perfect family moves into a suburban neighborhood, but when it comes to the "</span> +<br /> <span style="color: #006080">"truth as to why they're living there, they don't exactly come clean with their neighbors."</span>,<br /> ReleaseYear = 2009,<br /> AverageRating = 6.5,<br /> Genres = <span style="color: #0000ff">new</span> List<<span style="color: #0000ff">string</span>>() { <span style="color: #006080">"Comedy"</span>, <span style="color: #006080">"Drama"</span> },<br /> Cast = <span style="color: #0000ff">new</span> List<PersonReference>()<br /> {<br /> <span style="color: #0000ff">new</span> PersonReference() { PersonId = davidDuchowny.Id, PersonName = davidDuchowny.Name},<br /> <span style="color: #0000ff">new</span> PersonReference() { PersonId = demiMoore.Id, PersonName = demiMoore.Name},<br /> }<br /> };<br /> context.Movies.Add(theJoneses);<br /><br /> await context.SubmitChanges().AsTask(); <span style="color: #008000">// Id property is set here</span><br /><br /><br /> var context2 = <span style="color: #0000ff">new</span> NetflixDomainContext();<br /> <br /> var movie = (await context2.Load<br /> (<br /> from m <span style="color: #0000ff">in</span> context2.GetMoviesQuery()<br /> <span style="color: #0000ff">where</span> m.Name == <span style="color: #006080">"The Joneses"</span><br /> select m<br /> )).FirstOrDefault();<br /><br /> var people = (await context2.Load<br /> (<br /> from p <span style="color: #0000ff">in</span> context2.GetPeopleQuery()<br /> <span style="color: #0000ff">where</span> p.Id == movie.Cast[0].PersonId || p.Id == movie.Cast[1].PersonId<br /> select p<br /> )).ToArray();<br /><br /> context2.Movies.Remove(movie);<br /> context2.Persons.Remove(people[0]);<br /> context2.Persons.Remove(people[1]);<br /> await context2.SubmitChanges().AsTask();<br />}</pre>
<br /></div>
<p>RIA Services gives us a very nice implementation of <a href="http://martinfowler.com/eaaCatalog/unitOfWork.html">Unit Of Work</a> and <a href="http://martinfowler.com/eaaCatalog/identityMap.html">Identity Map</a> patterns so the code using DAL frameworks like LINQ to SQL, LINQ to Entities, NHibernate or Raven DB is very similar to that written on the client side. There is one thing worth mentioning at this point, RIA Services needs to know which property identifies the entity object. I didn’t show you how to do it yet but it will be presented in a moment, I am writing about it here because without this little hint, the code above wouldn’t even compile.</p>
<p>The last thing I would like to explain is how the <a href="http://martinfowler.com/eaaCatalog/optimisticOfflineLock.html">optimistic concurrency</a> pattern has been implemented in case of Raven DB. Raven DB has metadata mechanism which means that each JSON document besides the actual data has additional information like document type, last modification time, etag and so on. Etag is a single value of type Guid and its goal is very similar to Timestamp or Row Version column data type in SQL Server. Raven DB server changes the value of Etag internally every time the document is changing. With this Raven DB client API allows us to enable optimistic concurrency checking  on the session object level via UseOptimisticConcurrency property. There is one problem when it comes to integration with RIA Services optimistic concurrency mechanism. Etag is part of the metadata instead of document itself and it is handled by the session object internally. RIA Services doesn’t have any notion of metadata information, all data is stored inside the entity objects so we need to add additional property storing etag value which will be used on the RIA Services level but on the Raven DB level this value will be mapped into etag metadata field.</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span> IEtag<br />{<br /> Guid? Etag { get; set; }<br />}<br /><br />[MetadataTypeAttribute(<span style="color: #0000ff">typeof</span>(PersonMetadata))]<br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">partial</span> <span style="color: #0000ff">class</span> Person : IEtag<br />{<br /> [JsonIgnore] <span style="color: #008000">// do not store value of this property</span><br /> <span style="color: #0000ff">public</span> Guid? Etag { get; set; }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> PersonMetadata<br /> {<br /> [Key]<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Id { get; set; }<br /><br /> [RoundtripOriginal] <span style="color: #008000">// send back value of this property to client</span><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Etag { get; set; }<br /> } <br />}<br /><br />[MetadataTypeAttribute(<span style="color: #0000ff">typeof</span>(MovieMetadata))]<br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">partial</span> <span style="color: #0000ff">class</span> Movie : IEtag<br />{<br /> [JsonIgnore] <span style="color: #008000">// do not store value of this property</span><br /> <span style="color: #0000ff">public</span> Guid? Etag { get; set; }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> MovieMetadata<br /> {<br /> [Key]<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Id { get; set; }<br /><br /> [Display(Name=<span style="color: #006080">"nazwa"</span>)]<br /> [Required]<br /> [StringLength(200)] <br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Name { get; set; }<br /><br /> [Range(1900, 2012)]<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> ReleaseYear { get; set; }<br /><br /> [RoundtripOriginal] <span style="color: #008000">// send back value of this property to client</span><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Etag { get; set; }<br /> }<br />}<br /></pre>
<br /></div>
<p>Attributes like Key, Display, Required, Range, RoundtripOriginal and MetadataType are a part of the standard .net mechanism called data annotations. RIA Services similar to other frameworks like ASP.MVC or Dynamic Data uses them to define validation rules or UI controls in layout in declarative way. Key attributes tell RIA Services which property identifies the entity object, RoundtripOriginal attributes tell that the value of the property is changed on the server side so the new value should be sent back to the client after calling server method. JsonIgnore is specific to Raven DB and it means that this property should be ignore during serialization and deserialization process. IEtag interface was introduced as a marker interface so all entities implementing this interface are treated specially by listener code. Listeners are a part of Raven DB client API and we can think of them as of a client side triggers executed in various situations.For instance during JSON document conversion process (IDocumentConversionListener) or before and after document is stored inside Raven DB (IDocumentStoreListener).</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Global : System.Web.HttpApplication<br />{<br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> IDocumentStore _documentStore;<br /><br /> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">void</span> Application_Start(<span style="color: #0000ff">object</span> sender, EventArgs e)<br /> {<br /> var etagSetterListener = <span style="color: #0000ff">new</span> EtagSetterListener();<br /><br /> _documentStore = <span style="color: #0000ff">new</span> DocumentStore() { Url = <span style="color: #006080">"http://localhost:8080"</span>, }<br /> .RegisterListener(etagSetterListener <span style="color: #0000ff">as</span> IDocumentConversionListener)<br /> .RegisterListener(etagSetterListener <span style="color: #0000ff">as</span> IDocumentStoreListener)<br /> .Initialize();<br /> <br /> DomainService.Factory = <span style="color: #0000ff">new</span> RavenDomainServiceFactory(_documentStore, DomainService.Factory);<br /> }<br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> EtagSetterListener : IDocumentConversionListener, IDocumentStoreListener<br />{<br /> <span style="color: #cc6633">#region</span> IDocumentConversionListener<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> EntityToDocument(<span style="color: #0000ff">object</span> entity, RavenJObject document, RavenJObject metadata)<br /> {<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> DocumentToEntity(<span style="color: #0000ff">object</span> entity, RavenJObject document, RavenJObject metadata)<br /> {<br /> var etag = entity <span style="color: #0000ff">as</span> IEtag;<br /> <span style="color: #0000ff">if</span> (etag != <span style="color: #0000ff">null</span>)<br /> {<br /> etag.Etag = Guid.Parse(metadata[<span style="color: #006080">"@etag"</span>].ToString());<br /> }<br /> } <br /> <span style="color: #cc6633">#endregion</span><br /><br /><br /> <span style="color: #cc6633">#region</span> IDocumentStoreListener<br /> <br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">bool</span> BeforeStore(<span style="color: #0000ff">string</span> key, <span style="color: #0000ff">object</span> entityInstance, RavenJObject metadata)<br /> {<br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> AfterStore(<span style="color: #0000ff">string</span> key, <span style="color: #0000ff">object</span> entityInstance, RavenJObject metadata)<br /> {<br /> var etag = entityInstance <span style="color: #0000ff">as</span> IEtag;<br /> <span style="color: #0000ff">if</span> (etag != <span style="color: #0000ff">null</span>)<br /> {<br /> etag.Etag = Guid.Parse(metadata[<span style="color: #006080">"@etag"</span>].ToString());<br /> }<br /> }<br /><br /> <span style="color: #cc6633">#endregion</span><br />}<br /><br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> RavenDomainServiceFactory : IDomainServiceFactory<br />{<br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">readonly</span> IDocumentStore _documentStore;<br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">readonly</span> IDomainServiceFactory _domainServiceFactory;<br /><br /> <span style="color: #0000ff">public</span> RavenDomainServiceFactory(IDocumentStore documentStore, IDomainServiceFactory domainServiceFactory)<br /> {<br /> _documentStore = documentStore;<br /> _domainServiceFactory = domainServiceFactory;<br /> }<br /><br /> <span style="color: #0000ff">public</span> DomainService CreateDomainService(Type domainServiceType, DomainServiceContext context)<br /> {<br /> var service = _domainServiceFactory.CreateDomainService(domainServiceType, context);<br /><br /> <span style="color: #0000ff">if</span> (service <span style="color: #0000ff">is</span> RavenDomainService)<br /> {<br /> ((RavenDomainService)service).DoumentStore = _documentStore; <br /> }<br /><br /> <span style="color: #0000ff">return</span> service;<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> ReleaseDomainService(DomainService domainService)<br /> {<br /> _domainServiceFactory.ReleaseDomainService(domainService);<br /> }<br />}<br /></pre>
<br /></div>
<p>IDomainServiceFactory interface allows us extend the process of creation and destruction of domain services instance on the server side. Finally let’s see how the RavenDomainService class has been implemented:</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; background-color: #f4f4f4; margin: 0em; border-left-style: none; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; border-right-style: none; font-size: 8pt; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">class</span> RavenDomainService : DomainService<br />{<br /> <span style="color: #0000ff">public</span> IDocumentStore DoumentStore { get; set; }<br /><br /> <span style="color: #0000ff">private</span> IDocumentSession _session;<br /> <span style="color: #0000ff">protected</span> IDocumentSession Session<br /> {<br /> get<br /> {<br /> <span style="color: #0000ff">if</span> (_session == <span style="color: #0000ff">null</span> && DoumentStore != <span style="color: #0000ff">null</span>)<br /> {<br /> _session = CreateSession();<br /> } <br /> <span style="color: #0000ff">return</span> _session;<br /> }<br /> }<br /><br /> <span style="color: #0000ff">private</span> IDocumentSession _refreshSession;<br /> <span style="color: #0000ff">private</span> IDocumentSession RefreshSession<br /> {<br /> get<br /> {<br /> <span style="color: #0000ff">if</span> (_refreshSession == <span style="color: #0000ff">null</span> && DoumentStore != <span style="color: #0000ff">null</span>)<br /> {<br /> _refreshSession = CreateSession();<br /> }<br /> <span style="color: #0000ff">return</span> _refreshSession;<br /> }<br /> }<br /><br /> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">virtual</span> IDocumentSession CreateSession()<br /> {<br /> var session = DoumentStore.OpenSession();<br /> <span style="color: #0000ff">return</span> session;<br /> }<br /><br /> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> Dispose(<span style="color: #0000ff">bool</span> disposing)<br /> {<br /> <span style="color: #0000ff">if</span> (disposing)<br /> {<br /> <span style="color: #0000ff">if</span> (_session != <span style="color: #0000ff">null</span>)<br /> {<br /> _session.Dispose();<br /> _session = <span style="color: #0000ff">null</span>;<br /> }<br /> <span style="color: #0000ff">if</span> (_refreshSession!= <span style="color: #0000ff">null</span>)<br /> {<br /> _refreshSession.Dispose();<br /> _refreshSession = <span style="color: #0000ff">null</span>;<br /> } <br /> }<br /> <span style="color: #0000ff">base</span>.Dispose(disposing);<br /> }<br /><br /> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">int</span> Count<T>(IQueryable<T> query)<br /> {<br /> <span style="color: #0000ff">return</span> query.Count();<br /> }<br /><br /> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">bool</span> PersistChangeSet()<br /> {<br /> <span style="color: #0000ff">try</span><br /> {<br /> <span style="color: #0000ff">this</span>.Session.SaveChanges();<br /> }<br /> <span style="color: #0000ff">catch</span> (ConcurrencyException exception)<br /> {<br /> var items = <span style="color: #0000ff">base</span>.ChangeSet.ChangeSetEntries<br /> .Where(changeSet =><br /> {<br /> var etag = changeSet.Entity <span style="color: #0000ff">as</span> IEtag;<br /> <span style="color: #0000ff">if</span> (etag == <span style="color: #0000ff">null</span>)<br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;<br /> <span style="color: #0000ff">return</span> etag.Etag == exception.ExpectedETag;<br /> })<br /> .ToArray();<br /> <br /> <span style="color: #0000ff">foreach</span> (var item <span style="color: #0000ff">in</span> items)<br /> {<br /> var o = ChangeSet.GetChangeOperation(item.Entity);<br /> <span style="color: #0000ff">if</span>(o == ChangeOperation.Delete)<br /> {<br /> item.IsDeleteConflict = <span style="color: #0000ff">true</span>;<br /> }<br /> <span style="color: #0000ff">else</span><br /> {<br /> item.ConflictMembers = <span style="color: #0000ff">new</span>[] { <span style="color: #006080">"unknown"</span> };<br /> var id = Session.Advanced.GetDocumentId(item.Entity);<br /> item.StoreEntity = RefreshSession.Load<<span style="color: #0000ff">object</span>>(id);<br /> }<br /> }<br /> <br /> <span style="color: #0000ff">this</span>.OnError(<span style="color: #0000ff">new</span> DomainServiceErrorInfo(exception));<br /><br /> <span style="color: #0000ff">if</span> (!<span style="color: #0000ff">base</span>.ChangeSet.HasError)<br /> {<br /> <span style="color: #0000ff">throw</span>;<br /> }<br /><br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;<br /> }<br /><br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;<br /> }<br />}<br /></pre>
<br /></div>
<p>I know, I know, I hear you saying: "What did you do all this for ??? Raven DB gives you a wonderful client API for Silverlight". I totally agree with you. I am not trying to say that you should use RIA Services instead of Raven DB directly via its Silverlight API. Those two frameworks are slightly different things. They have a different functionalities, they are designed to resolve a bit different kinds of problems. Raven DB is a database system so it is focused mainly on data storage. RIA Services solves many common problems for a business n-tier application like server and client side validation, easy integration with DataGrid or DataForm UI controls, sharing common code between client and server, marshaling exceptions and so on. For me, those two frameworks can work great together and such cooperation seems to be very reasonable. I was searching google for any samples showing how to integrate them but I couldn’t find it. So I did my own !:) I hope you find it useful.</p>
<p><a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15895">Download</a></p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com1tag:blogger.com,1999:blog-712077106443942647.post-29148937220411807342012-02-19T05:48:00.001-08:002012-02-19T06:01:58.966-08:00Raven DB presentation<p><a href="http://vimeo.com/36683956">This presentation</a> is an introduction to document database Raven DB. I’m very sorry for the annoying noise :( (my phone was lying next to the microphone through the entire presentation). <a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15895">Code samples</a>.</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0tag:blogger.com,1999:blog-712077106443942647.post-73451227780225116612012-02-10T11:28:00.001-08:002012-02-10T11:28:52.401-08:00RIA Services (and Raven DB) presentation<p><a href="http://vimeo.com/36541182">This presentation</a> is an introduction to RIA Services framework. Most tutorials show how to integrate RIA Services with relational database using DAL frameworks such as LINQ to SQL, LINQ to Entities or NHibernate. This presentation shows how to integrate RIA Services with document database Raven DB. Source code and slides can be found <a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15895">here</a>.</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0tag:blogger.com,1999:blog-712077106443942647.post-65165457038034211032011-12-23T06:08:00.001-08:002011-12-23T06:08:39.740-08:00LINQ presentation<p>Today I gave my old (from 2009) presentation about the LINQ. The video can be found <a href="http://vimeo.com/34125399">here</a>, slides and all code samples presented during this talk can be downloaded from <a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15857">here</a>. I hope you find it useful.</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com1tag:blogger.com,1999:blog-712077106443942647.post-18458681551856808132011-09-20T02:14:00.001-07:002011-09-20T02:14:39.271-07:00When the Reactive Framework meets F# 3.0<p>Few days ago I have been writing about <a href="http://mnajder.blogspot.com/2011/09/programming-with-c-asynchronous.html">asynchronous sequences</a> in C#. This time we will see how easy it is to implement the same web crawler using Reactive Framework and a new F# 3.0 feature called <a href="http://msdn.microsoft.com/en-us/library/hh225374%28v=vs.110%29.aspx">Query Expressions</a>. The original implementation of web crawler created by Tomas Petricek can be found <a href="http://www.fssnip.net/7f">here</a> and my implementation is surprisingly similar:</p> <div id="codeSnippetWrapper"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">let rec randomCrawl url = <br /> let visited = <span style="color: #0000ff">new</span> System.Collections.Generic.HashSet<_>()<br /> <br /> let rec loop url = obs {<br /> <span style="color: #0000ff">if</span> visited.Add(url) then<br /> let! doc = (downloadDocument url) |> fromAsync<br /> match doc with <br /> | Some doc -><br /> <span style="color: #0000ff">yield</span> url, getTitle doc<br /> <span style="color: #0000ff">for</span> link <span style="color: #0000ff">in</span> extractLinks doc <span style="color: #0000ff">do</span><br /> <span style="color: #0000ff">yield</span>! loop link <br /> | _ -> () }<br /> loop url<br /><br />rxquery {<br /> <span style="color: #0000ff">for</span> (url, title) <span style="color: #0000ff">in</span> randomCrawl <span style="color: #006080">"http://news.bing.com"</span> <span style="color: #0000ff">do</span><br /> <span style="color: #0000ff">where</span> (url.Contains(<span style="color: #006080">"bing.com"</span>) |> not)<br /> select title<br /> take 10 into gr<br /> iter (printfn <span style="color: #006080">"%s"</span> gr)<br /> }<br />|> ObservableExtensions.Subscribe |> ignore</pre>
<br /></div>
<p>There are two interesting things inside the code above. The first one is “obs { … } ” code construction. This is custom implementation of <a href="http://msdn.microsoft.com/en-us/library/dd233182.aspx">Computation Expression</a> builder. obs is just a normal variable of a type that contains a special set of methods like: Bind, Delay, For, Combine, … and so on. The F# compiler translates the code inside the curly brackets into code calling those methods. In my case the whole expression returns the implementation of IObservable<T> type. This allows us to write imperative code representing observable source where each “yield” call returns next value (OnNext of subscribed observer is being called) and the “let!” keyword causes the program to wait for the values from the other observable source (let! keyword works like await keyword in C#). See the implementation of the builder class below:</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">type ObsBuiler() = <br /> member <span style="color: #0000ff">this</span>.Zero () = Observable.Empty(Scheduler.CurrentThread)<br /> member <span style="color: #0000ff">this</span>.Yield v = Observable.Return(v, Scheduler.CurrentThread) <br /> member <span style="color: #0000ff">this</span>.Delay (f: _ -> IObservable<_>) = Observable.Defer(fun _ -> f())<br /> member <span style="color: #0000ff">this</span>.Combine (o1,o2) = Observable.Concat(o1,o2)<br /> member <span style="color: #0000ff">this</span>.For (s:seq<_>, body : _ -> IObservable<_>) = Observable.Concat(s.Select(body))<br /> member <span style="color: #0000ff">this</span>.YieldFrom a : IObservable<_> = a<br /> member <span style="color: #0000ff">this</span>.Bind ((o : IObservable<_>),(f : _ -> IObservable<_>)) = o.SelectMany(f) <br /> member <span style="color: #0000ff">this</span>.TryFinally((o : IObservable<_>),f : unit -> unit ) = Observable.Finally(o,fun _ -> f())<br /> member <span style="color: #0000ff">this</span>.TryWith((o : IObservable<_>),f : Exception -> IObservable<_> ) = Observable.Catch(o,fun ex -> f(ex))<br /> member <span style="color: #0000ff">this</span>.While (p,body) = Observable.While((fun () -> p()), body)<br /> member <span style="color: #0000ff">this</span>.Using (dis,body) = Observable.Using( (fun () -> dis), fun d -> body(d))<br /><br />let obs = <span style="color: #0000ff">new</span> ObsBuiler()</pre>
<br /></div>
<p>The second interesting part is “rxquery { … }” code construction. This time we are using a feature called <a href="http://msdn.microsoft.com/en-us/library/hh225374%28v=vs.110%29.aspx">Query Expressions</a> introduced in F# 3.0 which was released few day ago during <a href="http://www.buildwindows.com/">Build</a> conference together with Visual Studio 11 and Windows 8. We can write queries very similar to LINQ queries and the F# compiler translate them into code calling methods like: where, select, groupBy, take and on so on. So it works like LINQ queries in C# but here we can extend the set of available methods arbitrarily !!! Look at Zip and ForkJoin methods below which are not available by default with <a href="http://msdn.microsoft.com/en-us/library/hh323943%28v=VS.110%29.aspx">QueryBuilder</a> implementation working with IEnumerable<T> type. Let’s see the implementation of query builder class:</p>
<div>
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">type RxQueryBuiler() = <br /> member <span style="color: #0000ff">this</span>.For (s:IObservable<_>, body : _ -> IObservable<_>) = s.SelectMany(body)<br /> [<CustomOperation(<span style="color: #006080">"select"</span>, AllowIntoPattern=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.Select (s:IObservable<_>, [<ProjectionParameter>] selector : _ -> _) = s.Select(selector)<br /> [<CustomOperation(<span style="color: #006080">"where"</span>, MaintainsVariableSpace=<span style="color: #0000ff">true</span>, AllowIntoPattern=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.Where (s:IObservable<_>, [<ProjectionParameter>] predicate : _ -> <span style="color: #0000ff">bool</span> ) = s.Where(predicate)<br /> [<CustomOperation(<span style="color: #006080">"takeWhile"</span>, MaintainsVariableSpace=<span style="color: #0000ff">true</span>, AllowIntoPattern=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.TakeWhile (s:IObservable<_>, [<ProjectionParameter>] predicate : _ -> <span style="color: #0000ff">bool</span> ) = s.TakeWhile(predicate)<br /> [<CustomOperation(<span style="color: #006080">"take"</span>, MaintainsVariableSpace=<span style="color: #0000ff">true</span>, AllowIntoPattern=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.Take (s:IObservable<_>, count) = s.Take(count)<br /> [<CustomOperation(<span style="color: #006080">"skipWhile"</span>, MaintainsVariableSpace=<span style="color: #0000ff">true</span>, AllowIntoPattern=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.SkipWhile (s:IObservable<_>, [<ProjectionParameter>] predicate : _ -> <span style="color: #0000ff">bool</span> ) = s.SkipWhile(predicate)<br /> [<CustomOperation(<span style="color: #006080">"skip"</span>, MaintainsVariableSpace=<span style="color: #0000ff">true</span>, AllowIntoPattern=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.Skip (s:IObservable<_>, count) = s.Skip(count)<br /> member <span style="color: #0000ff">this</span>.Zero () = Observable.Empty(Scheduler.CurrentThread)<br /> member <span style="color: #0000ff">this</span>.Yield (<span style="color: #0000ff">value</span>) = Observable.Return(<span style="color: #0000ff">value</span>)<br /> [<CustomOperation(<span style="color: #006080">"count"</span>)>]<br /> member <span style="color: #0000ff">this</span>.Count (s:IObservable<_>) = Observable.Count(s)<br /> [<CustomOperation(<span style="color: #006080">"all"</span>)>]<br /> member <span style="color: #0000ff">this</span>.All (s:IObservable<_>, [<ProjectionParameter>] predicate : _ -> <span style="color: #0000ff">bool</span> ) = s.All(<span style="color: #0000ff">new</span> Func<_,<span style="color: #0000ff">bool</span>>(predicate))<br /> [<CustomOperation(<span style="color: #006080">"contains"</span>)>]<br /> member <span style="color: #0000ff">this</span>.Contains (s:IObservable<_>, key) = s.Contains(key)<br /> [<CustomOperation(<span style="color: #006080">"distinct"</span>, MaintainsVariableSpace=<span style="color: #0000ff">true</span>, AllowIntoPattern=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.Distinct (s:IObservable<_>) = s.Distinct()<br /> [<CustomOperation(<span style="color: #006080">"exactlyOne"</span>)>]<br /> member <span style="color: #0000ff">this</span>.ExactlyOne (s:IObservable<_>) = s.Single()<br /> [<CustomOperation(<span style="color: #006080">"exactlyOneOrDefault"</span>)>]<br /> member <span style="color: #0000ff">this</span>.ExactlyOneOrDefault (s:IObservable<_>) = s.SingleOrDefault()<br /> [<CustomOperation(<span style="color: #006080">"find"</span>)>]<br /> member <span style="color: #0000ff">this</span>.Find (s:IObservable<_>, [<ProjectionParameter>] predicate : _ -> <span style="color: #0000ff">bool</span>) = s.First(<span style="color: #0000ff">new</span> Func<_,<span style="color: #0000ff">bool</span>>(predicate))<br /> [<CustomOperation(<span style="color: #006080">"head"</span>)>]<br /> member <span style="color: #0000ff">this</span>.Head (s:IObservable<_>) = s.First()<br /> [<CustomOperation(<span style="color: #006080">"headOrDefault"</span>)>]<br /> member <span style="color: #0000ff">this</span>.HeadOrDefault (s:IObservable<_>) = s.FirstOrDefault()<br /> [<CustomOperation(<span style="color: #006080">"last"</span>)>]<br /> member <span style="color: #0000ff">this</span>.Last (s:IObservable<_>) = s.Last()<br /> [<CustomOperation(<span style="color: #006080">"lastOrDefault"</span>)>]<br /> member <span style="color: #0000ff">this</span>.LastOrDefault (s:IObservable<_>) = s.LastOrDefault()<br /> [<CustomOperation(<span style="color: #006080">"maxBy"</span>)>]<br /> member <span style="color: #0000ff">this</span>.MaxBy (s:IObservable<<span style="color: #006080">'a>, [<ProjectionParameter>] valueSelector : '</span>a -> <span style="color: #006080">'b) = s.MaxBy(new Func<'</span>a,<span style="color: #006080">'b>(valueSelector))<br /> [<CustomOperation("minBy")>]<br /> member this.MinBy (s:IObservable<'</span>a>, [<ProjectionParameter>] valueSelector : <span style="color: #006080">'a -> '</span>b) = s.MinBy(<span style="color: #0000ff">new</span> Func<<span style="color: #006080">'a,'</span>b>(valueSelector))<br /> [<CustomOperation(<span style="color: #006080">"nth"</span>)>]<br /> member <span style="color: #0000ff">this</span>.Nth (s:IObservable<'a>, index ) = s.ElementAt(index)<br /> [<CustomOperation(<span style="color: #006080">"sumBy"</span>)>]<br /> member inline <span style="color: #0000ff">this</span>.SumBy (s:IObservable<_>,[<ProjectionParameter>] valueSelector : _ -> _) = s.Select(valueSelector).Aggregate(Unchecked.defaultof<_>, <span style="color: #0000ff">new</span> Func<_,_,_>( fun a b -> a + b)) <br /> [<CustomOperation(<span style="color: #006080">"groupBy"</span>, AllowIntoPattern=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.GroupBy (s:IObservable<_>,[<ProjectionParameter>] keySelector : _ -> _) = s.GroupBy(<span style="color: #0000ff">new</span> Func<_,_>(keySelector))<br /> [<CustomOperation(<span style="color: #006080">"groupValBy"</span>, AllowIntoPattern=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.GroupValBy (s:IObservable<_>,[<ProjectionParameter>] resultSelector : _ -> _,[<ProjectionParameter>] keySelector : _ -> _) = s.GroupBy(<span style="color: #0000ff">new</span> Func<_,_>(keySelector),<span style="color: #0000ff">new</span> Func<_,_>(resultSelector))<br /> [<CustomOperation(<span style="color: #006080">"join"</span>, IsLikeJoin=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.Join (s1:IObservable<_>,s2:IObservable<_>, [<ProjectionParameter>] s1KeySelector : _ -> _,[<ProjectionParameter>] s2KeySelector : _ -> _,[<ProjectionParameter>] resultSelector : _ -> _) = s1.Join(s2,<span style="color: #0000ff">new</span> Func<_,_>(s1KeySelector),<span style="color: #0000ff">new</span> Func<_,_>(s2KeySelector),<span style="color: #0000ff">new</span> Func<_,_,_>(resultSelector))<br /> [<CustomOperation(<span style="color: #006080">"groupJoin"</span>, AllowIntoPattern=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.GroupJoin (s1:IObservable<_>,s2:IObservable<_>, [<ProjectionParameter>] s1KeySelector : _ -> _,[<ProjectionParameter>] s2KeySelector : _ -> _,[<ProjectionParameter>] resultSelector : _ -> _) = s1.GroupJoin(s2,<span style="color: #0000ff">new</span> Func<_,_>(s1KeySelector),<span style="color: #0000ff">new</span> Func<_,_>(s2KeySelector),<span style="color: #0000ff">new</span> Func<_,_,_>(resultSelector))<br /> [<CustomOperation(<span style="color: #006080">"zip"</span>, IsLikeZip=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.Zip (s1:IObservable<_>,s2:IObservable<_>,[<ProjectionParameter>] resultSelector : _ -> _) = s1.Zip(s2,<span style="color: #0000ff">new</span> Func<_,_,_>(resultSelector))<br /> [<CustomOperation(<span style="color: #006080">"forkJoin"</span>, IsLikeZip=<span style="color: #0000ff">true</span>)>]<br /> member <span style="color: #0000ff">this</span>.ForkJoin (s1:IObservable<_>,s2:IObservable<_>,[<ProjectionParameter>] resultSelector : _ -> _) = s1.ForkJoin(s2,<span style="color: #0000ff">new</span> Func<_,_,_>(resultSelector))<br /> [<CustomOperation(<span style="color: #006080">"iter"</span>)>]<br /> member <span style="color: #0000ff">this</span>.Iter(s:IObservable<_>, [<ProjectionParameter>] selector : _ -> _) = s.Do(selector)<br /><br />let rxquery = <span style="color: #0000ff">new</span> RxQueryBuiler()</pre>
</div>
<div> </div>
<div><a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15682">download</a></div> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com2tag:blogger.com,1999:blog-712077106443942647.post-27496806691569094222011-09-15T03:02:00.001-07:002011-09-15T03:23:05.205-07:00Design-time support for Caliburn.Micro<p>Recently me together with <a href="http://bpampuch.blogspot.com/">Bartek Pampuch</a> have been wondering if it’s possible to fire Caliburn.Micro’s binding process at design-time. Caliburn.Micro is a really great framework (just <a href="http://www.youtube.com/watch?v=r8LMpNGAZw4">take a look</a> at some of our multitouch apps based on this framework and <a href="http://www.codeproject.com/KB/library/BFsharp.aspx">BFSharp</a>). You just name the controls appropriately and all magic happens automatically. Controls are bound to the View Model’s properties and methods for you. The problem is that it is all happing at run time not at design time. When you are preparing the form in the Visual Studio or Expression Blend you aren’t able to see how the form will look like with bound data. In some cases such feature would very useful, especially when we want to use the sample data generated by Expression Blend or Visual Studio designers. In this post we will show you how to run Caliburn.Micro’s conventions based binding mechanism at design time.</p> <p>Firstly, we discovered that we can change the objects tree representing the screen and that change is not persisted back to xaml file. You can read more about this feature in my <a href="http://mnajder.blogspot.com/2011/09/custom-design-time-attributes-in.html">previous post</a>. Secondly, we tried to run Caliburn.Micro’s binding process to see what happens. What was really amazing is that after first try all just started working smoothly! The framework itself is implemented so well :) </p> <p>One of the samples provided with Caliburn.Micro release is a very simple application called GameLibrary. AddGameView.xaml file defines the screen that looks like this:</p> <p><a href="http://lh4.ggpht.com/-hiamy-3Pi_M/TnHM9kpEvjI/AAAAAAAAAV4/hQXb5tK7VuA/s1600-h/image81.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/--ggGOmtJUWA/TnHM_W_cSgI/AAAAAAAAAV8/6uHKnqz6YfE/image_thumb4.png?imgmax=800" width="883" height="360" /></a></p> <p>After setting up sample data generated by Visual Studio and setting attached property 'DesignTime.Enable=”True” the same form looks like this:</p> <p><a href="http://lh6.ggpht.com/-2Ch9Gma3CM0/TnHM_5OxFgI/AAAAAAAAAWA/ule2ZzRrJaQ/s1600-h/clip_image0016.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="clip_image001" border="0" alt="clip_image001" src="http://lh3.ggpht.com/-HKcjwS6aAYY/TnHNAnMrbgI/AAAAAAAAAWE/5gAt5BhUCAg/clip_image001_thumb3.png?imgmax=800" width="894" height="474" /></a></p> <p>In the simplest scenario all we need to run Caliburn.Micro binding process at design time is setting design time data context and enabling binding via Enable attached property. In sample above we are setting sample data generated by Visual Studio because the AddGameViewModel class doesn’t provide default constructor. Of course we could always add a default constructor in code and define view model instance in xaml file.</p> <p>I chose this particular form intentionally because it contains the control that hasn’t defined custom binding convention by default. The Rating control is responsible for displaying Rating property value using stars. Rating property value is 0.8 so 4 stars should be displayed. In such cases where we are using controls with custom binding convention we need to register those conventions at design time. Any application using Caliburn.Micro has a type inherited from Bootstrapper type. This type is a starting point of our application and the instance of that type very often is defined as a resource inside App.xaml file. In fact Caliburn.Micro framework is already prepared for design time scenarios because Bootstrapper type contains virtual method called StartDesignTime. Let’s override this method and register appropriate convention:</p> <div id="codeSnippetWrapper"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Bootstrapper<br />{<br /> <span style="color: #0000ff">public</span> Bootstrapper() <br /> {<br /> <span style="color: #0000ff">if</span> (Execute.InDesignMode) StartDesignTime(); <span style="color: #0000ff">else</span> StartRuntime();<br /> }<br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Bootstrapper<TRootModel> : Bootstrapper <br />{ <br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> AppBootstrapper : Bootstrapper<IShell> <br />{<br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">bool</span> isInitializedInDesignTime = <span style="color: #0000ff">false</span>;<br /><br /> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> StartDesignTime()<br /> {<br /> <span style="color: #0000ff">base</span>.StartDesignTime();<br /><br /> <span style="color: #0000ff">if</span> (isInitializedInDesignTime)<br /> <span style="color: #0000ff">return</span>;<br /> isInitializedInDesignTime = <span style="color: #0000ff">true</span>;<br /> <br /> ConfigureConventions();<br /> }<br /><br /><br /> <span style="color: #0000ff">void</span> ConfigureConventions()<br /> {<br /> ConventionManager.AddElementConvention<Rating>(Rating.ValueProperty, <span style="color: #006080">"Value"</span>, <span style="color: #006080">"ValueChanged"</span>);<br /> }<br />}</pre>
<br /></div>
<p>The instance of AppBootstapper type can be created many times at design time so boolean flag ensures that the conventions will be registered only once. When we compile the project and reopen the form we will see something like this:</p>
<p><a href="http://lh4.ggpht.com/-9AxE0cAVOJk/TnHND9Bf5BI/AAAAAAAAAWI/IU82PjMZXJQ/s1600-h/image3.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-_1DAQZzXJMg/TnHNE9Aj1DI/AAAAAAAAAWM/Ffh2t90_1Rw/image_thumb1.png?imgmax=800" width="254" height="199" /></a></p>
<p>This form represents a very simple scenario where the view model type has only properties of simple types like: string, double. boolean. It doesn’t contain any property of collection type or other view model type. In such scenarios Caliburn.Micro can find the appropriate type of view (control type) based on the type of view model. Let’s see another form called ResultsView.xaml to demonstrate this case:</p>
<p><a href="http://lh6.ggpht.com/-bw7wlB75d0Y/TnHNFcoPtAI/AAAAAAAAAWQ/5AWxMKUaQK4/s1600-h/image11.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/-L8NsJ0ChQEQ/TnHNGfFMPGI/AAAAAAAAAWU/U-wG6nwSHXs/image_thumb5.png?imgmax=800" width="893" height="326" /></a></p>
<p>This is a typical problem when we work with Caliburn.Micro and we cannot see anything at design time because the control is entirely collapsed :). Let’s see what happen after connecting sample data.</p>
<p><a href="http://lh3.ggpht.com/-ziCou0GZMcE/TnHNHUD0ZnI/AAAAAAAAAWY/ey3WI-f_TyI/s1600-h/image17.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-TP7lk0Gocao/TnHNHwGf9dI/AAAAAAAAAWc/BwH0KiO6WPc/image_thumb9.png?imgmax=800" width="891" height="482" /></a></p>
<p>The list contains some elements but the font color is white so we aren’t able to read it because of the default Visual Studio background color. We can try to open this form inside Expression Blend where the background is dark or we can use custom design time attributes presented <u>in the previous post</u>.</p>
<p><a href="http://lh5.ggpht.com/-6UgVLDqipD8/TnHNIx6EvbI/AAAAAAAAAWg/Q9dr1KzjasI/s1600-h/image22.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-thXtfYmP-JQ/TnHNKhP9EGI/AAAAAAAAAWk/7fsdfseCpIU/image_thumb12.png?imgmax=800" width="890" height="478" /></a></p>
<p>Now we can see that Caliburn.Micro is not able to find view for view model type representing list item. It’s because we are using sample data mechanism from Visual Studio which generates dynamic type _.di0.GameLibrary.ViewModels.IndividualResultViewModel with the shape of the original view model type GameLibrary.ViewModels.IndividualResultViewModel. We need to change the way Caliburn.Micro is searching for view type based on specified view model type.</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> StartDesignTime()<br />{<br /> <span style="color: #0000ff">base</span>.StartDesignTime();<br /><br /> <span style="color: #0000ff">if</span> (isInitializedInDesignTime)<br /> <span style="color: #0000ff">return</span>;<br /> isInitializedInDesignTime = <span style="color: #0000ff">true</span>;<br /><br /> ConfigureConventions();<br /> <br /> AssemblySource.Instance.AddRange(<span style="color: #0000ff">new</span>[] { <span style="color: #0000ff">typeof</span>(App).Assembly });<br /><br /> var originalLocateTypeForModelType = ViewLocator.LocateTypeForModelType;<br /> Func<Type, <span style="color: #0000ff">bool</span>> isDesignTimeType = type => type.Assembly.IsDynamic;<br /> ViewLocator.LocateTypeForModelType = (modelType, displayLocation, context) =><br /> {<br /> var type = originalLocateTypeForModelType(modelType, displayLocation, context);<br /> <span style="color: #0000ff">if</span> (type == <span style="color: #0000ff">null</span> && isDesignTimeType(modelType))<br /> {<br /> <span style="color: #0000ff">if</span> (modelType.Name == <span style="color: #006080">"IndividualResultViewModel"</span>)<br /> {<br /> type = <span style="color: #0000ff">typeof</span>(IndividualResultView);<br /> }<br /> }<br /> <span style="color: #0000ff">return</span> type;<br /> };<br /><br /> IoC.GetInstance = <span style="color: #0000ff">base</span>.GetInstance;<br /> IoC.GetAllInstances = <span style="color: #0000ff">base</span>.GetAllInstances;<br />}</pre>
<br /></div>
<p>Finally the list of items and generated sample data look like this:</p>
<p><a href="http://lh3.ggpht.com/-hyh1LRQrJcA/TnHNLfcM5DI/AAAAAAAAAWo/0OLVR9H0aFI/s1600-h/image35.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/-XZzwX8StSTo/TnHNMvGHHlI/AAAAAAAAAWs/qXBYmbAGbWo/image_thumb18.png?imgmax=800" width="862" height="598" /></a></p>
<p>Attached property is not the most convenient way of extending the designer functionality because we need to write xaml code. I tried to rewrite attached property to custom behavior so we could use dra&drop instead of writing the code. The problem is that behaviors code is not executed at design time. But I have good news. If you are creating UI with Expression Blend you can use our attached property on the property grid like a normal property. </p>
<p><a href="http://lh4.ggpht.com/-Gd0O9jaQamo/TnHNNGniqhI/AAAAAAAAAWw/31aFLNV6iLQ/s1600-h/image39.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/-_h5oGT46tMo/TnHNOCFTYhI/AAAAAAAAAW0/lr3iYed53kM/image_thumb20.png?imgmax=800" width="348" height="182" /></a></p>
<p>It was possible thanks to the usage of attribute called AttachedPropertyBrowsableForTypeAttribute decorating attached property. Everything that was presented so far works both in Silverlight and WPF environments. It’s time to reveal how the magic works.</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> DesignTime<br /> {<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> DependencyProperty EnableProperty =<br /> DependencyProperty.RegisterAttached(<br /> <span style="color: #006080">"Enable"</span>,<br /> <span style="color: #0000ff">typeof</span>(<span style="color: #0000ff">bool</span>),<br /> <span style="color: #0000ff">typeof</span>(DesignTime),<br /> <span style="color: #0000ff">new</span> PropertyMetadata(<span style="color: #0000ff">new</span> PropertyChangedCallback(EnableChanged)));<br /><br /><span style="color: #cc6633">#if</span> !SILVERLIGHT && !WP7<br /> [AttachedPropertyBrowsableForTypeAttribute(<span style="color: #0000ff">typeof</span>(DependencyObject))]<br /><span style="color: #cc6633">#endif</span><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">bool</span> GetEnable(DependencyObject dependencyObject)<br /> {<br /> <span style="color: #0000ff">return</span> (<span style="color: #0000ff">bool</span>)dependencyObject.GetValue(EnableProperty);<br /> }<br /><br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> SetEnable(DependencyObject dependencyObject, <span style="color: #0000ff">bool</span> <span style="color: #0000ff">value</span>)<br /> {<br /> dependencyObject.SetValue(EnableProperty, <span style="color: #0000ff">value</span>);<br /> }<br /><br /> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> EnableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)<br /> {<br /> <span style="color: #0000ff">if</span> (!Execute.InDesignMode)<br /> <span style="color: #0000ff">return</span>;<br /><br /> BindingOperations.SetBinding(d, DataContextProperty, (<span style="color: #0000ff">bool</span>)e.NewValue ? <span style="color: #0000ff">new</span> Binding() : <span style="color: #0000ff">null</span>);<br /> }<br /><br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">readonly</span> DependencyProperty DataContextProperty =<br /> DependencyProperty.RegisterAttached(<br /> <span style="color: #006080">"DataContext"</span>,<br /> <span style="color: #0000ff">typeof</span>(<span style="color: #0000ff">object</span>),<br /> <span style="color: #0000ff">typeof</span>(DesignTime),<br /> <span style="color: #0000ff">new</span> PropertyMetadata(<span style="color: #0000ff">new</span> PropertyChangedCallback(DataContextChanged))<br /> );<br /><br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> DataContextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)<br /> {<br /> <span style="color: #0000ff">if</span> (!Execute.InDesignMode)<br /> <span style="color: #0000ff">return</span>;<br /><br /> <span style="color: #0000ff">object</span> enable = d.GetValue(EnableProperty);<br /> <span style="color: #0000ff">if</span> (enable == <span style="color: #0000ff">null</span> || ((<span style="color: #0000ff">bool</span>)enable) == <span style="color: #0000ff">false</span> || e.NewValue == <span style="color: #0000ff">null</span>)<br /> <span style="color: #0000ff">return</span>;<br /><br /> var fe = d <span style="color: #0000ff">as</span> FrameworkElement;<br /> <span style="color: #0000ff">if</span> (fe == <span style="color: #0000ff">null</span>)<br /> <span style="color: #0000ff">return</span>;<br /> <br /> ViewModelBinder.Bind(e.NewValue, d, <span style="color: #0000ff">string</span>.IsNullOrEmpty(fe.Name) ? fe.GetHashCode().ToString() : fe.Name);<br /> }<br /> }</pre>
<br /></div>
<p>I hope you find this solution useful.</p>
<p><a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15650">Download</a></p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com6tag:blogger.com,1999:blog-712077106443942647.post-34464316480188095362011-09-15T02:59:00.001-07:002011-09-15T02:59:14.162-07:00Custom design-time attributes in Silverlight and WPF designer<p>We all know the standard <a href="http://msdn.microsoft.com/en-us/library/ff602277%28v=vs.95%29.aspx">design-time attributes in the Silverlight</a> designer like d:DataContext, d:DesignWidth or d:DesignHeight. Let’s see how easy we can add some new attributes.</p> <pre class="csharpcode"><a href="http://lh6.ggpht.com/-GX4jxFtigCo/TnHMaiI-O-I/AAAAAAAAAVw/cY-4ev5BYrU/s1600-h/image6.png"><img style="background-image: none; border-right-width: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px; padding-top: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/-tNMvuELzBrs/TnHMcKk-llI/AAAAAAAAAV0/X5ZibMZ7t8o/image_thumb4.png?imgmax=800" width="702" height="446" /></a></pre>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">using</span> System.ComponentModel;<br /><span style="color: #0000ff">using</span> System.Windows;<br /><br /><span style="color: #0000ff">namespace</span> DesignTimeProperties<br />{<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> d<br /> {<br /> <span style="color: #0000ff">static</span> <span style="color: #0000ff">bool</span>? inDesignMode;<br /><br /> <span style="color: #008000">/// <summary></span><br /> <span style="color: #008000">/// Indicates whether or not the framework is in design-time mode. (Caliburn.Micro implementation)</span><br /> <span style="color: #008000">/// </summary></span><br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">bool</span> InDesignMode<br /> {<br /> get<br /> {<br /> <span style="color: #0000ff">if</span> (inDesignMode == <span style="color: #0000ff">null</span>)<br /> {<br /> var prop = DesignerProperties.IsInDesignModeProperty;<br /> inDesignMode = (<span style="color: #0000ff">bool</span>)DependencyPropertyDescriptor.FromProperty(prop, <span style="color: #0000ff">typeof</span>(FrameworkElement)).Metadata.DefaultValue;<br /><br /> <span style="color: #0000ff">if</span> (!inDesignMode.GetValueOrDefault(<span style="color: #0000ff">false</span>) && System.Diagnostics.Process.GetCurrentProcess()<br /> .ProcessName.StartsWith(<span style="color: #006080">"devenv"</span>, System.StringComparison.Ordinal))<br /> inDesignMode = <span style="color: #0000ff">true</span>;<br /> }<br /><br /> <span style="color: #0000ff">return</span> inDesignMode.GetValueOrDefault(<span style="color: #0000ff">false</span>);<br /> }<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> DependencyProperty BackgroundProperty = DependencyProperty.RegisterAttached(<br /> <span style="color: #006080">"Background"</span>, <span style="color: #0000ff">typeof</span>(System.Windows.Media.Brush), <span style="color: #0000ff">typeof</span>(d),<br /> <span style="color: #0000ff">new</span> PropertyMetadata(<span style="color: #0000ff">new</span> PropertyChangedCallback(BackgroundChanged)));<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> System.Windows.Media.Brush GetBackground(DependencyObject dependencyObject)<br /> {<br /> <span style="color: #0000ff">return</span> (System.Windows.Media.Brush)dependencyObject.GetValue(BackgroundProperty);<br /> }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> SetBackground(DependencyObject dependencyObject, System.Windows.Media.Brush <span style="color: #0000ff">value</span>)<br /> {<br /> dependencyObject.SetValue(BackgroundProperty, <span style="color: #0000ff">value</span>);<br /> }<br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> BackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)<br /> {<br /> <span style="color: #0000ff">if</span> (!InDesignMode)<br /> <span style="color: #0000ff">return</span>;<br /><br /> d.GetType().GetProperty(<span style="color: #006080">"Background"</span>).SetValue(d, e.NewValue, <span style="color: #0000ff">null</span>);<br /> }<br /> }<br />}</pre>
<br /></div>
<style type="text/css">
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }</style>
<p>Great, but what about many others very useful properties ? Do we need to write them all manually? No, we don’t. I have prepared T4 template that generates code for all properties of all controls available in WPF and Silverlight assemblies. When you look carefully at the code above you will find that I am using the reflection to set the value of the property. It’s because some properties like Background are defined many times in many different controls so instead of checking the actual control type I assume that the control contains appropriate property. This assumption simplifies the implementation very much. And of course the property can be set only in design time when we are editing the form inside Expression Blend or Visual Studio. T4 template code analyzes all properties from all controls and properties with the same names but different types are skipped during generation process. </p>
<p><a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15650">Download</a></p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0tag:blogger.com,1999:blog-712077106443942647.post-81855538950067186162011-09-04T22:46:00.001-07:002011-09-08T09:53:08.942-07:00Programming with C# asynchronous sequences<p>Tomas Petricek in his last <a href="http://tomasp.net/blog/async-sequences.aspx">blog post</a> titled “Programming with F# asynchronous sequences” presents F# implementation of something called asynchronous sequences. In this post I will show you how the same concept can be implemented in C#. Let’s look at the sample code below to better understand what the asynchronous sequence is:</p> <div id="codeSnippetWrapper"> <pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">IEnumerable<...> AsyncSeq()<br />{<br /> <span style="color: #0000ff">yield</span> <span style="color: #0000ff">return</span> <span style="color: #006080">"Hello"</span>;<br /> await TaskEx.Delay(100);<br /> <span style="color: #0000ff">yield</span> <span style="color: #0000ff">return</span> <span style="color: #006080">"world!"</span>;<br />}</pre>
<br /></div>
<p>Asynchronous sequences is a code that produces the sequence of values generated on demand (this is how the IEnumerable interface can be interpreted) but additionally does some asynchronous work during the evaluation process (await keyword). Every time the client of asynchronous sequence calls MoveNext method, next value is being evaluated. The key feature here is that the client decides when to produce next value and when to stop the processing.</p>
<p>There are two problems with such an implementation of asynchronous sequence. Sequences in .Net world are represented with IEnumerable interface, but the interface allows only synchronous processing. Since the MoveNext method returns bool value in the interface implementation, we need to immediately decide whether the next value can be produced or not. In the asynchronous processing it can take a few minutes or even hours to provide such information. The second problem is that so far we cannot mix together await keyword (Async Ctp) with yield return/yield break keywords inside the same method body. My solution resolves those two problems and the above sequence can be implemented the fallowing way:</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">IEnumerable<AsyncSeqItem<<span style="color: #0000ff">string</span>>> AsyncSeq()<br />{<br /> <span style="color: #0000ff">yield</span> <span style="color: #0000ff">return</span> <span style="color: #006080">"Hello"</span>;<br /> <span style="color: #0000ff">yield</span> <span style="color: #0000ff">return</span> TaskEx.Delay(100);<br /> <span style="color: #0000ff">yield</span> <span style="color: #0000ff">return</span> <span style="color: #006080">"world!"</span>;<br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">enum</span> AsyncSeqItemMode<br />{<br /> Value, Task, Sequence<br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> AsyncSeqItem<T><br />{<br /> <span style="color: #0000ff">public</span> AsyncSeqItemMode Mode { get; <span style="color: #0000ff">private</span> set; }<br /> <span style="color: #0000ff">public</span> T Value { get; <span style="color: #0000ff">private</span> set; }<br /> <span style="color: #0000ff">public</span> Task Task { get; <span style="color: #0000ff">private</span> set; }<br /> <span style="color: #0000ff">public</span> IEnumerable<AsyncSeqItem<T>> Seq { get; <span style="color: #0000ff">private</span> set; }<br /><br /> <span style="color: #0000ff">public</span> AsyncSeqItem(T <span style="color: #0000ff">value</span>)<br /> {<br /> Value = <span style="color: #0000ff">value</span>;<br /> Mode = AsyncSeqItemMode.Value;<br /> }<br /><br /> <span style="color: #0000ff">public</span> AsyncSeqItem(Task task)<br /> {<br /> Task = task;<br /> Mode = AsyncSeqItemMode.Task;<br /> }<br /><br /> <span style="color: #0000ff">public</span> AsyncSeqItem(IEnumerable<AsyncSeqItem<T>> seq)<br /> {<br /> Seq = seq;<br /> Mode = AsyncSeqItemMode.Sequence;<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">implicit</span> <span style="color: #0000ff">operator</span> AsyncSeqItem<T>(T <span style="color: #0000ff">value</span>)<br /> {<br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> AsyncSeqItem<T>(<span style="color: #0000ff">value</span>);<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">implicit</span> <span style="color: #0000ff">operator</span> AsyncSeqItem<T>(Task task)<br /> {<br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> AsyncSeqItem<T>(task);<br /> }<br />}</pre>
<br /></div>
<p>AsyncSeqItem represents one of three following values:</p>
<ul>
<li>Value – next value generated by the sequence</li>
<li>Task – some asynchronous work that needs to be awaited for before going forward</li>
<li>Sequence – it’s used with recursive calls and it means that we want to use tail recursion</li>
</ul>
<p>There are two ways of consuming such sequence in the client:</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> AsyncSeqExtensions<br />{<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IEnumerable<Task<Option<T>>> ToTaskEnumerable<T>(<span style="color: #0000ff">this</span> IEnumerable<AsyncSeqItem<T>> seq, <span style="color: #0000ff">bool</span> continueOnCapturedContext = <span style="color: #0000ff">true</span>)<br /> { ... } <br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IAsyncEnumerable<T> ToAsyncEnumerable<T>(<span style="color: #0000ff">this</span> IEnumerable<AsyncSeqItem<T>> seq, <span style="color: #0000ff">bool</span> continueOnCapturedContext = <span style="color: #0000ff">true</span>)<br /> { ... }<br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Option<T><br />{<br /> <span style="color: #0000ff">public</span> T Value { get; <span style="color: #0000ff">private</span> set; }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">bool</span> HasValue { get; <span style="color: #0000ff">private</span> set; }<br /><br /> <span style="color: #0000ff">public</span> Option()<br /> {<br /> HasValue = <span style="color: #0000ff">false</span>;<br /> }<br /><br /> <span style="color: #0000ff">public</span> Option(T <span style="color: #0000ff">value</span>)<br /> {<br /> Value = <span style="color: #0000ff">value</span>;<br /> HasValue = <span style="color: #0000ff">true</span>;<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">implicit</span> <span style="color: #0000ff">operator</span> Option<T>(T <span style="color: #0000ff">value</span>)<br /> {<br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Option<T>(<span style="color: #0000ff">value</span>);<br /> }<br />}</pre>
<br /></div>
<p>In the first approach we are calling ToAsyncEnumerable extension method returning the sequence of tasks. Each task wraps special type called Option<T> which can be used similarly to Nullable<T> type except that it works with value and reference types. Returning task with option object without the value means that we reached the end of the sequence. I also provide few standard LINQ operators built on the top of such a sequence semantic:</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> AsyncSeqExtensions<br />{<br /> async <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> Task ForEachTaskImpl<T>(<span style="color: #0000ff">this</span> IEnumerable<Task<Option<T>>> seq, Action<Task<Option<T>>> action)<br /> {<br /> <span style="color: #0000ff">foreach</span> (var task <span style="color: #0000ff">in</span> seq)<br /> { <br /> await task;<br /> action(task);<br /> }<br /> }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Task ForEachTask<T>(<span style="color: #0000ff">this</span> IEnumerable<Task<Option<T>>> seq, Action<Task<Option<T>>> action)<br /> {<br /> <span style="color: #0000ff">return</span> ForEachTaskImpl(seq, action);<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Task ForEach<T>(<span style="color: #0000ff">this</span> IEnumerable<Task<Option<T>>> seq, Action<T> action)<br /> {<br /> <span style="color: #0000ff">return</span> seq.ForEachTask(task =><br /> {<br /> <span style="color: #0000ff">if</span>(task.Result.HasValue) <br /> action(task.Result.Value);<br /> });<br /> }<br /><br /> async <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> Task<T[]> ToArrayImpl<T>(IEnumerable<Task<Option<T>>> seq)<br /> {<br /> var list = <span style="color: #0000ff">new</span> List<T>();<br /> await seq.ForEach(v => list.Add(v)); <br /> <span style="color: #0000ff">return</span> list.ToArray();<br /> }<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Task<T[]> ToArray<T>(<span style="color: #0000ff">this</span> IEnumerable<Task<Option<T>>> seq)<br /> {<br /> <span style="color: #0000ff">return</span> ToArrayImpl(seq);<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IEnumerable<Task<Option<TResult>>> Select<T, TResult>(<span style="color: #0000ff">this</span> IEnumerable<Task<Option<T>>> source,<br /> Func<T,TResult> selector) { ... }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IEnumerable<Task<Option<T>>> Where<T>(<span style="color: #0000ff">this</span> IEnumerable<Task<Option<T>>> source, <br /> Func<T, <span style="color: #0000ff">bool</span>> predicate) { ... }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IEnumerable<Task<Option<T>>> Take<T>(<span style="color: #0000ff">this</span> IEnumerable<Task<Option<T>>> source, <br /> <span style="color: #0000ff">int</span> count) { ... }<br /><br /> ...<br />}</pre>
<br /></div>
<p>Returning additional task object at the end of a sequence with special value allows us to use standard IEnumerable<T> interface but it’s a little bit inconvenient. In the second approach we use the IAsyncEnumerable interface from the <a href="http://blogs.msdn.com/b/rxteam/archive/2010/10/28/release-notes.aspx">Reactive Framework</a> library released some time ago.</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span> IAsyncEnumerable<<span style="color: #0000ff">out</span> T><br />{ <br /> IAsyncEnumerator<T> GetEnumerator();<br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span> IAsyncEnumerator<<span style="color: #0000ff">out</span> T> : IDisposable<br />{<br /> Task<<span style="color: #0000ff">bool</span>> MoveNext(); <br /> T Current { get; }<br />}<br /><br /><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> AsyncEnumerable<br />{<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IAsyncEnumerable<TResult> Select<TSource, TResult>(IAsyncEnumerable<TSource> source, <br /> Func<TSource, TResult> selector) { ... }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IAsyncEnumerable<TSource> Where<TSource>(IAsyncEnumerable<TSource> source, <br /> Func<TSource, <span style="color: #0000ff">bool</span>> predicate) { ... }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IAsyncEnumerable<TSource> Take<TSource>(IAsyncEnumerable<TSource> source, <br /> <span style="color: #0000ff">int</span> n) { ... }<br />}</pre>
<br /></div>
<p>This interface perfectly represents the semantic of asynchronous sequence. Rx library also provides many standard LINQ operations like: Where, Select, Take, Sum, First and so on. This allows us to write almost any LINQ query executing on the top of asynchronous sequence.</p>
<p>Now let’s summarize what we achieved so far. We can write imperative code implementing asynchronous sequence. We can use extension method to create one of two asynchronous sequence representations. Finally we can iterate through all items in such a sequence or we can build a new sequence object using LINQ operators.</p>
<p>The C# version of the web crawler presented in Tomas Petricek’s blog post could look like this:</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> AsyncSeqSample<br />{<br /> async <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Task CrawlBingUsingAsyncEnumerable()<br /> {<br /> await RandomCrawl(<span style="color: #006080">"http://news.bing.com"</span>) <br /> .ToAsyncEnumerable()<br /> .Where(t => !t.Item1.Contains(<span style="color: #006080">"bing.com"</span>))<br /> .Select(t => t.Item2)<br /> .Take(10)<br /> .ForEach(Console.WriteLine);<br /><br /> Console.WriteLine(<span style="color: #006080">"the end..."</span>);<br /> }<br /><br /> async <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Task CrawlBingUsingTaskEnumerable()<br /> {<br /> await RandomCrawl(<span style="color: #006080">"http://news.bing.com"</span>)<br /> .ToTaskEnumerable()<br /> .Where(t => !t.Item1.Contains(<span style="color: #006080">"bing.com"</span>))<br /> .Select(t => t.Item2)<br /> .Take(10)<br /> .ForEach(Console.WriteLine);<br /><br /> Console.WriteLine(<span style="color: #006080">"the end..."</span>);<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IEnumerable<AsyncSeqItem<Tuple<<span style="color: #0000ff">string</span>, <span style="color: #0000ff">string</span>>>> RandomCrawl(<span style="color: #0000ff">string</span> url)<br /> {<br /> <span style="color: #0000ff">return</span> RandomCrawlLoop(url, <span style="color: #0000ff">new</span> HashSet<<span style="color: #0000ff">string</span>>());<br /> }<br /><br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> IEnumerable<AsyncSeqItem<Tuple<<span style="color: #0000ff">string</span>,<span style="color: #0000ff">string</span>>>> RandomCrawlLoop(<span style="color: #0000ff">string</span> url, HashSet<<span style="color: #0000ff">string</span>> visited)<br /> {<br /> <span style="color: #0000ff">if</span> (visited.Add(url))<br /> {<br /> var downloadTask = DownloadDocument(url);<br /> <span style="color: #0000ff">yield</span> <span style="color: #0000ff">return</span> downloadTask;<br /> <span style="color: #0000ff">if</span> (downloadTask.Result.HasValue)<br /> {<br /> var doc = downloadTask.Result.Value;<br /> <span style="color: #0000ff">yield</span> <span style="color: #0000ff">return</span> Tuple.Create(url, GetTitle(doc));<br /> <span style="color: #0000ff">foreach</span> (var link <span style="color: #0000ff">in</span> ExtractLinks(doc))<br /> {<br /> <span style="color: #0000ff">foreach</span> (var l <span style="color: #0000ff">in</span> RandomCrawlLoop(link, visited))<br /> {<br /> <span style="color: #0000ff">yield</span> <span style="color: #0000ff">return</span> l;<br /> }<br /> }<br /> }<br /> }<br /> }<br /><br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">string</span>[] ExtractLinks(HtmlDocument doc)<br /> {<br /> <span style="color: #0000ff">try</span><br /> {<br /> var q = from a <span style="color: #0000ff">in</span> doc.DocumentNode.SelectNodes(<span style="color: #006080">"//a"</span>)<br /> <span style="color: #0000ff">where</span> a.Attributes.Contains(<span style="color: #006080">"href"</span>)<br /> let href = a.Attributes[<span style="color: #006080">"href"</span>].Value<br /> <span style="color: #0000ff">where</span> href.StartsWith(<span style="color: #006080">"http://"</span>)<br /> let endl = href.IndexOf(<span style="color: #006080">'?'</span>)<br /> select endl > 0 ? href.Substring(0, endl) : href;<br /><br /> <span style="color: #0000ff">return</span> q.ToArray();<br /> }<br /> <span style="color: #0000ff">catch</span><br /> {<br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> <span style="color: #0000ff">string</span>[0];<br /> }<br /> }<br /><br /> async <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> Task<Option<HtmlDocument>> DownloadDocument(<span style="color: #0000ff">string</span> url)<br /> {<br /> <span style="color: #0000ff">try</span><br /> {<br /> var client = <span style="color: #0000ff">new</span> WebClient();<br /> var html = await client.DownloadStringTaskAsync(url);<br /> var doc = <span style="color: #0000ff">new</span> HtmlDocument();<br /> doc.LoadHtml(html);<br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Option<HtmlDocument>(doc);<br /> }<br /> <span style="color: #0000ff">catch</span> (Exception)<br /> {<br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Option<HtmlDocument>();<br /> }<br /> }<br /><br /> <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">string</span> GetTitle(HtmlDocument doc)<br /> {<br /> var title = doc.DocumentNode.SelectSingleNode(<span style="color: #006080">"//title"</span>);<br /> <span style="color: #0000ff">return</span> title != <span style="color: #0000ff">null</span> ? title.InnerText.Trim() : <span style="color: #006080">"Untitled"</span>;<br /> }<br />}</pre>
<br /></div>
<p>Now let’s see how ToAsyncEnumerable and ToTaskEnumerable methods have been implemented:</p>
<div id="codeSnippetWrapper">
<pre style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> AsyncSeqExtensions<br />{<br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IAsyncEnumerable<T> ToAsyncEnumerable<T>(<span style="color: #0000ff">this</span> IEnumerable<AsyncSeqItem<T>> seq, <span style="color: #0000ff">bool</span> continueOnCapturedContext = <span style="color: #0000ff">true</span>)<br /> {<br /> <span style="color: #0000ff">if</span> (seq == <span style="color: #0000ff">null</span>) <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> ArgumentNullException(<span style="color: #006080">"seq"</span>);<br /><br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> AnonymousAsyncEnumerable<T>(() =><br /> {<br /> var enumerator = seq.ToTaskEnumerable(continueOnCapturedContext).GetEnumerator();<br /> seq = <span style="color: #0000ff">null</span>; <span style="color: #008000">// holding reference to seq parameter introduces memory leaks when asynchronous sequence uses recursive calls</span><br /> TaskCompletionSource<<span style="color: #0000ff">bool</span>> currentTcs = <span style="color: #0000ff">null</span>;<br /> Task<Option<T>> currentTask = <span style="color: #0000ff">null</span>;<br /><br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> AnonymousAsyncEnumerator<T>(<br /> () =><br /> {<br /> currentTcs = <span style="color: #0000ff">new</span> TaskCompletionSource<<span style="color: #0000ff">bool</span>>();<br /><br /> <span style="color: #0000ff">if</span> (CheckEndOfSeq(currentTask) == <span style="color: #0000ff">false</span>)<br /> {<br /> currentTcs.SetResult(<span style="color: #0000ff">false</span>);<br /> <span style="color: #0000ff">return</span> currentTcs.Task;<br /> }<br /><br /> enumerator.MoveNext();<br /> <br /> enumerator.Current.ContinueWith(t =><br /> {<br /> <span style="color: #0000ff">if</span> (t.IsFaulted)<br /> {<br /> currentTcs.SetException(t.Exception);<br /> }<br /> <span style="color: #0000ff">else</span><br /> {<br /> <span style="color: #0000ff">if</span> (!t.Result.HasValue)<br /> {<br /> currentTcs.SetResult(<span style="color: #0000ff">false</span>);<br /> }<br /> <span style="color: #0000ff">else</span><br /> {<br /> currentTask = t;<br /> currentTcs.SetResult(<span style="color: #0000ff">true</span>);<br /> }<br /> }<br /> });<br /><br /> <span style="color: #0000ff">return</span> currentTcs.Task;<br /> },<br /> () => currentTask.Result.Value<br /> );<br /> });<br /> }<br /><br /> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IEnumerable<Task<Option<T>>> ToTaskEnumerable<T>(<span style="color: #0000ff">this</span> IEnumerable<AsyncSeqItem<T>> seq, <span style="color: #0000ff">bool</span> continueOnCapturedContext = <span style="color: #0000ff">true</span>)<br /> {<br /> <span style="color: #0000ff">if</span> (seq == <span style="color: #0000ff">null</span>) <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> ArgumentNullException(<span style="color: #006080">"seq"</span>);<br /> <br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> AnonymousEnumerable<Task<Option<T>>>(() =><br /> {<br /> var synchronizationContext = continueOnCapturedContext ? SynchronizationContext.Current : <span style="color: #0000ff">null</span>;<br /><br /> var enumerator = seq.GetEnumerator();<br /> seq = <span style="color: #0000ff">null</span>; <span style="color: #008000">// holding reference to seq parameter introduces memory leaks when asynchronous sequence uses recursive calls</span><br /><br /> TaskCompletionSource<Option<T>> currentTcs = <span style="color: #0000ff">null</span>;<br /><br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> AnonymousEnumerator<Task<Option<T>>>(<br /> () =><br /> {<br /> <span style="color: #0000ff">if</span> (CheckEndOfSeq(currentTcs) == <span style="color: #0000ff">false</span>)<br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;<br /><br /> currentTcs = <span style="color: #0000ff">new</span> TaskCompletionSource<Option<T>>();<br /><br /> Action moveNext = <span style="color: #0000ff">null</span>;<br /> moveNext = () =><br /> {<br /> Start:<br /><br /> <span style="color: #0000ff">bool</span> b;<br /><br /> <span style="color: #0000ff">try</span><br /> {<br /> b = enumerator.MoveNext();<br /> }<br /> <span style="color: #0000ff">catch</span> (Exception exception)<br /> {<br /> currentTcs.SetException(exception);<br /> <span style="color: #0000ff">return</span>;<br /> }<br /><br /> <span style="color: #0000ff">if</span> (b == <span style="color: #0000ff">false</span>)<br /> {<br /> currentTcs.SetResult(<span style="color: #0000ff">new</span> Option<T>());<br /> }<br /> <span style="color: #0000ff">else</span><br /> {<br /> var c = enumerator.Current;<br /> <span style="color: #0000ff">if</span> (c.Mode == AsyncSeqItemMode.Value)<br /> {<br /> currentTcs.SetResult(c.Value);<br /> }<br /> <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (c.Mode == AsyncSeqItemMode.Task)<br /> {<br /> <span style="color: #0000ff">if</span> (synchronizationContext != <span style="color: #0000ff">null</span>)<br /> c.Task.ContinueWith(_ => synchronizationContext.Post(s => ((Action)s)(), moveNext));<br /> <span style="color: #0000ff">else</span><br /> c.Task.ContinueWith(_ => moveNext());<br /> }<br /> <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (c.Mode == AsyncSeqItemMode.Sequence)<br /> {<br /> enumerator = c.Seq.GetEnumerator();<br /> <span style="color: #0000ff">goto</span> Start;<br /> }<br /> }<br /> };<br /><br /> moveNext();<br /><br /> <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;<br /> },<br /> () => currentTcs.Task<br /> );<br /> });<br /> }<br />}</pre>
<br /></div>
<p>As you can see the implementation is really simple but the whole concept of asynchronous sequence is very powerful.</p>
<p><a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15651">Download</a></p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com2tag:blogger.com,1999:blog-712077106443942647.post-4881275093334655642011-05-06T06:07:00.001-07:002011-05-06T06:07:04.961-07:00Rx projects update<p>In the past I have been writing about my projects related to Reactive Framework. Subsequent versions of Rx are published every one or two months and of course I have been updating my projects for my own purpose but they have not been available publicly. <a href="http://social.msdn.microsoft.com/Forums/en-US/rx/thread/527002a3-18af-4eda-8e35-760ca0006b98">Last release</a> of Rx (RC0) distinguishes two versions “Stable” and “Experimental” so I think we can expect that Rx API is really close to the final version. I thought that it is a great opportunity to publish updated versions of all my projects:</p> <ul> <li><a href="http://mnajder.blogspot.com/2009/08/generating-observable-events-with-t4.html">Observable event</a> </li> <li><a href="http://mnajder.blogspot.com/2010/10/debugging-reactive-framework-rxdebugger.html">RxDebugger</a> </li> <li><a href="http://mnajder.blogspot.com/2010/03/rxsandbox-v1.html">RxSandbox</a> </li> </ul> <p>Basically the content of the first two projects stays the same but the RxSandbox has changed a little bit. Few new operators have been added and there are currently 69 total, additionally operators that are still in experimental state (not stable) are highlighted. I am considering moving RxSandbox application from WPF to Silverlight, that will simplify the process of deployment and the end users will be always up to date with the newest version of Rx. What do you think?</p> <p><a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15376">Download</a>.</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0tag:blogger.com,1999:blog-712077106443942647.post-76868975115649335952011-05-05T09:30:00.001-07:002011-05-05T09:30:26.301-07:00Simplifying XNA game development using Async CTP or F# asynchronous workflow (GameAwaiter)<p><a href="http://mnajder.blogspot.com/2011/01/async-ctp-on-wp7.html">Last time</a> I have been writing about launching the Async CTP on WP7 platform. The <a href="http://msdn.microsoft.com/en-us/vstudio/async/">Async CTP Refresh</a><u> </u>has been released during MIX 2011 and finally WP7 platform is supported, so my last post is quite obsolete right now. But I hope that, after reading it, you better understand how Async CTP works underneath.</p> <p>This time we will go one step forward. Once we have Tasks on WP7 and two new keywords await and async in C# we can use all that to change the way we write games in XNA.</p> <p>If you know something about TPL and XNA framework it may seem a bit strange how I am going to mix them both since at first look TPL is all about building multithreaded applications and XNA application uses one single thread in most cases.</p> <p>I will not not write too much about XNA framework itself  (especially because I am a beginner in game development :) ) but if you try writing even a very simple 2D game you will find out that code for XNA is really hard to understand and maintain. Probably you will have many fields storing state of the game items, many boolean flags and a lot of if-then-else statements changing that state. You can say that the game is actually one big state machine. That’s what I’ve found out after writing my fist game in XNA.</p> <p>Async CTP can change the structure of the code dramatically so we can easily discover the flow of the game logic and what is most interesting everything is running on single thread.</p> <p>In this post I will show you three implementations of a very simple 2D game called Smiley. All of those implementations use XNA framework but the first one is a typical XNA approach and the last two are totally different. They are using Async CTP and the F# asynchronous workflow.</p> <p><a href="http://lh5.ggpht.com/_o4bEwho21rA/TcLQjz_bT4I/AAAAAAAAAJ8/1mlfOzrJ2P4/s1600-h/image5.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_o4bEwho21rA/TcLQkUOnnGI/AAAAAAAAAKA/qbva0PL4d9s/image_thumb3.png?imgmax=800" width="505" height="349" /></a> </p> <p>I took the idea for the game from the <a href="http://tomasp.net/academic/reactive-thesis/thesis.pdf">Tomas Petricek’s master thesis</a> and it can be presented on the three screens:</p> <p><a href="http://lh4.ggpht.com/_o4bEwho21rA/TcLQk-uCxoI/AAAAAAAAAKE/2uzUQiJsbqg/s1600-h/image%5B15%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_o4bEwho21rA/TcLQlbWE7yI/AAAAAAAAAKI/cw99jfDWQ8E/image_thumb%5B6%5D.png?imgmax=800" width="337" height="184" /></a> </p> <p><a href="http://lh3.ggpht.com/_o4bEwho21rA/TcLQl3Th4BI/AAAAAAAAAKM/qkTHd_UxizQ/s1600-h/image%5B16%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_o4bEwho21rA/TcLQmRVpp1I/AAAAAAAAAKQ/D6n5pWBaED8/image_thumb%5B7%5D.png?imgmax=800" width="337" height="183" /></a></p> <p> <a href="http://lh3.ggpht.com/_o4bEwho21rA/TcLQmyGl5rI/AAAAAAAAAKU/WlVhQFzpIRw/s1600-h/image%5B17%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_o4bEwho21rA/TcLQoEVeZGI/AAAAAAAAAKY/e1xqcKk2qZ4/image_thumb%5B8%5D.png?imgmax=800" width="335" height="183" /></a> </p> <p>We tap the screen to start the game, then we have 20 seconds to hit moving Smiley image as many times as we can and at the end the number of hits is displayed for 4 seconds. The first screen appears again. The Smiley position is changing in 2 seconds periods or directly after tapping on it.</p> <p>Originally, that game was implemented in F# using <a href="http://tomasp.net/blog/fsharp-variations-joinads.aspx">Joinads</a>. A few months ago I have implemented that game also in F# using Reactive Framework and treating the IObservable<T> type as the <a href="http://en.wikipedia.org/wiki/Monad_(functional_programming)">Monad</a> type. With that I built my own workflow builder. I will try to describe that approach in the next blog post but now let’s come back to the subject of today’s post.</p> <p>As you can see in the class diagram above, all three implementations have a common base class called SmileyGameBase. That class inherits from Game class which is the main XNA component representing the whole game. And all we need to do when writing an XNA game is to override two methods: Update and Draw. Update method is responsible for recalculating the game state and the Draw method draws all game items like texts, textures and so on. Both methods are called by XNA environment (Update before Draw) many times during each second when the game is running (about 30 times per second on WP7). In our game the Draw method looks the same in all three cases but the Update is specific for each of them.</p> <div> <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">class</span> SmileyGameBase : Game
{
<span style="color: #008000">// ... </span>
<span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
_spriteBatch.Begin();
<span style="color: #0000ff">if</span> (_isRunning)
{
<span style="color: #0000ff">float</span> fontScale = 2;
_spriteBatch.DrawString(_spriteFont, <span style="color: #006080">"time : "</span> + _time, <span style="color: #0000ff">new</span> Vector2(10, 5),
Color.White, 0, Vector2.Zero, fontScale, SpriteEffects.None, 0);
_spriteBatch.DrawString(_spriteFont, <span style="color: #006080">"score : "</span> + _score, <span style="color: #0000ff">new</span> Vector2(500, 5),
Color.White, 0, Vector2.Zero, fontScale, SpriteEffects.None, 0);
_spriteBatch.Draw(_smileyTexture, _smileyPosition, Color.White);
}
<span style="color: #0000ff">else</span>
{
<span style="color: #0000ff">float</span> fontScale = 3;
_spriteBatch.DrawString(_spriteFont, _message, <span style="color: #0000ff">new</span> Vector2(10, 100),
Color.Red, 0, Vector2.Zero, fontScale, SpriteEffects.None, 0);
}
_spriteBatch.End();
<span style="color: #0000ff">base</span>.Draw(gameTime);
}
}</pre>
</div>
<p>The code is pretty simple, we have few fields representing the game state and the Draw method draws Smiley image and prints some text messages. Now let’s look at the XNA and Async CTP implementations to compare them together.</p>
<p>This is the Async CTP implementation.</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">using</span> System.Threading.Tasks;
<span style="color: #0000ff">using</span> Microsoft.Xna.Framework.Input.Touch;
<span style="color: #0000ff">namespace</span> SmileyGame.Common
{
<span style="color: #0000ff">using</span> AsyncXnaIntegration;
<span style="color: #0000ff">public</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">class</span> AsyncCtpGame : SmileyGameBase
{
<span style="color: #0000ff">private</span> GameAwaiter _gameAwaiter;
<span style="color: #0000ff">protected</span> AsyncCtpGame()
{
_gameAwaiter = <span style="color: #0000ff">new</span> GameAwaiter(<span style="color: #0000ff">this</span>);
Components.Add(_gameAwaiter);
}
<span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> LoadContent()
{
<span style="color: #0000ff">base</span>.LoadContent();
StartMenu();
}
async <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> StartMenu()
{
<span style="color: #0000ff">while</span> (<span style="color: #0000ff">true</span>)
{
_message = <span style="color: #006080">"tap to start the game ... "</span>;
await _gameAwaiter.Gesture(GestureType.Tap);
_isRunning = <span style="color: #0000ff">true</span>;
await StartGame();
_isRunning = <span style="color: #0000ff">false</span>;
_message = <span style="color: #006080">"your score : "</span> + _score;
await _gameAwaiter.Delay(4000);
}
}
async <span style="color: #0000ff">private</span> Task StartGame()
{
_score = 0;
var timer = StartTimer(GameDuration);
<span style="color: #0000ff">while</span> (<span style="color: #0000ff">true</span>)
{
var match = await _gameAwaiter.WhenAny(timer,
_gameAwaiter.Delay(ChangePositionPeriod), _gameAwaiter.Gesture(IsSmileyClicked));
<span style="color: #0000ff">switch</span> (match.Index)
{
<span style="color: #0000ff">case</span> 0:
<span style="color: #0000ff">return</span>;
<span style="color: #0000ff">case</span> 1:
_smileyPosition = GetRandomPostion();
<span style="color: #0000ff">break</span>;
<span style="color: #0000ff">case</span> 2:
_smileyPosition = GetRandomPostion();
_score++;
<span style="color: #0000ff">break</span>;
<span style="color: #0000ff">default</span>: <span style="color: #0000ff">break</span>;
}
}
}
async <span style="color: #0000ff">private</span> Task StartTimer(<span style="color: #0000ff">int</span> n)
{
<span style="color: #0000ff">while</span> (n >= 0)
{
_time = n;
await _gameAwaiter.Delay(TimerPeriod);
n--;
}
}
}
}</pre>
</div>
<p>And here is the pure XNA implementation. </p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">using</span> System;
<span style="color: #0000ff">using</span> System.Collections.Generic;
<span style="color: #0000ff">using</span> System.Linq;
<span style="color: #0000ff">using</span> Microsoft.Xna.Framework;
<span style="color: #0000ff">using</span> Microsoft.Xna.Framework.Input.Touch;
<span style="color: #0000ff">namespace</span> SmileyGame.Common
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">class</span> XnaGame : SmileyGameBase
{
<span style="color: #0000ff">protected</span> XnaGame()
{
_message = <span style="color: #006080">"tap to start the game ... "</span>;
}
<span style="color: #0000ff">private</span> TimeSpan _nextTimerTime;
<span style="color: #0000ff">private</span> TimeSpan _nextChangePostionTime;
<span style="color: #0000ff">private</span> TimeSpan? _nextDisplayFinalScoreTime;
<span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> Update(GameTime gameTime)
{
<span style="color: #0000ff">base</span>.Update(gameTime);
var gestures = GetGestures();
<span style="color: #0000ff">if</span> (!_isRunning)
{
<span style="color: #0000ff">if</span> (_nextDisplayFinalScoreTime.HasValue)
{
<span style="color: #0000ff">if</span> (gameTime.TotalGameTime > _nextDisplayFinalScoreTime.Value)
{
_nextDisplayFinalScoreTime = <span style="color: #0000ff">null</span>;
_message = <span style="color: #006080">"tap to start the game ... "</span>;
}
}
<span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (gestures.Any(g => IsGestureType(g, GestureType.Tap)))
{
_isRunning = <span style="color: #0000ff">true</span>;
_score = 0;
_time = GameDuration;
_nextTimerTime = gameTime.TotalGameTime + TimeSpan.FromMilliseconds(TimerPeriod);
_nextChangePostionTime = gameTime.TotalGameTime + TimeSpan.FromMilliseconds(ChangePositionPeriod);
}
}
<span style="color: #0000ff">else</span>
{
<span style="color: #0000ff">if</span> (gameTime.TotalGameTime > _nextTimerTime )
{
_time--;
_nextTimerTime = gameTime.TotalGameTime + TimeSpan.FromMilliseconds(TimerPeriod);
<span style="color: #0000ff">if</span> (_time < 0)
{
_isRunning = <span style="color: #0000ff">false</span>;
_nextDisplayFinalScoreTime = gameTime.TotalGameTime + TimeSpan.FromMilliseconds(4000);
_message = <span style="color: #006080">"your score : "</span> + _score;
}
}
<span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (gameTime.TotalGameTime > _nextChangePostionTime )
{
_smileyPosition = GetRandomPostion();
_nextChangePostionTime = gameTime.TotalGameTime + TimeSpan.FromMilliseconds(ChangePositionPeriod);
}
<span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (gestures.Any(IsSmileyClicked))
{
_smileyPosition = GetRandomPostion();
_nextChangePostionTime = gameTime.TotalGameTime + TimeSpan.FromMilliseconds(ChangePositionPeriod);
_score++;
}
}
}
<span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">bool</span> IsGestureType(GestureSample gestureSample, GestureType gestureType)
{
<span style="color: #0000ff">return</span> (gestureSample.GestureType & gestureType) == gestureType;
}
<span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> List<GestureSample> GetGestures()
{
var gestures = <span style="color: #0000ff">new</span> List<GestureSample>();
<span style="color: #0000ff">while</span> (TouchPanel.IsGestureAvailable)
gestures.Add(TouchPanel.ReadGesture());
<span style="color: #0000ff">return</span> gestures;
}
}
}</pre>
</div>
<p>When we read first implementation we can easily discover the flow of the program and the order of particular pieces of code look natural. In the pure XNA approach it is really hard to understand how the game works internally and how to extend them. Let’s image that we would like to display sequentially “3” “2” “1” “start” just after first tap in 1 second periods. Think how to do it in each of these two approaches ?</p>
<p>So now lets go to F# implementation. F# has something called asynchronous workflow which was available for F# developers long before Async CTP (and in fact it was the inspiration for Async CTP authors) the F# implementation is very similar to Async CTP one.</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">namespace</span> SmileyGame.FSharp
open SmileyGame.Common
open AsyncXnaIntegration
open SmileyGame.FSharp.Extensions
open Microsoft.Xna.Framework.Input.Touch
type FSharpGame() <span style="color: #0000ff">as</span> <span style="color: #0000ff">this</span> =
inherit SmileyGameBase()
let _gameAwaiter = <span style="color: #0000ff">new</span> GameAwaiter(<span style="color: #0000ff">this</span>)
<span style="color: #0000ff">do</span> <span style="color: #0000ff">this</span>.Components.Add(_gameAwaiter)
<span style="color: #008000">// access to protected members</span>
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.set_smileyPosition p = <span style="color: #0000ff">this</span>._smileyPosition <- p
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.set_time t = <span style="color: #0000ff">this</span>._time <- t
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.set_score s = <span style="color: #0000ff">this</span>._score <- s
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.set_message m = <span style="color: #0000ff">this</span>._message <- m
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.set_isRunning r = <span style="color: #0000ff">this</span>._isRunning <- r
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.inc_score() = <span style="color: #0000ff">this</span>._score <- <span style="color: #0000ff">this</span>._score + 1
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.get_score = <span style="color: #0000ff">this</span>._score
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.get_TimerPeriod = SmileyGameBase.TimerPeriod
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.get_GameDuration = SmileyGameBase.GameDuration
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.get_ChangePositionPeriod = SmileyGameBase.ChangePositionPeriod
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.IsSmileyClicked g = <span style="color: #0000ff">base</span>.IsSmileyClicked g
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.GetRandomPostion() = <span style="color: #0000ff">base</span>.GetRandomPostion()
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.StartTimer n =
let n = <span style="color: #0000ff">ref</span> n
async {
<span style="color: #0000ff">while</span> !n >= 0 <span style="color: #0000ff">do</span>
<span style="color: #0000ff">this</span>.set_time !n
<span style="color: #0000ff">do</span>! _gameAwaiter.Delay(<span style="color: #0000ff">this</span>.get_TimerPeriod) |> Async.AwaitTask
n := !n - 1
}
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.StartGame() =
async {
<span style="color: #0000ff">do</span> <span style="color: #0000ff">this</span>.set_score 0
let timer = <span style="color: #0000ff">this</span>.StartTimer(<span style="color: #0000ff">this</span>.get_GameDuration) |> Async.ToTask
let c = <span style="color: #0000ff">ref</span> <span style="color: #0000ff">true</span>
<span style="color: #0000ff">while</span> !c <span style="color: #0000ff">do</span>
let! m = _gameAwaiter.WhenAny(timer,_gameAwaiter.Delay(<span style="color: #0000ff">this</span>.get_ChangePositionPeriod), _gameAwaiter.Gesture(<span style="color: #0000ff">this</span>.IsSmileyClicked)) |> Async.AwaitTask
match m.Index with
| 0 -> c := <span style="color: #0000ff">false</span>
| 1 -> <span style="color: #0000ff">this</span>.set_smileyPosition(<span style="color: #0000ff">this</span>.GetRandomPostion())
| 2 -> <span style="color: #0000ff">this</span>.set_smileyPosition(<span style="color: #0000ff">this</span>.GetRandomPostion()) ; <span style="color: #0000ff">this</span>.inc_score()
| _ -> ()
}
member <span style="color: #0000ff">private</span> <span style="color: #0000ff">this</span>.StartMenu() =
async {
<span style="color: #0000ff">while</span> <span style="color: #0000ff">true</span> <span style="color: #0000ff">do</span>
<span style="color: #0000ff">this</span>.set_message <span style="color: #006080">"tap to start the game ... "</span>
let! _ = _gameAwaiter.Gesture(GestureType.Tap) |> Async.AwaitTask
<span style="color: #0000ff">this</span>.set_isRunning <span style="color: #0000ff">true</span>
<span style="color: #0000ff">do</span>! <span style="color: #0000ff">this</span>.StartGame()
<span style="color: #0000ff">this</span>.set_isRunning <span style="color: #0000ff">false</span>
<span style="color: #0000ff">this</span>.set_message (<span style="color: #006080">"your score : "</span> + (<span style="color: #0000ff">this</span>.get_score).ToString() )
<span style="color: #0000ff">do</span>! _gameAwaiter.Delay(<span style="color: #0000ff">float</span> 4000) |> Async.AwaitTask
}
<span style="color: #0000ff">override</span> <span style="color: #0000ff">this</span>.LoadContent() =
<span style="color: #0000ff">base</span>.LoadContent()
<span style="color: #0000ff">this</span>.StartMenu() |> Async.StartImmediate </pre>
</div>
<p>Fine, but how does it work? All I had to do was to implement class GameAwaiter deriving from GameComponent which means that we can add it to the components stored inside Game class and its Update method will be called automatically when Game’s Update method is being called. GameAwaiter gives us basically a few public methods such as Gesture, Delay and WhenAny. All of them return Task object which means that at some point in the future the result will come. Let’s see the details:</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">using</span> System;
<span style="color: #0000ff">using</span> System.Collections.Generic;
<span style="color: #0000ff">using</span> System.Linq;
<span style="color: #0000ff">using</span> System.Threading.Tasks;
<span style="color: #0000ff">using</span> Microsoft.Xna.Framework;
<span style="color: #0000ff">using</span> Microsoft.Xna.Framework.Input.Touch;
<span style="color: #0000ff">namespace</span> AsyncXnaIntegration
{
<span style="color: #0000ff">using</span> AsyncXnaIntegration;
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> GameAwaiter : GameComponent
{
<span style="color: #0000ff">private</span> <span style="color: #0000ff">readonly</span> List<Job> _jobs = <span style="color: #0000ff">new</span> List<Job>();
<span style="color: #0000ff">public</span> GameAwaiter(Game game)
: <span style="color: #0000ff">base</span>(game)
{ }
<span style="color: #0000ff">public</span> Task Delay(TimeSpan interval)
{
<span style="color: #0000ff">return</span> RegisterJob(<span style="color: #0000ff">new</span> TimerJob { Interval = interval });
}
<span style="color: #0000ff">public</span> Task Delay()
{
<span style="color: #0000ff">return</span> RegisterJob(<span style="color: #0000ff">new</span> TimerJob());
}
<span style="color: #0000ff">public</span> Task While(Func<<span style="color: #0000ff">bool</span>> condition)
{
<span style="color: #0000ff">return</span> RegisterJob(<span style="color: #0000ff">new</span> WhileJob { Condition = condition });
}
<span style="color: #0000ff">public</span> Task<GestureSample[]> Gesture(Func<GestureSample, <span style="color: #0000ff">bool</span>> predicate)
{
<span style="color: #0000ff">return</span> RegisterJob(<span style="color: #0000ff">new</span> GestureJob { GestureCondition = predicate });
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> TryDisposeTask(Task tt)
{
var job = _jobs.FirstOrDefault(j => j.TaskO == tt);
<span style="color: #0000ff">if</span> (job != <span style="color: #0000ff">null</span>)
job.IsDisposed = <span style="color: #0000ff">true</span>;
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> Update(GameTime gametime)
{
var state = <span style="color: #0000ff">new</span> State { GameTime = gametime, TouchState = TouchPanel.GetState(), };
<span style="color: #0000ff">while</span> (TouchPanel.IsGestureAvailable)
state.Gestures.Add(TouchPanel.ReadGesture());
<span style="color: #0000ff">foreach</span> (var job <span style="color: #0000ff">in</span> _jobs.ToArray())
{
<span style="color: #0000ff">if</span> (job.IsDisposed || job.Update(state))
_jobs.Remove(job);
}
}
<span style="color: #0000ff">private</span> Task<T> RegisterJob<T>(Job<T> job)
{
_jobs.Add(job);
<span style="color: #0000ff">return</span> job.Task;
}
<span style="color: #cc6633">#region</span> inner types
<span style="color: #0000ff">private</span> <span style="color: #0000ff">class</span> State
{
<span style="color: #0000ff">public</span> GameTime GameTime;
<span style="color: #0000ff">public</span> TouchCollection TouchState;
<span style="color: #0000ff">public</span> <span style="color: #0000ff">readonly</span> List<GestureSample> Gestures = <span style="color: #0000ff">new</span> List<GestureSample>();
}
<span style="color: #0000ff">private</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">class</span> Job
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">bool</span> IsDisposed { get; set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">abstract</span> Task TaskO { get; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">bool</span> Update(State state);
}
<span style="color: #0000ff">private</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">class</span> Job<T> : Job
{
<span style="color: #0000ff">protected</span> TaskCompletionSource<T> _source = <span style="color: #0000ff">new</span> TaskCompletionSource<T>();
<span style="color: #0000ff">public</span> Task<T> Task { get { <span style="color: #0000ff">return</span> _source.Task; } }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> Task TaskO { get { <span style="color: #0000ff">return</span> Task; } }
}
<span style="color: #0000ff">private</span> <span style="color: #0000ff">class</span> TimerJob : Job<<span style="color: #0000ff">object</span>>
{
<span style="color: #0000ff">private</span> TimeSpan? StartTime;
<span style="color: #0000ff">public</span> TimeSpan? Interval;
<span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">bool</span> Update(State state)
{
<span style="color: #0000ff">if</span> (!Interval.HasValue)
{
_source.TrySetResult(<span style="color: #0000ff">null</span>);
<span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;
}
<span style="color: #0000ff">if</span> (!StartTime.HasValue)
StartTime = state.GameTime.TotalGameTime;
<span style="color: #0000ff">if</span> (state.GameTime.TotalGameTime - StartTime >= Interval)
{
_source.TrySetResult(<span style="color: #0000ff">null</span>);
<span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;
}
<span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;
}
}
<span style="color: #0000ff">private</span> <span style="color: #0000ff">class</span> WhileJob : Job<<span style="color: #0000ff">object</span>>
{
<span style="color: #0000ff">public</span> Func<<span style="color: #0000ff">bool</span>> Condition;
<span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">bool</span> Update(State state)
{
<span style="color: #0000ff">if</span> (Condition())
{
_source.TrySetResult(<span style="color: #0000ff">null</span>);
<span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;
}
<span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;
}
}
<span style="color: #0000ff">private</span> <span style="color: #0000ff">class</span> GestureJob : Job<GestureSample[]>
{
<span style="color: #0000ff">public</span> Func<GestureSample, <span style="color: #0000ff">bool</span>> GestureCondition;
<span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">bool</span> Update(State state)
{
<span style="color: #0000ff">if</span> (state.Gestures.Count > 0)
{
<span style="color: #0000ff">if</span> (GestureCondition == <span style="color: #0000ff">null</span>)
{
_source.TrySetResult(state.Gestures.ToArray());
<span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;
}
var gestures = state.Gestures.Where(GestureCondition).ToArray();
<span style="color: #0000ff">if</span> (gestures.Length > 0)
{
_source.TrySetResult(gestures);
<span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;
}
}
<span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;
}
}
<span style="color: #cc6633">#endregion</span>
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> GameAwaiterExtensions
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Task<Branch> WhenAny(<span style="color: #0000ff">this</span> GameAwaiter gameAwaiter, <span style="color: #0000ff">params</span> Task[] tasks)
{
<span style="color: #0000ff">return</span> GameAwaiterExtensions.WhenAny(tasks)
.ContinueWith(t =>
{
<span style="color: #0000ff">try</span>
{
<span style="color: #0000ff">foreach</span> (var tt <span style="color: #0000ff">in</span> tasks)
gameAwaiter.TryDisposeTask(tt);
<span style="color: #0000ff">return</span> t.Result;
}
<span style="color: #0000ff">catch</span> (Exception exception)
{
Debugger.Break();
<span style="color: #0000ff">return</span> t.Result;
}
}, TaskContinuationOptions.ExecuteSynchronously);
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Task<Branch> WhenAny(<span style="color: #0000ff">params</span> Task[] tasks)
{
<span style="color: #0000ff">return</span> TaskEx
.WhenAny(tasks)
.ContinueWith(t =>
{
var task = t.Result;
var taskType = task.GetType();
<span style="color: #0000ff">object</span> <span style="color: #0000ff">value</span> = <span style="color: #0000ff">null</span>;
<span style="color: #008000">// we cannot read nonpublic types via reflection in silverlight </span>
<span style="color: #0000ff">if</span> (taskType.IsGenericType && taskType.GetGenericArguments()[0].IsPublic)
<span style="color: #0000ff">value</span> = task.GetType().GetProperty(<span style="color: #006080">"Result"</span>).GetValue(task, <span style="color: #0000ff">null</span>);
<span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Branch { Index = Array.IndexOf(tasks, task), Value = <span style="color: #0000ff">value</span> };
}, TaskContinuationOptions.ExecuteSynchronously);
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Task Delay(<span style="color: #0000ff">this</span> GameAwaiter gameAwaiter, <span style="color: #0000ff">double</span> milliseconds)
{
<span style="color: #0000ff">return</span> gameAwaiter.Delay(TimeSpan.FromMilliseconds(milliseconds));
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Task<GestureSample[]> Gesture(<span style="color: #0000ff">this</span> GameAwaiter gameAwaiter, GestureType gestureType)
{
<span style="color: #0000ff">return</span> gameAwaiter.Gesture(g => (g.GestureType & gestureType) == gestureType);
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Task<GestureSample[]> Gesture(<span style="color: #0000ff">this</span> GameAwaiter gameAwaiter)
{
<span style="color: #0000ff">return</span> gameAwaiter.Gesture(g => <span style="color: #0000ff">true</span>);
}
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Branch
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span> Index;
<span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Value;
}
}</pre>
</div>
<p>The last thing I would like to mention is a really tricky stuff :) What was really important for me when writing GameAwaiter, was the linear execution of the code. I didn’t want to introduce any new threads or use the SynchronizationContext object underneath. XNA framework calls Update and Draw methods one by one in the single thread many times per second and next iteration can start after the previous one has finished, so it’s really easy to debug such a single-threaded application. The problem is that, by default, Async CTP uses SynchronizationContext‘s Post method when the continuation delegate passed to TaskAwaiter object is called. Of course that happens if any context exists and in XNA case the “SynchronizationContext.Current” property returns the instance of the context. The latest version of Async CTP gives us the ability to configure that behavior but we would need to call “task.ConfigureAwait(false)” in every place where we use await keyword. That would be pretty inconvenient. So I have implemented my own extension method for Task object, that creates appropriately configured awaiter object.</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">namespace</span> AsyncXnaIntegration
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> Extensions
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> ConfiguredTaskAwaitable.ConfiguredTaskAwaiter GetAwaiter(<span style="color: #0000ff">this</span> Task task)
{
<span style="color: #0000ff">return</span> task.ConfigureAwait(<span style="color: #0000ff">false</span>).GetAwaiter();
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> ConfiguredTaskAwaitable<T>.ConfiguredTaskAwaiter GetAwaiter<T>(<span style="color: #0000ff">this</span> Task<T> task)
{
<span style="color: #0000ff">return</span> task.ConfigureAwait(<span style="color: #0000ff">false</span>).GetAwaiter();
}
}
}</pre>
</div>
<p>Now we need to find a way to force C# compiler to use our extension method instead of that provided in AsyncCtpLibrary_Phone.dll library. We can do it for example by placing “using AsyncXnaIntegration;” statement inside the namespace declaration in all files where we are using Async CTP. Thanks to that little trick our method will be “closer” than all others defined outside the namespace declaration.</p>
<p>Of course GameAwaiter class can be extended (and it most likely will be) by many other useful methods simplifying use of phone’s Keyboard, Geo-Position or Accelerometer APIs, but this is just a proof of concept. As always I encourage you to download the <a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15375">source code</a> and definitely play the Smiley game :) Thanks for reading this post and I hope it will open your eyes for many new very interesting scenarios where the Async CTP can change XNA game development.</p>
<p><u><a href="http://archive.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=15375">downlaod</a></u></p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com3tag:blogger.com,1999:blog-712077106443942647.post-88474617387485690842011-01-21T03:45:00.001-08:002011-01-21T03:45:33.369-08:00Async CTP on WP7<p>In this post I will show you how to use <a href="http://msdn.microsoft.com/en-us/vstudio/gg316360">Async CTP</a> released during last PDC conference inside your Windows Phone application. Async CTP extends two .Net platform languages C# and VB giving us a new way of writing asynchronous code. There are two main aspects of this project: new C#/VB compiler (two new keywords: async, await) and library AsyncCtpLibrary.dll. When the compiler sees asynchronous method it generates IL code (which we will see in details further) and that code is using some types from the mentioned library. The problem is that so far we have only two versions of library: .Net and Silverlight. So in this post I will show you how we can use  Async CTP on Windows Phone 7 despite these limitations.</p> <p>The first thing we need to do before we write our first asynchronous method in the WP7 project is we need to add the reference to Silverlight version of the library AsyncCtpLibrary_Silverlight.dll. Just after doing it Visual Studio shows  a warning: “Adding a reference to a Silverlight assembly may lead to unexpected application behavior. Do you want to continue?”. The problem is that the assembly is compiled under full version of Silverlight and the Windows Phone does not contain the full version but some subset of it running on the top of .Net compact framework. So if we execute some code from such a assembly which is using types that are not available on the phone we will get the runtime exception. The key element of the AsyncCtpLibrary are Tasks and unfortunately they are not running on the phone throwing exception at runtime. The question is: can we use Async CTP without Tasks ? Of course we can! The whole mechanism behind asynchronous methods doesn’t force us to use the instance of type Task followed by await keyword. That type needs to contain method (instance or extension method) called GetAwaiter returning any type that contains appropriate pair of methods (instance or extension) BeginAwait and EndAwait. And all I did is I implemented such a matching type.</p> <div> <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">enum</span> AwaiterResultType
{
Completed,
Failed,
Cancelled
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> AwaiterResult<T>
{
<span style="color: #0000ff">public</span> AwaiterResultType ResultType { get; <span style="color: #0000ff">private</span> set; }
<span style="color: #0000ff">public</span> Exception Exception { get; <span style="color: #0000ff">private</span> set; }
<span style="color: #0000ff">public</span> T Value { get; <span style="color: #0000ff">private</span> set; }
<span style="color: #0000ff">private</span> AwaiterResult() { }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> AwaiterResult<T> Completed(T result)
{
<span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> AwaiterResult<T> { ResultType = AwaiterResultType.Completed, Value = result };
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> AwaiterResult<T> Failed(Exception exception)
{
<span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> AwaiterResult<T> { ResultType = AwaiterResultType.Failed, Exception = exception };
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> AwaiterResult<T> Cancelled()
{
<span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> AwaiterResult<T> { ResultType = AwaiterResultType.Cancelled };
}
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Awaiter<T>
{
<span style="color: #0000ff">private</span> SynchronizationContext Context { get; set; }
<span style="color: #0000ff">private</span> <span style="color: #0000ff">bool</span> IsSynchronized { get; set; }
<span style="color: #0000ff">private</span> Action _continuation;
<span style="color: #0000ff">public</span> AwaiterResult<T> Result { get; <span style="color: #0000ff">private</span> set; }
<span style="color: #0000ff">private</span> Awaiter() { }
<span style="color: #0000ff">public</span> Awaiter<T> GetAwaiter()
{
<span style="color: #0000ff">return</span> <span style="color: #0000ff">this</span>;
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">bool</span> BeginAwait(Action continuation)
{
<span style="color: #0000ff">if</span> (Result != <span style="color: #0000ff">null</span>)
<span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;
_continuation += continuation;
<span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;
}
<span style="color: #0000ff">public</span> T EndAwait()
{
<span style="color: #0000ff">if</span> (Result == <span style="color: #0000ff">null</span>)
<span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> InvalidOperationException(<span style="color: #006080">"Awaiter does not contain the result yet."</span>);
<span style="color: #0000ff">if</span> (Result.ResultType == AwaiterResultType.Completed)
<span style="color: #0000ff">return</span> Result.Value;
<span style="color: #0000ff">if</span> (Result.ResultType == AwaiterResultType.Failed)
<span style="color: #0000ff">throw</span> Result.Exception;
<span style="color: #0000ff">return</span> <span style="color: #0000ff">default</span>(T); <span style="color: #008000">// if cancelled</span>
}
<span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> OnResult(AwaiterResult<T> result)
{
<span style="color: #0000ff">if</span> (result == <span style="color: #0000ff">null</span>) <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> ArgumentNullException(<span style="color: #006080">"result"</span>);
<span style="color: #0000ff">if</span> (Result != <span style="color: #0000ff">null</span>) <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> InvalidOperationException(<span style="color: #006080">"The result can be provided only once."</span>);
Result = result;
<span style="color: #0000ff">if</span> (IsSynchronized && Context != <span style="color: #0000ff">null</span>)
{
Context.Post(o =>
{
<span style="color: #0000ff">if</span> (_continuation != <span style="color: #0000ff">null</span>)
_continuation();
_continuation = <span style="color: #0000ff">null</span>;
}, <span style="color: #0000ff">null</span>);
Context = <span style="color: #0000ff">null</span>;
}
<span style="color: #0000ff">else</span>
{
<span style="color: #0000ff">if</span> (_continuation != <span style="color: #0000ff">null</span>)
_continuation();
_continuation = <span style="color: #0000ff">null</span>;
}
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<T> Create(Action<Action<AwaiterResult<T>>> resultProvider, <span style="color: #0000ff">bool</span> synchronizeWithCurrentContext = <span style="color: #0000ff">true</span>)
{
<span style="color: #0000ff">if</span> (resultProvider == <span style="color: #0000ff">null</span>) <span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span> ArgumentNullException(<span style="color: #006080">"resultProvider"</span>);
var awaiter = <span style="color: #0000ff">new</span> Awaiter<T> { IsSynchronized = synchronizeWithCurrentContext };
<span style="color: #0000ff">if</span> (synchronizeWithCurrentContext)
awaiter.Context = SynchronizationContext.Current;
resultProvider(awaiter.OnResult);
<span style="color: #0000ff">return</span> awaiter;
}
}</pre>
</div>
<p></p>
<p>The key class here is Awaiter class containing appropriate three methods: GetAwaiter, BeginAwait and EndAwait. This is an abstraction of asynchronous work (very similar to Task type) which at some point in time is finishing its work in one of three possible states: an exception could be thrown, maybe someone cancelled the execution or the work has been completed correctly returning some result. The constructor is private so the factory method called Create is the only way to create an instance of Awaiter type. So let’s see how we can use it:</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> AwaiterEx
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<T> Run<T>(Func<T> action)
{
<span style="color: #0000ff">return</span> Awaiter<T>.Create(resultProvider =>
{
ThreadPool.QueueUserWorkItem(o =>
{
<span style="color: #0000ff">try</span>
{
var result = action();
resultProvider(AwaiterResult<T>.Completed(result));
}
<span style="color: #0000ff">catch</span> (Exception exception)
{
resultProvider(AwaiterResult<T>.Failed(exception));
}
},<span style="color: #0000ff">null</span>);
});
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<<span style="color: #0000ff">object</span>> Delay(TimeSpan timeSpan)
{
<span style="color: #0000ff">return</span> Awaiter<<span style="color: #0000ff">object</span>>.Create(resultProvider =>
{
var timer = <span style="color: #0000ff">new</span> Timer(o => resultProvider(AwaiterResult<<span style="color: #0000ff">object</span>>.Completed(<span style="color: #0000ff">null</span>)));
timer.Change((<span style="color: #0000ff">int</span>)timeSpan.TotalMilliseconds, -1);
});
}
}
async <span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Sample()
{
<span style="color: #0000ff">int</span> intResult = await AwaiterEx.Run(() =>
{
Thread.Sleep(3000);
<span style="color: #0000ff">return</span> 123;
});
MessageBox.Show(<span style="color: #006080">"Completed: "</span> + intResult);
await AwaiterEx.Delay(TimeSpan.FromSeconds(3));
MessageBox.Show(<span style="color: #006080">"After 3 seconds..."</span>);
}</pre>
</div>
<p>Now let’s look at simplified version of what compiler is generating underneath to allow us to write synchronously looking code running asynchronously.</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> SampleInternals()
{
Awaiter<<span style="color: #0000ff">int</span>> awaiter1 = <span style="color: #0000ff">null</span>;
Awaiter<<span style="color: #0000ff">object</span>> awaiter2 = <span style="color: #0000ff">null</span>;
<span style="color: #0000ff">int</span> state = 0;
Action action = <span style="color: #0000ff">null</span>;
action = () =>
{
<span style="color: #0000ff">if</span> (state == 1) <span style="color: #0000ff">goto</span> JUMP_LABEL_1;
<span style="color: #0000ff">if</span> (state == 2) <span style="color: #0000ff">goto</span> JUMP_LABEL_2;
awaiter1 = AwaiterEx.Run(() =>
{
Thread.Sleep(3000);
<span style="color: #0000ff">return</span> 123;
}).GetAwaiter();
state = 1;
<span style="color: #0000ff">if</span> (awaiter1.BeginAwait(action))
<span style="color: #0000ff">return</span>;
JUMP_LABEL_1:
var intResult = awaiter1.EndAwait();
MessageBox.Show(<span style="color: #006080">"Completed: "</span> + intResult);
awaiter2 = AwaiterEx.Delay(TimeSpan.FromSeconds(3)).GetAwaiter();
state = 2;
<span style="color: #0000ff">if</span> (awaiter2.BeginAwait(action))
<span style="color: #0000ff">return</span>;
JUMP_LABEL_2:
awaiter2.EndAwait();
MessageBox.Show(<span style="color: #006080">"After 3 seconds..."</span>);
};
action();
}</pre>
</div>
<p>The last thing worth mentioning is how to write asynchronous method returning some value. Asynchronous methods have two limitations: void, Task and Task<T> are the only valid return types and out parameters are not allowed. As we said before Tasks under WP7 don’t work so we cannot return Task object. In fact the solution is very simple:</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> AwaiterEx
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<<span style="color: #0000ff">object</span>> BeginWriteAwaiter(<span style="color: #0000ff">this</span> Stream stream, <span style="color: #0000ff">byte</span>[] buffer, <span style="color: #0000ff">int</span> offset, <span style="color: #0000ff">int</span> numBytes)
{
<span style="color: #0000ff">return</span> Awaiter<<span style="color: #0000ff">object</span>>.Create(resultProvider =>
{
<span style="color: #0000ff">try</span>
{
stream.BeginWrite(buffer, offset, numBytes, o =>
{
<span style="color: #0000ff">try</span>
{
stream.EndWrite(o);
resultProvider(AwaiterResult<<span style="color: #0000ff">object</span>>.Completed(<span style="color: #0000ff">null</span>));
}
<span style="color: #0000ff">catch</span> (Exception exception)
{
resultProvider(AwaiterResult<<span style="color: #0000ff">object</span>>.Failed(exception));
}
}, <span style="color: #0000ff">null</span>);
}
<span style="color: #0000ff">catch</span> (Exception exception)
{
resultProvider(AwaiterResult<<span style="color: #0000ff">object</span>>.Failed(exception));
}
});
}
}
<span style="color: #0000ff">public</span> Awaiter<<span style="color: #0000ff">object</span>> WriteFileAwaiter(<span style="color: #0000ff">string</span> path, <span style="color: #0000ff">string</span> text)
{
<span style="color: #0000ff">return</span> Awaiter<<span style="color: #0000ff">object</span>>.Create(async resultProvider =>
{
<span style="color: #0000ff">try</span>
{
<span style="color: #0000ff">using</span> (var stream = IsolatedStorageFile.OpenFile(path, FileMode.Create))
<span style="color: #008000">// caution: in fact the stream is running synchronously on WP7</span>
{
var data = Encoding.Unicode.GetBytes(text);
await stream.BeginWriteAwaiter(data, 0, data.Length);
resultProvider(AwaiterResult<<span style="color: #0000ff">object</span>>.Completed(<span style="color: #0000ff">null</span>));
}
}
<span style="color: #0000ff">catch</span> (Exception exception)
{
resultProvider(AwaiterResult<<span style="color: #0000ff">object</span>>.Failed(exception));
}
});
}</pre>
</div>
<p>I encourage you to <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=14873">download sources</a> with attached samples and play with Async CTP on WP7 because it changes a lot in terms of writing asynchronous code. AsyncCtpLibrary library provides TaskEx class with few very useful methods so you can find counterpart in my library called AwaiterEx with following API:</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> AwaiterEx
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<<span style="color: #0000ff">string</span>> DownloadStringAwaiter(<span style="color: #0000ff">this</span> WebClient webClient, Uri uri) { ... }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<<span style="color: #0000ff">object</span>> BeginWriteAwaiter(<span style="color: #0000ff">this</span> Stream stream, <span style="color: #0000ff">byte</span>[] buffer, <span style="color: #0000ff">int</span> offset, <span style="color: #0000ff">int</span> numBytes) { ... }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<T> ToAwaiter<T>(<span style="color: #0000ff">this</span> IObservable<T> observable) { ... }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<T[]> ToAwaiterAll<T>(<span style="color: #0000ff">this</span> IObservable<T> observable) { ... }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IObservable<T> ToObservable<T>(<span style="color: #0000ff">this</span> Awaiter<T> awaiter) { ... }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<T[]> WhenAll<T>(<span style="color: #0000ff">this</span> IEnumerable<Awaiter<T>> awaiters) { ... }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<T[]> WhenAll<T>(<span style="color: #0000ff">params</span> Awaiter<T>[] awaiters) { ... }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<T> Run<T>(Func<T> action) { ... }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Awaiter<<span style="color: #0000ff">object</span>> Delay(TimeSpan timeSpan) { ... }
}</pre>
</div>
<p>Have fun and let me know if you liked it or not. <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=14873">Download</a></p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0tag:blogger.com,1999:blog-712077106443942647.post-31060764356249107942010-12-09T09:55:00.001-08:002010-12-09T09:55:07.894-08:00Recording of my presentation "Introduction to F#” has been published<p><a href="http://mnajder.blogspot.com/2010/10/after-microsoft-technology-summit-2010.html">Few weeks</a> ago I promised recording of my presentation given during MTS 2010 conference, <a href="http://vimeo.com/17615280">here</a> it is. Enjoy!</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0tag:blogger.com,1999:blog-712077106443942647.post-33317665524727447602010-11-07T23:43:00.001-08:002010-11-07T23:43:30.044-08:00Currying in C#<p>During reviewing samples for <a href="http://msdn.microsoft.com/en-us/vstudio/async.aspx">Async Ctp</a> I have found such code:</p> <div> <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">var cts = <span style="color: #0000ff">new</span> CancellationTokenSource();
btnCancel.Click += cts.EventHandler; <span style="color: #008000">// !!!!</span>
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> Extensions
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> EventHandler(<span style="color: #0000ff">this</span> CancellationTokenSource cts,
<span style="color: #0000ff">object</span> sender, EventArgs e)
{
cts.Cancel();
}
}</pre>
</div>
<p>Did you know it was possible ?</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com1tag:blogger.com,1999:blog-712077106443942647.post-47237713910439915512010-10-27T14:55:00.001-07:002010-10-27T14:55:13.328-07:00After Microsoft Technology Summit 2010<p>This year again I had the opportunity to speak during <a href="http://www.mtskonferencja.pl/">MTS 2010</a> conference in Warsaw. <a href="http://mnajder.blogspot.com/2009/11/after-microsoft-technology-summit-2009.html">Last time</a> I have been talking about WF4 and this time the title of my talk was <a href="http://www.mtskonferencja.pl/rejestracja/sessions.aspx">“Introduction to F#”</a>. I would like to thank all attendees for coming! All resources presented during the session are available for download <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=14210">here</a>, <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=12939">here</a> and <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=14211">here</a>. In the near future I’ll publish recording from this session.</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0tag:blogger.com,1999:blog-712077106443942647.post-46882970354553939102010-10-25T01:23:00.001-07:002011-05-06T06:12:42.493-07:00Debugging Reactive Framework (RxDebugger) and Linq to objects (LinqDebugger)<p><font color="#ff0000">[<a href="http://mnajder.blogspot.com/2011/05/rx-projects-update.html">New version</a> (2011.05.06)]</font></p> <p><font color="#ff0000">[Project download has been upgraded to the newest version of Rx (Build v1.0.2787.0) and VS2010 ] </font><a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=14361"><font color="#ff0000">download</font></a> <br /><font color="#ff0000">(Changes: projects converted to VS2010, sample project for RxDebugger added)</font></p> <p>In this post I will present two projects <strong>LinqDebugger</strong> and <strong>RxDebugger</strong>. Few months ago after reading Bart De Smet’s great <a href="http://community.bartdesmet.net/blogs/bart/archive/2009/04/23/linq-to-objects-debugging.aspx">post</a> about tracing execution of the Linq to objects queries I was wondering if it was be possible to implement the same concept but in more general way. If we want to trace the execution of all of the Linq operators using described approach we would have to implement many extension methods, one for each Linq operator. How to avoid this ? <strong>LinqDebugger</strong> is the the answer ;)<strong> . </strong>If you are wondering what the lazy evaluation is and how to debug Linq to object queries this project can be very useful. Let’s see a very simple query :</p> <div> <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">var q =
from i <span style="color: #0000ff">in</span> Enumerable.Range(0, 12)
<span style="color: #0000ff">where</span> i > 5 && i % 2 == 0
select i.ToString(<span style="color: #006080">"C"</span>);
<span style="color: #0000ff">foreach</span> (var s <span style="color: #0000ff">in</span> q)
Console.WriteLine(s);</pre>
</div>
<p>Now let’s debug that query:</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">var q =
from i <span style="color: #0000ff">in</span> Enumerable.Range(0, 12).AsDebuggable()
<span style="color: #0000ff">where</span> i > 5 && i % 2 == 0
select i.ToString(<span style="color: #006080">"C"</span>);
<span style="color: #0000ff">foreach</span> (var s <span style="color: #0000ff">in</span> q)
Console.WriteLine(s); </pre>
</div>
<p>After running this code you will find the following text on the console:</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">Select creation
Select begin
Where creation
Where begin
predicate i => ((i > 5) && ((i % 2) = 0)) : (0) => False
predicate i => ((i > 5) && ((i % 2) = 0)) : (1) => False
predicate i => ((i > 5) && ((i % 2) = 0)) : (2) => False
predicate i => ((i > 5) && ((i % 2) = 0)) : (3) => False
predicate i => ((i > 5) && ((i % 2) = 0)) : (4) => False
predicate i => ((i > 5) && ((i % 2) = 0)) : (5) => False
predicate i => ((i > 5) && ((i % 2) = 0)) : (6) => True
Where end 6
selector i => i.ToString(<span style="color: #006080">"C"</span>) : (6) => 6,00 zł
Select end 6,00 zł
6,00 zł
Select begin
Where begin
predicate i => ((i > 5) && ((i % 2) = 0)) : (7) => False
predicate i => ((i > 5) && ((i % 2) = 0)) : (8) => True
Where end 8
selector i => i.ToString(<span style="color: #006080">"C"</span>) : (8) => 8,00 zł
Select end 8,00 zł
8,00 zł
Select begin
Where begin
predicate i => ((i > 5) && ((i % 2) = 0)) : (9) => False
predicate i => ((i > 5) && ((i % 2) = 0)) : (10) => True
Where end 10
selector i => i.ToString(<span style="color: #006080">"C"</span>) : (10) => 10,00 zł
Select end 10,00 zł
10,00 zł
Select begin
Where begin
predicate i => ((i > 5) && ((i % 2) = 0)) : (11) => False
Where end (no result)
Select end (no result)</pre>
</div>
<p>This text shows how the query has been executed. There can find there information about enumerators object creation, about data passing from one enumerator to another and execution of all functions used inside the query. One thing worth mentioning is that everything is presented in the same order as it was executed. Having this information we can easily figure out for example in which iteration the exception has been thrown and what were the values processing by the query at that moment. If such text representation is hard to read for you I also provide the VS visualizer for ExecutionPlan type presenting the same information on the tree control (copy LinqDebugger.dll and LinqDebugger.Visualizer.dll files to C:\Program Files\Microsoft Visual Studio 9.0\Common7\Packages\Debugger\Visualizers folder to make it available).</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">var executionPlan = <span style="color: #0000ff">new</span> ExecutionPlan();
var q =
from i <span style="color: #0000ff">in</span> Enumerable.Range(0, 12).AsDebuggable(executionPlan)
<span style="color: #0000ff">where</span> i > 5 && i % 2 == 0
select i.ToString(<span style="color: #006080">"C"</span>);
<span style="color: #0000ff">foreach</span> (var s <span style="color: #0000ff">in</span> q)
Console.WriteLine(s);</pre>
</div>
<p><a href="http://lh6.ggpht.com/_o4bEwho21rA/TMU-emxy1fI/AAAAAAAAAHQ/yz_Iy4C97C8/s1600-h/image4%5B1%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_o4bEwho21rA/TMU-fA4Qc7I/AAAAAAAAAHU/UOSfmPIfuWA/image_thumb2.png?imgmax=800" width="534" height="437" /></a></p>
<p>I am not going to describe here in details how LinqDebugger has been implemented, you can download the code and check this out yourself. As a hint I will just show you the signature of AsDebuggable method. Please notice what else you can pass to that method. We can choose which operators we want to trace using LinqOperators enum type or pass TextWriter object (Console.Out is set as a default TextWriter).</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> LinqDebuggerExtensions
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IQueryable<T> AsDebuggable<T>(<span style="color: #0000ff">this</span> IEnumerable<T> source, ExecutionPlan executionPlan,
LinqOperators linqOperators, TextWriter textWriter)
{ ... }
}
[Flags]
<span style="color: #0000ff">public</span> <span style="color: #0000ff">enum</span> LinqOperators : <span style="color: #0000ff">long</span>
{
None = 0,
Aggregate = 1,
All = 2,
Any = 4,
AsQueryable = 8,
Average = 16,
Cast = 32,
Concat = 64,
Contains = 128,
...
}
[Serializable]
<span style="color: #0000ff">public</span> <span style="color: #0000ff">sealed</span> <span style="color: #0000ff">class</span> ExecutionPlan
{
<span style="color: #0000ff">public</span> Expression Query { get; <span style="color: #0000ff">internal</span> set; }
<span style="color: #0000ff">public</span> List<Record> Records { get; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Reset();
}
[Serializable]
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Record
{
<span style="color: #0000ff">public</span> RecordType RecordType { get; <span style="color: #0000ff">internal</span> set; }
<span style="color: #0000ff">public</span> MethodCallExpression OperatorCallExpression { get; <span style="color: #0000ff">internal</span> set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Result { get; <span style="color: #0000ff">internal</span> set; }
<span style="color: #0000ff">public</span> LambdaExpression FuncCallExpression { get; <span style="color: #0000ff">internal</span> set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> FuncCallName { get; <span style="color: #0000ff">internal</span> set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span>[] Arguments { get; <span style="color: #0000ff">internal</span> set; }
}</pre>
</div>
<p>Tracing similar information during Rx queries execution is even more useful because in most cases such queries are executed asynchronously so debugging them is really hard. Let’s debug Rx version of previous query using <strong>RxDebugger</strong>:</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">var q =
from i <span style="color: #0000ff">in</span> Enumerable.Range(0, 12).ToObservable().AsDebuggable(
<span style="color: #0000ff">new</span> DebugSettings {SourceName = <span style="color: #006080">"range"</span>, Logger = DebugSettings.ConsoleLogger})
<span style="color: #0000ff">where</span> i > 5 && i % 2 == 0
select i.ToString(<span style="color: #006080">"C"</span>);
q.Run(Console.WriteLine);
range.Where.Select.Subscribe()
range.Where.Subscribe()
range.Subscribe()
range.OnNext(0)
range.OnNext(1)
range.OnNext(2)
range.OnNext(3)
range.OnNext(4)
range.OnNext(5)
6,00 zł
range.OnNext(6)
range.Where.OnNext(6)
range.Where.Select.OnNext(6,00 zł)
range.OnNext(7)
8,00 zł
range.OnNext(8)
range.Where.OnNext(8)
range.Where.Select.OnNext(8,00 zł)
range.OnNext(9)
10,00 zł
range.OnNext(10)
range.Where.OnNext(10)
range.Where.Select.OnNext(10,00 zł)
range.OnNext(11)
range.OnCompleted()
range.Where.OnCompleted()
range.Where.Select.OnCompleted()
range.Where.Select.Dispose()
range.Where.Dispose()
range.Dispose()</pre>
</div>
<p>As you can see this time a quite deferent information displayed on the screen and there is no VS visualizer available. It’s because the implementation of RxDebugger is totally different from LinqDebugger. But there are some additional features too. To understand how RxDebugger works I will show you the Debug method which gives us ability to trace single observable object instead of the whole Rx query.</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">var q =
from i <span style="color: #0000ff">in</span> Enumerable.Range(0, 12).ToObservable().Debug(
<span style="color: #0000ff">new</span> DebugSettings {SourceName = <span style="color: #006080">"range"</span>, Logger = DebugSettings.ConsoleLogger})
<span style="color: #0000ff">where</span> i > 5 && i % 2 == 0
select i.ToString(<span style="color: #006080">"C"</span>);
q.Run(Console.WriteLine);
range.Subscribe()
range.OnNext(0)
range.OnNext(1)
range.OnNext(2)
range.OnNext(3)
range.OnNext(4)
range.OnNext(5)
6,00 zł
range.OnNext(6)
range.OnNext(7)
8,00 zł
range.OnNext(8)
range.OnNext(9)
10,00 zł
range.OnNext(10)
range.OnNext(11)
range.OnCompleted()
range.Dispose()</pre>
</div>
<p> </p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IObservable<T> Debug<T>(<span style="color: #0000ff">this</span> IObservable<T> source, DebugSettings settings, Func<T, <span style="color: #0000ff">object</span>> valueSelector)
{
Action<T> onNext = v => { };
<span style="color: #0000ff">if</span> ((settings.NotificationFilter & NotificationFilter.OnNext) == NotificationFilter.OnNext)
onNext = v =>
{
<span style="color: #0000ff">if</span> (settings.Logger != <span style="color: #0000ff">null</span>)
settings.LoggerScheduler.Schedule(() => settings.Logger(DebugEntry.Create(settings, NotificationFilter.OnNext, valueSelector(v))));
};
Action<Exception> onError = ... ;
Action onCompleted = ... ;
Action subscribe = ... ;
Action dispose = ... ;
<span style="color: #0000ff">return</span> Observable.CreateWithDisposable<T>(o =>
{
var newObserver = Observer.Create<T>
(
v => { onNext(v); o.OnNext(v); },
e => { onError(e); o.OnError(e); },
() => { onCompleted(); o.OnCompleted(); }
);
subscribe();
var disposable = source.Subscribe(newObserver);
<span style="color: #0000ff">return</span> Disposable.Create(() =>
{
dispose();
disposable.Dispose();
});
});
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">sealed</span> <span style="color: #0000ff">class</span> DebugSettings
{
<span style="color: #008000">// defaults </span>
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Action<DebugEntry> DefaultLogger { get; set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IScheduler DefaultLoggerSchduler { get; set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">string</span> DefaultMessageFormat { get; set; }
<span style="color: #008000">//loggers</span>
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Action<DebugEntry> ConsoleLogger { get; <span style="color: #0000ff">private</span> set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Action<DebugEntry> DebugLogger { get; <span style="color: #0000ff">private</span> set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> MessageFormat { get; set; }
<span style="color: #0000ff">public</span> Action<DebugEntry> Logger { get; set; }
<span style="color: #0000ff">public</span> IScheduler LoggerScheduler { get; set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> SourceName { get; set; }
<span style="color: #0000ff">public</span> NotificationFilter NotificationFilter { get; set; }
<span style="color: #0000ff">public</span> OperatorFilter OperatorFilter { get; set; }
<span style="color: #0000ff">static</span> DebugSettings()
{
ConsoleLogger = n => Console.WriteLine(n.FormattedMessage);
DebugLogger = n => Debug.WriteLine(n.FormattedMessage);
DefaultLogger = DebugLogger;
DefaultLoggerSchduler = Scheduler.CurrentThread;
DefaultMessageFormat = <span style="color: #006080">"{0}.{1}({2})"</span>;
}
<span style="color: #0000ff">public</span> DebugSettings()
{
SourceName = <span style="color: #006080">""</span>;
NotificationFilter = NotificationFilter.All;
OperatorFilter = OperatorFilter.AllOperators;
Logger = DefaultLogger;
LoggerScheduler = DefaultLoggerSchduler;
MessageFormat = DefaultMessageFormat;
}
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> DebugEntry
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> SourceName { get; set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> FormattedMessage { get; set; }
<span style="color: #0000ff">public</span> NotificationFilter Kind { get; set; }
<span style="color: #0000ff">public</span> Exception Exception { get; set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">object</span> Value { get; set; }
}</pre>
</div>
<p>Debug method creates a new observable object on the top of given observable sources. Each observer passed to this observable source is wrapped into a new observer tracing information about calling Subscribe, Dispose methods at the IObservable level and OnNext, OnError, OnCompleted methods at the IObserver level. We can provide filter on Rx operators (OperatorFilter enum type) or logged information (NotificationFilter enum type). In LinqDebugger project TextWiter class has been used to log information. Here we have much more flexible solution because we can pass delegate type responsible for storing logged information. RxDebugger provides standard loggers such as DebugSettings.ConsoleLogger or DebugSettings.DebugLogger but we can also set our own delegate type or even merge many different logger delegates. Such a scenario will be presented in further part of the post. Once we know how Debug method works let’s reveal the secret behind the AsDebuggable method.</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span> IDebuggedObservable<T> : IObservable<T>
{
DebugSettings Settings { get; }
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">partial</span> <span style="color: #0000ff">class</span> RxDebuggerExtensions
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IDebuggedObservable<T> AsDebuggable<T>(<span style="color: #0000ff">this</span> IObservable<T> source, DebugSettings settings)
{
<span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> DebuggedObservable<T>(source.Debug(settings), settings);
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IDebuggedObservable<TSource> Where<TSource>(<span style="color: #0000ff">this</span> IDebuggedObservable<TSource> source , Func<TSource,<span style="color: #0000ff">bool</span>> predicate)
{
var settings = source.Settings.Copy();
settings.SourceName = settings.SourceName + <span style="color: #006080">".Where"</span>;
<span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> DebuggedObservable<TSource>((source <span style="color: #0000ff">as</span> IObservable<TSource>).Where<TSource>(predicate).Debug(settings), settings);
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> IDebuggedObservable<TResult> Select<TSource,TResult>(<span style="color: #0000ff">this</span> IDebuggedObservable<TSource> source , Func<TSource,TResult> selector)
{
var settings = source.Settings.Copy();
settings.SourceName = settings.SourceName + <span style="color: #006080">".Select"</span>;
<span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> DebuggedObservable<TResult>((source <span style="color: #0000ff">as</span> IObservable<TSource>).Select<TSource,TResult>(selector).Debug(settings), settings);
}
...
<span style="color: #0000ff">private</span> <span style="color: #0000ff">class</span> DebuggedObservable<T> : IDebuggedObservable<T>
{
<span style="color: #0000ff">private</span> <span style="color: #0000ff">readonly</span> IObservable<T> _source;
<span style="color: #0000ff">private</span> <span style="color: #0000ff">readonly</span> DebugSettings _settings;
<span style="color: #0000ff">public</span> DebugSettings Settings { get { <span style="color: #0000ff">return</span> _settings; } }
<span style="color: #0000ff">public</span> DebuggedObservable(IObservable<T> source, DebugSettings settings)
{
_source = source;
_settings = settings;
}
<span style="color: #0000ff">public</span> IDisposable Subscribe(IObserver<T> observer)
{
<span style="color: #0000ff">return</span> _source.Subscribe(observer);
}
}
}</pre>
</div>
<p>Of course I didn’t implement extension methods for all Rx operator manually, I wrote T4 template generating appropriate extension methods (currently 127 methods in .Net version and 125 methods in Silverlight version :) ). The best way to use RxDebugger in your projects is to add T4 template to the project you are working on and run template every time you change the version of Rx. It allows you to always be synchronized with Rx dlls. Finally let’s see how to use RxDebugger in Silverlight application.</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff"><</span><span style="color: #800000">UserControl</span> <span style="color: #ff0000">x:Class</span><span style="color: #0000ff">="Blog.SL.Post016.RxDebuggerTest"</span>
<span style="color: #ff0000">xmlns</span><span style="color: #0000ff">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span>
<span style="color: #ff0000">xmlns:x</span><span style="color: #0000ff">="http://schemas.microsoft.com/winfx/2006/xaml"</span>
<span style="color: #ff0000">xmlns:d</span><span style="color: #0000ff">="http://schemas.microsoft.com/expression/blend/2008"</span>
<span style="color: #ff0000">xmlns:mc</span><span style="color: #0000ff">="http://schemas.openxmlformats.org/markup-compatibility/2006"</span>
<span style="color: #ff0000">mc:Ignorable</span><span style="color: #0000ff">="d"</span> <span style="color: #ff0000">d:DesignWidth</span><span style="color: #0000ff">="640"</span> <span style="color: #ff0000">d:DesignHeight</span><span style="color: #0000ff">="480"</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><</span><span style="color: #800000">StackPanel</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><</span><span style="color: #800000">TextBox</span> <span style="color: #ff0000">x:Name</span><span style="color: #0000ff">="input"</span><span style="color: #0000ff">/></span>
<span style="color: #0000ff"><</span><span style="color: #800000">TextBox</span> <span style="color: #ff0000">x:Name</span><span style="color: #0000ff">="output"</span><span style="color: #0000ff">/></span>
<span style="color: #0000ff"><</span><span style="color: #800000">ItemsControl</span> <span style="color: #ff0000">x:Name</span><span style="color: #0000ff">="log"</span><span style="color: #0000ff">/></span>
<span style="color: #0000ff"></</span><span style="color: #800000">StackPanel</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"></</span><span style="color: #800000">UserControl</span><span style="color: #0000ff">></span></pre>
</div>
<p> </p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">partial</span> <span style="color: #0000ff">class</span> RxDebuggerTest : UserControl
{
<span style="color: #0000ff">public</span> RxDebuggerTest()
{
InitializeComponent();
var entries = <span style="color: #0000ff">new</span> ObservableCollection<DebugEntry>();
log.ItemsSource = entries;
var q = input
.GetObservableTextChanged()
.Select(e => ((TextBox)e.Sender).Text)
.AsDebuggable(<span style="color: #0000ff">new</span> DebugSettings
{
SourceName = <span style="color: #006080">"textChanged"</span>,
LoggerScheduler = Scheduler.Dispatcher,
Logger = DebugSettings.DebugLogger + entries.Add,
})
.Throttle(TimeSpan.FromSeconds(2))
.Select(t => <span style="color: #0000ff">new</span> <span style="color: #0000ff">string</span>(t.Reverse().ToArray()));
q.ObserveOnDispatcher().Subscribe(t => output.Text = t);
}
}</pre>
</div>
<p><a href="http://lh4.ggpht.com/_o4bEwho21rA/TMU-fuB4LtI/AAAAAAAAAHY/qUl5mzeQ7l0/s1600-h/image4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_o4bEwho21rA/TMU-gGR_PkI/AAAAAAAAAHc/iIQVWqukxNY/image_thumb1.png?imgmax=800" width="327" height="248" /></a></p>
<p>And that’s it for the post. I encourage you to download and play with the two simple tools I provided here. They can be very helpful in debugging LINQ quires or learning about the internals of LINQ and Rx.
<br /><a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=14209">downlaod</a> (Rx versions: .Net3.5 v1.0.2698.0 and SL3 v1.0.2698.0) Always check for newest version at the beginning of the post.</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com3tag:blogger.com,1999:blog-712077106443942647.post-54377593335239505562010-07-05T01:04:00.001-07:002010-07-05T01:04:49.550-07:00After Virtual Study Conference 2010<p><a href="http://conf2010.virtualstudy.pl/index.php?sub=home_en">VirtualStudy Conference 2010</a> was the first edition of the virtual conference where all attendees as well as speakers have been remotely connected together via Live Meeting platform. This time I have been talking about reactive programming  as a general way of writing code. Here is the overview of my presentation:</p> <p><b>Reactive Programming - a new paradigm of programming</b></p> <p>Nowadays more and more systems created by us work in the cloud. Client while connecting using WebService is performing certain operations. Remote calls have longer time of duration than local methods, so often we are forced to perform them asynchronously. .NET Framework provides mechanisms, such as threads, APM pattern (Asynchronous Programming Model) or EAP (Event-based Asynchronous Pattern.) But the problem arises, when we want to coordinate a number of simultaneous asynchronous requests. What will happen in a situation where one of the operations will be canceled, or there is an unexpected error? Code that supports such a scenario becomes unreadable, and thus - difficult in maintenance and testing. During this session we will be presenting several approaches to reactive programming, including Reactive Framework, TPL, asynchronous workflows in F # and AsyncEnumerator project.</p> <p>As usually code samples and slides are available <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=12939">here</a> and you can watch the presentation <a href="http://vimeo.com/12937473">here</a>. Enjoy!</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0tag:blogger.com,1999:blog-712077106443942647.post-44545103245135877382010-03-30T23:45:00.001-07:002010-03-30T23:45:00.968-07:00After Rx Road show<p>Last week I have finished Rx Road show. I have been giving presentations about Reactive Framework on four Polish .Net Users Groups: in <a href="http://ms-groups.pl/wroc.net/20.spotkanie/default.aspx?InstanceID=1">Wroclaw</a>, <a href="http://ms-groups.pl/lodz/Lists/Kalendarz/DispForm.aspx?ID=57&Source=http%3A%2F%2Fms%2Dgroups%2Epl%2Flodz%2FLists%2FKalendarz%2Fcalendar%2Easpx">Lodz</a>, <a href="http://ms-groups.pl/kgd.net/55_spotkanie/pages/Prezentacje.aspx">Krakow</a> and <a href="http://ms-groups.pl/slaskagrupa/Lists/Kalendarium/DispForm.aspx?ID=46&Source=http%3A%2F%2Fms%2Dgroups%2Epl%2Fslaskagrupa%2FLists%2FKalendarium%2FAllItems%2Easpx">Chorzow</a>. Thank you all for coming to my session and filling the evaluations, I hope you have learned something useful about Rx during the session. I have also good news for those of you who were interested in my presentation but for some reason couldn’t come, one of the presentation has been recorded and it is now available for download or watching live online <a href="http://www.vimeo.com/10529774">here</a>. Slides and all code samples can be download from <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=9524">here</a>. Enjoy!</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com12tag:blogger.com,1999:blog-712077106443942647.post-52591801897120341552010-03-08T13:46:00.001-08:002011-05-06T06:12:04.507-07:00RxSandbox V1<p><font color="#ff0000">[<a href="http://mnajder.blogspot.com/2011/05/rx-projects-update.html">New version</a> (2011.05.06)]</font></p> <p><font color="#ff0000">[RxSandbox downlaod has been upgraded to the newest version of Rx (Build 1.0.2677.0 08/27/2010).] <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=13718">download</a> </font></p> <p><font color="#ff0000">[RxSandbox downlaod has been upgraded to the newest version of Rx (Build 1.0.2617.0 07/15/2010).] <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=13676">download</a> <br />(Changes: solution converted to VS2010, Net 4.0; 56 operators, grouping operators on the tree control; zoom)</font></p> <p><font color="#ff0000">[RxSandbox downlaod has been upgraded to the newest version of Rx (Build 1.0.2441.0 04/14/2010).] <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=10232">download</a></font></p> <p><font color="#ff0000">[RxSandbox downlaod has been upgraded to the newest version of Rx (Build 1.0.2350.0 03/15/2010).] <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=9324">download</a></font></p> <p>I am really happy to announce that the new version of RxSandbox has been just released. <a href="http://mnajder.blogspot.com/2009/11/rxsandbox.html">Last time</a><u> </u>I have been writing about the concept and the main ideas behind the project. That was just a small prototype, the proof of concept. This release is much more mature, the user can test more standard Rx operators and the API has been changed a little bit, however the concept stated the same. </p> <p>These are the main new features:</p> <ul> <li>Marble diagrams </li> <li>New powerful API </li> <li>Extensibility mechanism </li> <li>Description of Rx the operators taken from Rx documentation </li> </ul> <p>Lets start from the the end-user which is not necessary interested in writing any code. He just wants to experiment with Rx operators, check how they behave in specific scenarios. When we start RxSandbox application we will see the list of standard operators on the left hand side. Lets assume that we don’t know how Merge operator works. After double click on the Merge node the new tab will be displayed. We can find the short description of Merge operator taken from documentation provided by Rx installer, we can also find the code sample that can be tested interactively trough UI. Each input argument is presented as a simple automatically generated UI with one textbox where we can write input value, tree buttons and the history of the source. The output of the expression can be presented in two ways: by a simple list displaying the results (“Output” tab) or the marble diagrams drawn live during testing (‘Marble diagram – Live” tab). There is also one tab called “Marble diagram - Definition” showing the operator definition.</p> <p><a href="http://lh3.ggpht.com/_o4bEwho21rA/S5VwMTywnvI/AAAAAAAAAEg/H8osSgs2-jk/s1600-h/image4%5B1%5D.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_o4bEwho21rA/S5VwNVHeA4I/AAAAAAAAAEk/ACuZqP5WrEQ/image_thumb1.png?imgmax=800" width="524" height="405" /></a> </p> <p>Now lets see what the developer can do with RxSandbox. The most important class in Rx API is the ExpressionDefinition. It holds all necessary information describing tested expression such as name, description and sample code.</p> <p><a href="http://lh5.ggpht.com/_o4bEwho21rA/S5VwN50w55I/AAAAAAAAAEo/5VMbrr7DdgM/s1600-h/image17.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_o4bEwho21rA/S5VwOYpf4NI/AAAAAAAAAEs/YDBvaqV6kg4/image_thumb9.png?imgmax=800" width="616" height="341" /></a> </p> <p>When we look inside RxSandbox project we will see that the definitions of all standard operators are very similar, for example the Merge operator is defined like this:</p> <div> <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> ExpressionDefinition Merge()
{
Expression<Func<IObservable<<span style="color: #0000ff">string</span>>, IObservable<<span style="color: #0000ff">string</span>>, IObservable<<span style="color: #0000ff">string</span>>,
IObservable<<span style="color: #0000ff">string</span>>>> expression
= (a, b, c) => Observable.Merge(a, b, c);
<span style="color: #0000ff">return</span> ExpressionDefinition.Create(expression);
}</pre>
</div>
<p>This is all we need to write. Other things like operator’s name, description and the text of expression can be inferred from the Linq expression. Of course all these information can be set manually using appropriate Create method overload and ExpressionSettings class. All .Net types are supported as observable type, not only the System.String type like in this example. The only requirement is there must exist a <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter(VS.71).aspx">TypeConverter</a> for that type. Later in this post I’ll how implement TypeConverter for custom type and how to create ExpressionDefinition without using Linq expression but using the whole method with many statements. The second very important class in RxSandbox API is an ExpressionInstance class which is very useful in scenarios where we want to use some RxSandbox functionalities directly from code without any UI experience (for example during writing Unit Tests or recording marble diagram).</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">Expression<Func<IObservable<<span style="color: #0000ff">string</span>>, IObservable<<span style="color: #0000ff">string</span>>, IObservable<<span style="color: #0000ff">string</span>>,
IObservable<<span style="color: #0000ff">string</span>>>> expression
= (a, b, c) => Observable.Merge(a, b, c);
ExpressionDefinition definition = ExpressionDefinition.Create(expression);
<span style="color: #0000ff">using</span> (var instance = ExpressionInstance.Create(definition))
{
ExpressionInstance instance = ExpressionInstance.Create(definition);
<span style="color: #008000">// using non-generic type 'ObservableSource'</span>
ObservableSource output1 = instance.Output;
output1.ObservableStr.Subscribe(Console.WriteLine);
<span style="color: #008000">// using generic type 'ObservableSource<T>'</span>
ObservableOutput<<span style="color: #0000ff">string</span>> output2 = instance.Output <span style="color: #0000ff">as</span> ObservableOutput<<span style="color: #0000ff">string</span>>;
output2.Observable.Subscribe(Console.WriteLine);
instance[<span style="color: #006080">"a"</span>].OnNext(<span style="color: #006080">"one"</span>); <span style="color: #008000">// using non-generic type 'ObservableInput'</span>
(instance[<span style="color: #006080">"a"</span>] <span style="color: #0000ff">as</span> ObservableInput<<span style="color: #0000ff">string</span>>).OnNext(<span style="color: #006080">"two"</span>); <span style="color: #008000">// using generic type</span>
instance[<span style="color: #006080">"b"</span>].OnNext(<span style="color: #006080">"tree"</span>);
instance[<span style="color: #006080">"a"</span>].OnCompleted();
instance[<span style="color: #006080">"b"</span>].OnCompleted();
instance[<span style="color: #006080">"c"</span>].OnCompleted();
}</pre>
</div>
<p>When we add delay before sending each input signal we can very easily record sample marble diagram.</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">internal</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> Extensions
{
<span style="color: #0000ff">internal</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> OnNext2(<span style="color: #0000ff">this</span> ObservableInput input, <span style="color: #0000ff">string</span> <span style="color: #0000ff">value</span>)
{
input.OnNext(<span style="color: #0000ff">value</span>);
Thread.Sleep(100);
}
<span style="color: #0000ff">internal</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> OnError2(<span style="color: #0000ff">this</span> ObservableInput input)
{
input.OnError(<span style="color: #0000ff">new</span> Exception());
Thread.Sleep(100);
}
<span style="color: #0000ff">internal</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> OnCompleted2(<span style="color: #0000ff">this</span> ObservableInput input)
{
input.OnCompleted();
Thread.Sleep(100);
}
}</pre>
</div>
<p>Marble diagrams are described in a very simple object model.</p>
<p><a href="http://lh4.ggpht.com/_o4bEwho21rA/S5VwO4GLaaI/AAAAAAAAAEw/GgnAhmf2bFg/s1600-h/image12.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_o4bEwho21rA/S5VwPfbvNKI/AAAAAAAAAE0/YCCi0TxsoBw/image_thumb6.png?imgmax=800" width="544" height="222" /></a> </p>
<p>This object model can be serialized to Xml format, for instance the code above creates fallowing marble diagram:</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff"><</span><span style="color: #800000">Diagram</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Input</span> <span style="color: #ff0000">Name</span><span style="color: #0000ff">="a"</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Marble</span> <span style="color: #ff0000">Value</span><span style="color: #0000ff">="one"</span> <span style="color: #ff0000">Order</span><span style="color: #0000ff">="0"</span> <span style="color: #0000ff">/></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Marble</span> <span style="color: #ff0000">Value</span><span style="color: #0000ff">="two"</span> <span style="color: #ff0000">Order</span><span style="color: #0000ff">="1"</span> <span style="color: #0000ff">/></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Marble</span> <span style="color: #ff0000">Kind</span><span style="color: #0000ff">="OnCompleted"</span> <span style="color: #ff0000">Order</span><span style="color: #0000ff">="3"</span> <span style="color: #0000ff">/></span>
<span style="color: #0000ff"></</span><span style="color: #800000">Input</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Input</span> <span style="color: #ff0000">Name</span><span style="color: #0000ff">="b"</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Marble</span> <span style="color: #ff0000">Value</span><span style="color: #0000ff">="tree"</span> <span style="color: #ff0000">Order</span><span style="color: #0000ff">="2"</span> <span style="color: #0000ff">/></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Marble</span> <span style="color: #ff0000">Kind</span><span style="color: #0000ff">="OnCompleted"</span> <span style="color: #ff0000">Order</span><span style="color: #0000ff">="4"</span> <span style="color: #0000ff">/></span>
<span style="color: #0000ff"></</span><span style="color: #800000">Input</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Input</span> <span style="color: #ff0000">Name</span><span style="color: #0000ff">="c"</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Marble</span> <span style="color: #ff0000">Kind</span><span style="color: #0000ff">="OnCompleted"</span> <span style="color: #ff0000">Order</span><span style="color: #0000ff">="5"</span> <span style="color: #0000ff">/></span>
<span style="color: #0000ff"></</span><span style="color: #800000">Input</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Output</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Marble</span> <span style="color: #ff0000">Value</span><span style="color: #0000ff">="one"</span> <span style="color: #ff0000">Order</span><span style="color: #0000ff">="0"</span> <span style="color: #0000ff">/></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Marble</span> <span style="color: #ff0000">Value</span><span style="color: #0000ff">="two"</span> <span style="color: #ff0000">Order</span><span style="color: #0000ff">="1"</span> <span style="color: #0000ff">/></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Marble</span> <span style="color: #ff0000">Value</span><span style="color: #0000ff">="tree"</span> <span style="color: #ff0000">Order</span><span style="color: #0000ff">="2"</span> <span style="color: #0000ff">/></span>
<span style="color: #0000ff"><</span><span style="color: #800000">Marble</span> <span style="color: #ff0000">Kind</span><span style="color: #0000ff">="OnCompleted"</span> <span style="color: #ff0000">Order</span><span style="color: #0000ff">="5"</span> <span style="color: #0000ff">/></span>
<span style="color: #0000ff"></</span><span style="color: #800000">Output</span><span style="color: #0000ff">></span>
<span style="color: #0000ff"></</span><span style="color: #800000">Diagram</span><span style="color: #0000ff">></span></pre>
</div>
<p><a href="http://lh5.ggpht.com/_o4bEwho21rA/S5VwP9CY6qI/AAAAAAAAAE4/kfO6kZPiWLA/s1600-h/image4.png"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_o4bEwho21rA/S5VwQaFzRiI/AAAAAAAAAE8/-o3-BiH2Agw/image_thumb11.png?imgmax=800" width="349" height="142" /></a> </p>
<p>As we can see single marble diagram have a very simple Xml representation and diagrams for all standard operators from RxSandbox are stored in Diagrams.xml file (this file path can be changed in the configuration files).</p>
<p>Short description added to all standard operators extracted from Rx documentation Xml file is a next new feature of current release. Of course not all tested reactive expression are related to one particular operator so the description can be set manually (ExpressionSettings.Description property). When we want write a very complicated Linq expression or the expression is passed as delegate type to the ExpressionDefinition.Create method and we also want to provide description from particular Rx operator at the same time, we can do it indicating operator thought MethodInfo type (ExpressionSettings.Operator property).</p>
<p>The last but not least new feature is the extensibility mechanism. When we want to write our custom reactive expression without changing anything inside RxSadbox project we can do it by implementing IExpressionProvider interface directly or by inheriting from an abstract class ExpressionAttributeBasedProvider and setting our assembly name in the configuration file (ExtensionsAssembly element). During startup process RxSandbox loads that assembly, analyzes it and finds all expression providers. <a href="http://mnajder.blogspot.com/2009/08/incremental-find-with-reactive.html">Few weeks ago</a> I have been writing about Incremental Find implemented using Rx, lets see how such a query can tested via RxSandbox. </p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">[AttributeUsage(AttributeTargets.Method,AllowMultiple = <span style="color: #0000ff">false</span>, Inherited = <span style="color: #0000ff">true</span>)]
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> ExpressionAttribute : Attribute { }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span> IExpressionProvider
{
IEnumerable<ExpressionDefinition> GetExpressions();
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">abstract</span> <span style="color: #0000ff">class</span> ExpressionAttributeBasedProvider : IExpressionProvider
{
<span style="color: #0000ff">public</span> IEnumerable<ExpressionDefinition> GetExpressions()
{
var q =
from m <span style="color: #0000ff">in</span> <span style="color: #0000ff">this</span>.GetType().GetMethods()
let attr = Attribute.GetCustomAttribute(m, <span style="color: #0000ff">typeof</span>(ExpressionAttribute))
<span style="color: #0000ff">as</span> ExpressionAttribute
<span style="color: #0000ff">where</span> attr != <span style="color: #0000ff">null</span>
select m.Invoke(<span style="color: #0000ff">null</span>, <span style="color: #0000ff">null</span>) <span style="color: #0000ff">as</span> ExpressionDefinition;
<span style="color: #0000ff">return</span> q.ToList();
}
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> CustomExpressions : ExpressionAttributeBasedProvider
{
[Expression]
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> ExpressionDefinition IncrementalSearch()
{
Func<IObservable<<span style="color: #0000ff">string</span>>, IObservable<Person>, IObservable<Person>> expression
= (codeChanged, webServiceCall) =>
{
var q =
from code <span style="color: #0000ff">in</span> codeChanged
from x <span style="color: #0000ff">in</span> Observable.Return(<span style="color: #0000ff">new</span> Unit())
.Delay(TimeSpan.FromSeconds(4)).TakeUntil(codeChanged)
from result <span style="color: #0000ff">in</span> webServiceCall.TakeUntil(codeChanged)
select result;
<span style="color: #0000ff">return</span> q;
};
<span style="color: #0000ff">return</span> ExpressionDefinition.Create(expression, <span style="color: #0000ff">new</span> ExpressionSettings
{
Name = <span style="color: #006080">"Incremental find"</span>,
Description = <span style="color: #006080">@"Send the code of the person you are looking for, "</span>
+ <span style="color: #006080">"after four seconds (if you don't send new code again) web service "</span>
+ <span style="color: #006080">"will be called. The result won't be returned if new code is provided "</span>
+ <span style="color: #006080">"in the meantime."</span>,
});
}
}
[TypeConverter(<span style="color: #0000ff">typeof</span>(PersonConverter))]
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Person
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Code { get; set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> Name { get; set; }
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> PersonConverter : TypeConverter
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">bool</span> CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
<span style="color: #0000ff">if</span> (sourceType == <span style="color: #0000ff">typeof</span> (<span style="color: #0000ff">string</span>))
<span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;
<span style="color: #0000ff">return</span> <span style="color: #0000ff">base</span>.CanConvertFrom(context, sourceType);
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">object</span> ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, <span style="color: #0000ff">object</span> <span style="color: #0000ff">value</span>)
{
<span style="color: #0000ff">if</span> (<span style="color: #0000ff">value</span> <span style="color: #0000ff">is</span> <span style="color: #0000ff">string</span>)
{
<span style="color: #0000ff">string</span>[] v = ((<span style="color: #0000ff">string</span>)<span style="color: #0000ff">value</span>).Split(<span style="color: #0000ff">new</span>[] { <span style="color: #006080">','</span> });
<span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Person {Code = v[0], Name = v[1]};
}
<span style="color: #0000ff">return</span> <span style="color: #0000ff">base</span>.ConvertFrom(context, culture, <span style="color: #0000ff">value</span>);
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">object</span> ConvertTo(ITypeDescriptorContext context,
CultureInfo culture, <span style="color: #0000ff">object</span> <span style="color: #0000ff">value</span>, Type destinationType)
{
<span style="color: #0000ff">if</span> (destinationType == <span style="color: #0000ff">typeof</span> (<span style="color: #0000ff">string</span>))
{
var person = <span style="color: #0000ff">value</span> <span style="color: #0000ff">as</span> Person;
<span style="color: #0000ff">return</span> person.Code + <span style="color: #006080">","</span> + person.Name;
}
<span style="color: #0000ff">return</span> <span style="color: #0000ff">base</span>.ConvertTo(context, culture, <span style="color: #0000ff">value</span>, destinationType);
}
}</pre>
</div>
<p>So that’s it for this release of RxSandbox. I encourage you to play with it a little bit and let me know what you think.</p>
<p>And that’s not the end of the project. In upcoming releases I plan to:</p>
<ul>
<li>create Silverlight version with ability to write reactive expression directly in the web browser </li>
<li>add integration with MEF </li>
<li>add better look and feel experience </li>
</ul>
<p>Here you can <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=9324">download</a> sources and binaries</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com11tag:blogger.com,1999:blog-712077106443942647.post-31518559082672448362009-11-26T12:58:00.001-08:002009-11-26T12:58:29.583-08:00After Microsoft Technology Summit 2009<p>I would like to thank all of the attendees who came to my session - "Workflow Foundation 4.0" on the <a href="http://mts2009.pl/">MTS2009</a> conference. Thanks for all evaluations and comments! The videos from the conference has just been published. <a href="http://mts2009.pl/rejestracja/webcast.aspx?id=63">Here</a> is my webcast presentation (polish version).</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com2tag:blogger.com,1999:blog-712077106443942647.post-32546450569277655052009-11-26T06:44:00.001-08:002010-03-16T00:07:37.350-07:00RxSandbox<p>Rx is awesome :)</p> <p>I have just started a new project called RxSandbox. It will be a very simple application that help to understand how Rx works, how each operator is implemented. But lets start from the beginning. Few days ago I was playing with Rx operators such as Zip, Merge, Wait, etc. writing a very short chunk of code for each operator. I was wondering how do they work in details, if they cache the values from sources, when exactly is OnCompleted executed on the observers and so on. The code could look like this:</p> <div> <pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">a.Zip(b, (x, y) => x + <span style="color: #006080">" - "</span> + y)</pre>
</div>
<p>I wanted to a and b be the implementation of IObservable<string>. But what is the easiest way to create the implementation for them? I just wanted to be focused on writing code using operators so I needed some infrastructure for creating sample observable data sources. The RxSandbox is the solution! When you write something like this:</p>
<div>
<pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">Expression<Func<ManualObservable<<span style="color: #0000ff">string</span>>, ManualObservable<<span style="color: #0000ff">string</span>>,
IObservable<<span style="color: #0000ff">string</span>>>> zipExpression
= (a, b) => a.Zip(b, (x, y) => x + <span style="color: #006080">" - "</span> + y);
Control control = RxExpressionVisualizer.CreateControl(zipExpression);</pre>
</div>
<p>RxSandbox will automatically generate testing UI control:</p>
<p><a href="http://lh4.ggpht.com/_o4bEwho21rA/Sw6UNH7FYSI/AAAAAAAAACo/Oco-BCzbbww/s1600-h/image3.png"><img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="image" src="http://lh6.ggpht.com/_o4bEwho21rA/Sw6UOi-lEBI/AAAAAAAAACs/f5JMkfW1icg/image_thumb1.png?imgmax=800" width="428" height="255" /></a> </p>
<p>In the code above ManualObservable means that the user can manually define the values sent to the expression by writing them in a text box. Other possible could be RandomObservable, IntervalObservable and there are many more options. The UI control will be different for each type of Observable source. The only reason why the Expression<Func<...>> type has been used here is that this allows us to display the body of expression, but of course this is just an option. In general, the test case is a method taking some Observable sources and returning observable collection. It can be some really complicated code snippet with many statements as well.</p>
<p>Possible scenarios working with RxSanbox:</p>
<ul>
<li>Run RxSandbox application, create new project in VS, write Rx expression, compile it, RxSandbox automatically  finds new version of dll file and loads it, you are ready to test it (it may be <a href="http://msdn.microsoft.com/en-us/library/dd460648(VS.100).aspx">MEF</a>, VS AddIn not just of stand along application) </li>
<li>Run RxSandbox, write your Rx expression inside RxSandbox, start testing it (the easy way to do this is to use <a href="http://msdn.microsoft.com/en-us/library/system.activities.design.view.expressiontextbox(VS.100).aspx">ExpressionTextBox</a> control from WF4.0 which allows us to write single VB expression and expose it as an Linq expression type) </li>
<li>Drawing marble diagrams live during testing and also presenting the definitions of the operators as marble diagrams (of course with pac-mans and hearts :) - ) </li>
<li>Supporting Silverlight version </li>
<li>Many many more....</li>
</ul>
<p>I hope you got the idea. <a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=8410">Here</a> you can find the first prototype.</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com3tag:blogger.com,1999:blog-712077106443942647.post-37610917332867848232009-11-20T05:26:00.001-08:002009-11-20T05:26:32.739-08:00Puzzle<p>What will be displayed on the screen when we write it (and why) ?</p> <div><pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">Action<<span style="color: #0000ff">string</span>> a = Console.WriteLine;
var b = a;
var c = (a += Console.WriteLine);
a(<span style="color: #006080">"Rx"</span>);
b(<span style="color: #006080">"rulez"</span>);
c(<span style="color: #006080">"!"</span>);</pre></div>
<p>Hint: delegate type is:<br>- reference type<br>- immutable type</p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0tag:blogger.com,1999:blog-712077106443942647.post-10584047554583115372009-11-12T22:50:00.001-08:002009-11-12T22:50:38.324-08:00Linq to ICollectionView<p></p> <p>Currently I'm working on the project written in Silverlight and I have encountered an interface called <a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.icollectionview(VS.95).aspx">ICollectionView</a> and its standard implementation <a href="http://msdn.microsoft.com/en-us/library/system.windows.data.pagedcollectionview(VS.95).aspx">PagedCollectionView</a>. In short, this components allow us to create the view of collection of items with filtering, grouping and sorting functionality. The idea behind this interface is very similar to <a href="http://msdn.microsoft.com/en-us/library/system.data.dataview.aspx">DataView</a>/DataTable mechanism. DataTable is responsible for storing data and DataView is just an appropriately configured proxy (only filtering and sorting in this case) which can be bound to UI controls. Let's look at a very simple example:</p> <div><pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Number
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span> Value { get; set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span> Random { get; set; }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Number[] GetAll()
{
var random = <span style="color: #0000ff">new</span> Random();
<span style="color: #0000ff">return</span>
(from n <span style="color: #0000ff">in</span> Enumerable.Range(1,5)
from m <span style="color: #0000ff">in</span> Enumerable.Repeat(n, n)
select <span style="color: #0000ff">new</span> Number {Value = n, Random = random.Next(10)}).ToArray();
}
}
<span style="color: #008000">// Silverlight</span>
<span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> LinqToICollectionView : UserControl
{
<span style="color: #0000ff">public</span> LinqToICollectionView()
{
Number[] numbers = Number.GetAll();
Content = <span style="color: #0000ff">new</span> StackPanel
{
Orientation = Orientation.Horizontal,
Children =
{
<span style="color: #0000ff">new</span> DataGrid { ItemsSource = <span style="color: #0000ff">new</span> PagedCollectionView(numbers).SetConfiguration()},
}
};
}
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> Configurator
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> ICollectionView SetConfiguration(<span style="color: #0000ff">this</span> ICollectionView view)
{
<span style="color: #008000">// filtering</span>
view.Filter = (<span style="color: #0000ff">object</span> o) => ((Number)o).Value < 5;
<span style="color: #008000">// grouping</span>
view.GroupDescriptions.Add(<span style="color: #0000ff">new</span> PropertyGroupDescription(<span style="color: #006080">"Value"</span>));
<span style="color: #008000">// sorting</span>
view.SortDescriptions.Add(<span style="color: #0000ff">new</span> SortDescription(<span style="color: #006080">"Value"</span>, ListSortDirection.Descending));
view.SortDescriptions.Add(<span style="color: #0000ff">new</span> SortDescription(<span style="color: #006080">"Random"</span>, ListSortDirection.Ascending));
<span style="color: #0000ff">return</span> view;
}
}</pre></div>
<p><a href="http://lh4.ggpht.com/_o4bEwho21rA/Sv0BumJMmdI/AAAAAAAAACg/reGHKQ0TugM/s1600-h/image4.png"><img style="border-right-width: 0px; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" border="0" alt="image" src="http://lh5.ggpht.com/_o4bEwho21rA/Sv0BvOL3_UI/AAAAAAAAACk/oG8sQRtAbqg/image_thumb1.png?imgmax=800" width="117" height="286"></a> </p>
<p>But wait a minute, we said ... filtering, ordering, grouping ? Let's use LINQ query to configure ICollectionView:</p>
<div><pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> Configurator
{
<span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> ICollectionView SetConfigurationWithLinq(<span style="color: #0000ff">this</span> ICollectionView view)
{
var q =
from n <span style="color: #0000ff">in</span> <span style="color: #0000ff">new</span> View<Number>()
<span style="color: #0000ff">where</span> n.Value < 5
orderby n.Value descending, n.Random
group n by n.Value;
q.Apply(view);
<span style="color: #0000ff">return</span> view;
}
}</pre></div>
<p>The whole implementation consists of 3 simple classes: View<T>, OrderedView<T> and GroupedView<T>.</p>
<div><pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> View<T>
{
<span style="color: #0000ff">public</span> IEnumerable<GroupDescription> GroupDescriptions { get { ... } }
<span style="color: #0000ff">public</span> IEnumerable<SortDescription> SortDescriptions { get { ... } }
<span style="color: #0000ff">public</span> Func<T,<span style="color: #0000ff">bool</span>> Filter { get { ... } }
<span style="color: #0000ff">public</span> View<T> Where(Func<T, <span style="color: #0000ff">bool</span>> func) { ... }
<span style="color: #0000ff">public</span> SortedView<T> OrderBy<T2>(Expression<Func<T, T2>> func) { ... }
<span style="color: #0000ff">public</span> SortedView<T> OrderByDescending<T2>(Expression<Func<T, T2>> func) { ... }
<span style="color: #0000ff">public</span> GroupedView<T> GroupBy<T2>(Expression<Func<T, T2>> func) { ... }
<span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Apply(ICollectionView collectionView) { ... }
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">sealed</span> <span style="color: #0000ff">class</span> SortedView<T> : View<T>
{
<span style="color: #0000ff">public</span> SortedView<T> ThenBy<T2>(Expression<Func<T, T2>> func) { ... }
<span style="color: #0000ff">public</span> SortedView<T> ThenByDescending<T2>(Expression<Func<T, T2>> func) { ... }
}
<span style="color: #0000ff">public</span> <span style="color: #0000ff">sealed</span> <span style="color: #0000ff">class</span> GroupedView<T> : View<T>
{
<span style="color: #0000ff">public</span> GroupedView<T> ThenBy<T2>(Expression<Func<T, T2>> func) { ... }
}</pre></div>
<p>Methods for sorting and grouping which take an expression tree as a parameter analyze the tree looking for indicated members (fields or properties) and collect appropriate SortDescription and GroupDescription objects. <strong>Where</strong> method takes a delegate type which is combined via logical <strong>and</strong> operator with existing filter delegate set previously (in case when Where method is called many times). Of course the same mechanism work also in WPF.</p>
<div><pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">Number[] numbers = Number.GetAll();
<span style="color: #008000">// WPF</span>
<span style="color: #0000ff">new</span> Window
{
Content = <span style="color: #0000ff">new</span> StackPanel
{
Orientation = Orientation.Horizontal,
Children =
{
CreateListView(<span style="color: #0000ff">new</span> CollectionViewSource { Source = numbers }.View.SetConfiguration()),
CreateListView(<span style="color: #0000ff">new</span> CollectionViewSource { Source = numbers }.View.SetConfigurationWithLinq())
}
}
}
.ShowDialog();
<span style="color: #0000ff">private</span> <span style="color: #0000ff">static</span> ListView CreateListView(ICollectionView view)
{
<span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> ListView
{
GroupStyle = { GroupStyle.Default },
View = <span style="color: #0000ff">new</span> GridView
{
Columns =
{
<span style="color: #0000ff">new</span> GridViewColumn { Header = <span style="color: #006080">"Value"</span>, DisplayMemberBinding = <span style="color: #0000ff">new</span> Binding(<span style="color: #006080">"Value"</span>) },
<span style="color: #0000ff">new</span> GridViewColumn { Header = <span style="color: #006080">"Random"</span>, DisplayMemberBinding = <span style="color: #0000ff">new</span> Binding(<span style="color: #006080">"Random"</span>) },
}
},
ItemsSource = view
};
}</pre></div>
<p>At the end I'd like to mention one interesting thing. We only support filtering, sorting and grouping and don't support for instance projection, joining and so on. That's way this code should compile:</p>
<div><pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">var v1 = <span style="color: #008000">// only filtering specified</span>
from n <span style="color: #0000ff">in</span> <span style="color: #0000ff">new</span> View<Number>()
<span style="color: #0000ff">where</span> n.Value < 5
select n;
var v2 = <span style="color: #008000">// grouping (last grouping definition overrides previous ones)</span>
from n <span style="color: #0000ff">in</span> <span style="color: #0000ff">new</span> View<Number>()
group n by n.Random into s
group s by s.Value;
</pre></div>
<p>but this will not:</p>
<div><pre style="border-bottom-style: none; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: consolas, 'Courier New', courier, monospace; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">var v3 = <span style="color: #008000">// joining is not supported</span>
from p <span style="color: #0000ff">in</span> <span style="color: #0000ff">new</span> View<Number>()
join pp <span style="color: #0000ff">in</span> <span style="color: #0000ff">new</span>[] { 1, 2, 3, 4 } on p.Random equals pp
select p;
var v4 = <span style="color: #008000">// projection is not supported</span>
from p <span style="color: #0000ff">in</span> <span style="color: #0000ff">new</span> View<Number>()
<span style="color: #0000ff">where</span> p.Value > 5
select p.Random;
var v5 = <span style="color: #008000">// at least one filtering, grouping or sorting definition must be specified</span>
from p <span style="color: #0000ff">in</span> <span style="color: #0000ff">new</span> View<Number>()
select p;
var v6 = <span style="color: #008000">// Numer type is the only valid type of grouped element</span>
from p <span style="color: #0000ff">in</span> <span style="color: #0000ff">new</span> View<Number>()
group p.Random by p.Value;</pre></div>
<p>As a homework I leave you a question: why it works this way ? :)</p>
<p><a href="http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=mnajder&DownloadId=8219">Sources</a></p> Marcin Najderhttp://www.blogger.com/profile/11205707928830073432noreply@blogger.com0