{"id":1335,"date":"2012-05-15T00:00:00","date_gmt":"2012-05-15T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/c-async-what-is-it-and-how-does-it-work\/"},"modified":"2021-05-11T15:56:21","modified_gmt":"2021-05-11T15:56:21","slug":"c-async-what-is-it-and-how-does-it-work","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/dotnet-development\/c-async-what-is-it-and-how-does-it-work\/","title":{"rendered":"C# Async: What is it, and how does it work?"},"content":{"rendered":"<div id=\"pretty\">\n<h2>Solving a problem<\/h2>\n<p class=\"start\">The much-anticipated Async feature is designed to solve a problem that every developer has run into when writing a GUI application, the GUI locking &amp; freezing. Most windowing libraries avoid the need to take locks by having all of the GUI code run on a single thread, with this thread using some kind of mailbox to prevent asynchronous message arrival. <\/p>\n<p>We obviously want to prevent asynchronous message arrival because, when the string of a TextBox is being updated to &#8220;fred&#8221;, we don&#8217;t want to get a message telling us to update it to &#8220;joe&#8221; while we are still in the middle of processing the change to &#8220;fred&#8221;. The key to this enforcement of linear processing is that the GUI is only going to respond to user interaction if the single GUI-owned thread is available to do processing of incoming events. If we need to do a blocking operation, such as hitting a web service, and we do it on the GUI-owned thread, then the GUI is going to feel dead, with screen updates and actions not having any effect until the blocking operation finishes. <\/p>\n<p>This is unacceptable, particularly on touch controlled devices, where the feedback has to be quick if it is&#160; to be effective. Visiting some sites on my iPhone&#8217;s web browser can be painful, as I often touch to cause some kind of action, but then find that Safari is still busy processing the page. Frustratingly, this leaves me in a state where I don&#8217;t know if Safari is going to do something when it gets less busy, or whether my earlier interaction has just been ignored. WinRT is going to be designed for touch from day one, and its designers have apparently paid careful attention to existing touch Operating Systems, and learned some valuable lessons. As a result, WinRT requires all operations that are going to take more than 50 milliseconds to offer an asynchronous version (and, in lots of cases, only an asynchronous version), as a means of keeping the user experience of Metro applications slick and intuitive. The question then becomes how to make it easy for developers to use this new functionality.<\/p>\n<h2>New tricks<\/h2>\n<p>In the past we&#8217;ve been able to defer work to a later point in time by capturing the context as a closure, passing this closure to some object that is responsible for doing the wait, and then having that closure called when the code should continue running. This continuation-passing style makes the code very complicated to read, and makes it very hard to follow the control flow of the code. <\/p>\n<p>Let&#8217;s take a look at an example of this using a very simplistic example. Suppose we want to read two strings from the Console, and write their total length in characters to the Console. If at any point a blank line is entered, then we don&#8217;t want to read any more data, but we still want to print the total number of characters:<\/p>\n<pre class=\"lang:c# theme:vs2012\">&#160;&#160;&#160;&#160;&#160;&#160; int totalCharacters = 0;\n&#160;&#160;&#160;&#160;&#160;&#160; string input = Console.ReadLine();\n&#160;&#160;&#160;&#160;&#160;&#160; if (!string.IsNullOrEmpty(input))\n&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(\"First string: {0}\", input);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; totalCharacters += input.Length;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; input = Console.ReadLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (!string.IsNullOrEmpty(input))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(\"Second string: {0}\", input);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; &#160;&#160;&#160;totalCharacters += input.Length;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(totalCharacters);\n\n<\/pre>\n<p>The trouble with the above code is that it is blocking the main thread, which doesn&#8217;t matter in this case, but would if it were an operation on the GUI. The thread also sits inside <b>Console.ReadLine<\/b>, consuming the resources that a thread requires (such as 1mb of stack space), without doing any useful work. If this was some kind of (web) server application, then this would be wasteful and would inhibit scalability. Ideally, we&#8217;d really like to record the state of the program, but then pass the thread back to the runtime, only grabbing it later when we have more work to do.<\/p>\n<p>Let&#8217;s say we were provided with some kind of asynchronous version of <b>Console.ReadLine<\/b>, such as a function of the following form, which takes responsibility for getting data from the console and then calling an action function with that data when it is available on some available thread:<\/p>\n<pre class=\"lang:c# theme:vs2012\">static void ReadLineAndThenDo(Action&lt;string&gt;action)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ThreadPool.QueueUserWorkItem(\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;delegate\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; string line = Console.ReadLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; action(line);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;});\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n<\/pre>\n<p>In that situation, it would be possible for the outer function to release the thread it is running on, knowing that the action function is going to be called on a suitable thread when the result is available.<\/p>\n<pre class=\"lang:c# theme:vs2012\">static void ReadLineAndThenDo(Action&lt;string&gt;action)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ThreadPool.QueueUserWorkItem(\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;delegate\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; string line = Console.ReadLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; action(line);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;});\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n<\/pre>\n<p>There are two different ways that you could implement the new program. You might use the continuation-passing style that we briefly mentioned earlier, using lambda expressions to capture the state of the local variables, which we can use for later parts of the computation:<\/p>\n<pre class=\"lang:c# theme:vs2012\">static void Attempt2()\n{\n&#160;&#160; int totalCharacters= 0;\n&#160;&#160;&#160;&#160;&#160;&#160;ReadLineAndThenDo(\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;input =&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;if (!string.IsNullOrEmpty(input))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(\"First string: {0}\",input);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; totalCharacters += input.Length;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ReadLineAndThenDo(\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; input2 =&gt;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (!string.IsNullOrEmpty(input2))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(\"Second string: {0}\",input2);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; totalCharacters += input2.Length;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(totalCharacters);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; });\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;});\n}\n<\/pre>\n<p>In this instance, the change has been localised to our function, but what a change it is! Every time we want to do an asynchronous call, we have had to pass in the rest of the code as a lambda expression (input =&gt; &#8230;) or (input2 =&gt; &#8230;). The indentation gets deeper and deeper, and things become very complicated if we have a loop construct of any kind in the code. The logic of the code has been obfuscated in order to fit into the programming language.<\/p>\n<p>However, if we take another look at the very first version of our string reader, we can see that there are distinct sections of code, with a new section starting each time we pass control to a <b>ReadLine<\/b>. For example, we start in state one, which does the initial setup of the local variables, and we then do a <b>ReadLine<\/b> and assume we enter state two when this has finished. As we enter state two, we know that there is new input available, and we can process this until we get to the next <b>ReadLine<\/b>, which starts state three:<\/p>\n<pre class=\"lang:c# theme:vs2012\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; \/*State 0 *\/\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; inttotalCharacters = 0;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; string input = Console.ReadLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;\/* State 1 *\/\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (!string.IsNullOrEmpty(input))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Console.WriteLine(\"First string: {0}\",input);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;totalCharacters += input.Length;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;input = Console.ReadLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;\/* State 2 *\/\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;if (!string.IsNullOrEmpty(input))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Console.WriteLine(\"Second string: {0}\",input);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;totalCharacters += input.Length;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160; \/* State 3 *\/\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(totalCharacters);\n&#160;\n<\/pre>\n<p>This feels very much like what is known as a <a href=\"http:\/\/en.wikipedia.org\/wiki\/Finite-state_machine\"><b>state machine<\/b><\/a> in Computer Science parlance, which is the second way we can implement this program. We&#8217;ve seen such implementations used before, in the compilation of iterator blocks by the C# compiler, so there is already existing compiler technology for implementing such transformations.<\/p>\n<p>We can implement the state machine using a new compiler generated class, <b>Attempt3Machine<\/b>. This will have a state variable, <b>m_State<\/b>, recording the state of the machine as one of its fields. We&#8217;ll lift the local variables of the method into the fields of the state machine (necessary because they live between the calls into our state machine), and we&#8217;ll implement the machine in a way that uses a single method to transition it from its current state to the next state. We call this method <b>MoveNext<\/b>, in the spirit of iterator blocks implementation.<\/p>\n<h2>Implementing a state machine<\/h2>\n<p>We&#8217;ll now need to change our asynchronous version of <b>ReadLine<\/b> to interact with our state machine. For the moment, the <b>ReadLine<\/b> will read a line from the Console, set this into the <b>m_Input field<\/b> which corresponds to the local variable input in the original code, and will then force the machine to make a transition:<\/p>\n<pre class=\"lang:c# theme:vs2012\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; static void ReadLineAndThenDo2(Attempt3MachinestateMachine)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ThreadPool.QueueUserWorkItem(\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;delegate\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; string line = Console.ReadLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; stateMachine.m_Input= line;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; stateMachine.MoveNext();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;});\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n<\/pre>\n<p>This then leaves us with a state machine with the following implementation:<\/p>\n<pre class=\"lang:c# theme:vs2012\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; class Attempt3Machine\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; intm_State = 0;\n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; private int m_TotalCharacters= 0;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; public string m_Input;\n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; public void MoveNext()\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;switch (m_State)\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;case 0:\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; m_State= 1;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ReadLineAndThenDo2(this);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return;\n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;case 1:\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (!string.IsNullOrEmpty(m_Input))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(\"First string: {0}\",m_Input);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; m_TotalCharacters+= m_Input.Length;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; m_State= 2;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ReadLineAndThenDo2(this);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; goto case 3;\n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;case 2:\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (!string.IsNullOrEmpty(m_Input))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(\"Second string: {0}\",m_Input);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; m_TotalCharacters+= m_Input.Length;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; goto case 3;\n&#160;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;case 3:\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(m_TotalCharacters);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; return;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n<\/pre>\n<p>And with a method that uses this of the form:<\/p>\n<pre class=\"lang:c# theme:vs2012\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; static void Attempt3()\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; new Attempt3Machine().MoveNext();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n\n<\/pre>\n<h2>Results<\/h2>\n<p>So where has this got us? Well, the translation between the code above and something that started out like the following is fairly mechanical:<\/p>\n<pre class=\"lang:c# theme:vs2012\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; int totalCharacters = 0;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; string input = await Console.ReadLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (!string.IsNullOrEmpty(input))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(\"First string: {0}\", input);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; totalCharacters += input.Length;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; input = await Console.ReadLine();\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; if (!string.IsNullOrEmpty(input))\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(\"Second string: {0}\", input);\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; totalCharacters += input.Length;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Console.WriteLine(totalCharacters);\n<\/pre>\n<p>The position of the <b>Await<\/b> expressions tells us where we need to have new states for the state machine, and we simply need to push the code in-between into the relevant state transition blocks. <\/p>\n<p>By using the <b>Await<\/b> in the above code, we have kept the code in a state where it is easy to follow the control flow, even though the method stops running at the point where the await is called.<\/p>\n<h2>Tidying up with Tasks<\/h2>\n<p>There are, of course, several loose ends to tidy up. First, it looks easy in the above code to split the code into the transitions on a line by line basis, but in reality you can put multiple <b>Await<\/b> expressions in a single statement:<\/p>\n<pre class=\"lang:c# theme:vs2012\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; int x = await f() + await g(); \n<\/pre>\n<p>This means we may need a new field location to store the result of the first <b>Await<\/b> while we are waiting for the second Await to complete. We could use several locations, or just have a single location that stores the intermediate value typed as an object, and then cast as necessary when wanting to use this value. The current semantics of await only allow a single outstanding call at any time, so we need to wait for <b>f()<\/b> to finish before<b> g()<\/b> is launched.<\/p>\n<p>If we have an Async function, then the caller needs to have something that they can use to get the value when it is finally calculated. .NET 4 included the rather brilliant <b>Task&lt;&gt; <\/b>abstraction, which reflects a computation that may still be running. A <b>Task&lt;int&gt;<\/b> object, for example, represents a calculation that may eventually return an integer. Using its Result property, a client can fish out the result value, blocking until it is available, and find out details of any exceptions that were thrown. Tasks support a number of very powerful operators, such as a <b>ContinueWith<\/b> (which allows you to schedule the execution of one task when some other task completes), and a means of waiting for one or many tasks to finish. Tasks also support a model of synchronous cancellation, with the user function being expected to regularly check for a demand for cancellation, and throwing an exception if this is required. As a result, any method that uses await must either return <b>void<\/b> or <b>Task&lt;&#8230;&gt;<\/b>.<\/p>\n<h2>Some Considerations<\/h2>\n<p>Threading always adds complication to any design, and our current example doesn&#8217;t really have a good threading model. Some operations need to be called on certain threads, so our code would really need to transition back onto one of these threads before it is called, probably by using the Post operation of the synchronization context that was active when we launched the asynchronous call. .NET also has a notion of an execution context which may need to flow across to any worker threads that are launched. We may need to capture these values when we launch a call, and then get back to the correct state before we restart in the next transition.<\/p>\n<p>Exceptions also need to handled and stored away in the <b>Task<\/b> object associated with the current method, so that callers can later get the correct details of what went wrong. If the method finishes successfully, we&#8217;re also going to need to store the result away in the task, or at least mark the task as finished if there is no return value. This will allow callers to wait on our method finishing. <\/p>\n<p>There are also several missing pieces in the story of the communication between the state machine (when it fires off the asynchronous work) and the object that is going to do the work. The example above hacked this, by having the asynchronous method we were calling (<b>DoReadLineAndThenDo<\/b>) know lots of detail about the caller, such as the field in which to write the return value. This code is obviously too specific, and is purely for demonstration purposes. We get around this by adding indirection, having the asynchronous <b>ReadLine<\/b> return a Task, and then hook an <b>OnCompletion<\/b> action to the returned task which causes the state machine to move to the next state. <\/p>\n<p>Also, the action may complete really quickly, or might even have finished already. In that case it is a real waste of effort to go through the mechanism of returning from MoveNext and then having a <b>MoveNext<\/b> transition called by an external party. We could have simply jumped to the new state in the MoveNext implementation itself, without going through the capture state and then restore process. This is handled, as we&#8217;ll see in my next blog post, by having an Awaiter pattern which includes the asynchronous object, providing a property called <b>IsCompleted<\/b> which can be used to allow the <b>MoveNext<\/b> to instantly transition to the next state. The result will be fetched using <b>GetResult<\/b>.<\/p>\n<h2>Decompiling Async Code<\/h2>\n<p>Asynchronous code is clearly incredibly useful, and remarkably cunning in its implementation.&#160; In the .NET Reflector team where I work, it has taken a lot of effort to make sure .NET Reflector can accurately decompile asynchronous code so that you can start investigating C#5 code right away.&#160; Hopefully you will then be able to see how quickly Async code can start to become convoluted, and how backtracking the various calls and state transitions in a real application poses a challenge. <\/p>\n<p>Async is remarkably cunning, and can become tortuously tricky to follow when applied in a real application, which naturally makes any decompilation a bit of a challenge. <\/p>\n<p>We&#8217;ve implemented support for the decompilation of async inside .NET Reflector, so all the code you&#8217;ll see later on in this article will be generated by Reflector, both before and after the translation phase that deals with the <b>async state machines<\/b>. <\/p>\n<div class=\"note\">\n<p class=\"note\">You need to be aware that there are several implementations of Async in the code that we&#8217;ll see, because there are different implementations of Async in the code that you find in the .NET 4.5 framework libraries compared with code that is compiled using the Dev11 C# 5 compiler.&#160; For our Reflector work we are currently working on the former, mainly because the fundamental part of the work (the processing of the state machine) is the same in both cases, and the framework libraries contain hundreds of potential test cases.<\/p>\n<\/div>\n<h2>Real code<\/h2>\n<p>If you look at the <b>ReadAsyncInternal<\/b> method in the .NET 4.5 version of <b>mscorlib<\/b>, you&#8217;ll see that it has the following code:<\/p>\n<p><a href=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-1ReadAsyncInternalBig.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-1ReadAsyncInternal_sml.png\" width=\"540\" height=\"226\" alt=\"1489-1ReadAsyncInternal_sml.png\" \/><\/a><br \/><i>Click for an enlarged version<\/i><\/p>\n<p>Remember, from our earlier example of the simple string-reader program, the compiler generates a class which implements the state machine, setting the various fields corresponding to the arguments and the local variables, which get lifted into this class. The <b>&lt;&gt;t__builder<\/b> is an instance of <b>AsyncTaskMethodBuilder<\/b>, which is used to do the plumbing between the client and the implementation of the async method, and we&#8217;ll see it used in the <b>MoveNext<\/b> method.<\/p>\n<p>The compiler-generated class has the following form: <\/p>\n<p class=\"illustration\"><a href=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-2AsyncTaskMethodBuilderBig.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-2AsyncTaskMethodBuilder_sml.png\" width=\"540\" height=\"375\" alt=\"1489-2AsyncTaskMethodBuilder_sml.png\" \/><\/a><br \/><i>Click for an enlarged version<\/i><\/p>\n<p>Notice the state value field <b>&lt;&gt;1__state<\/b>, and the field <b>&lt;&gt;4__ this<\/b> which allows access back to the original instance of <b>StreamReader<\/b> which constructed this instance of the state machine.<\/p>\n<p>For us, the really interesting part is the code in the <b>MoveNext<\/b> method:<\/p>\n<p class=\"illustration\"><a href=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-3MoveNextBig.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-3MoveNext_sml.png\" width=\"540\" height=\"444\" alt=\"1489-3MoveNext_sml.png\" \/><\/a><br \/><i>Click for an enlarged version<\/i><\/p>\n<p>The outer <b>Try<\/b> has a body that ends with the code:<\/p>\n<pre>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.&lt;&gt;l_state = -1;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.&lt;&gt;t_builder. SetResult(this. &lt;charsRead&gt;5_19);\n&#160;&#160;&#160; }\n&#160;&#160;&#160; catch (Exception exception)\n&#160;&#160;&#160; {\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.&lt;&gt;l_state = -1;\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; this.&lt;&gt;t_builder. SetException (exception);\n&#160;&#160;&#160; }\n}\n<\/pre>\n<p>Let&#8217;s take a quick walk through the implications of this.<\/p>\n<h2>Stepping through the code<\/h2>\n<p>In the exception case we set the state to -1, which is a state that causes the <b>MoveNext<\/b> to return instantly while remaining in that state. In the success case, we store the function result value using the <b>SetResult<\/b>, which ends up setting the value into the <b>Task<\/b> associated with this invocation of the method. Likewise, the <b>SetException<\/b> sets the <b>Exception<\/b> property of the <b>Task<\/b> object, taking care to specially handle the <b>OperationCanceledException<\/b>, which is used by the <b>Task<\/b> library to communicate that a synchronous cancellation request was successfully honoured. After this, anyone waiting on the <b>Task<\/b> will be notified that they can continue running via the usual implementation in the <b>Task<\/b> class.<\/p>\n<p>It&#8217;s fairly easy to follow the code around while keeping an eye on the state transitions, but the most interesting thing that happens occurs when we call out to some asynchronous method, such as in the following code fragment:<\/p>\n<p><a href=\"http:\/\/www.reflector.net\/blog\/wp-content\/uploads\/2012\/05\/5Asynchronous%20Callout.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-5Asynchronous-Callout_sml.png\" width=\"540\" height=\"291\" alt=\"1489-5Asynchronous-Callout_sml.png\" \/><\/a><\/p>\n<p>Our method is calling into the <b>ReadAsync<\/b> method:<\/p>\n<p><a href=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-6ReadAsync.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-6ReadAsync.png\" width=\"616\" height=\"85\" alt=\"1489-6ReadAsync.png\" \/><\/a><\/p>\n<p>This returns a <b>Task<\/b> which will eventually contain a count of the number of bytes read, potentially also modifying the arrays that were passed in as arguments. <\/p>\n<p>We now get a slight complication. In order to control whether the synchronization context and other information needs to be preserved, the <b>Task<\/b> is passed through the .<b>ConfigureAwait<\/b> method before its <b>GetAwaiter<\/b> is called. This result of the call to <b>GetAwaiter()<\/b> supports the <b>Await<\/b> pattern; it is expected to have certain methods implemented on it, much like an <b>Enumerable<\/b> is expected to have a <b>GetEnumerator<\/b> method. Let&#8217;s take a look at how this process can proceed.<\/p>\n<p>First we have the quick path: when <b>IsCompleted<\/b> returns true to say that the result is already available, we can jump straight to label <b>03AD<\/b>. Otherwise, things get a little more complicated: we need to save any state we&#8217;re going to need later into a field in the current object, set up the <b>OnCompleted<\/b> action of the task so that the <b>MoveNext<\/b> method is going to be called again, set the state field to the next state, and return. At some point, assuming no exceptions, we&#8217;ll be called back, the state value will ensure that we reach label <b>0390<\/b>, where we can get back the values that we saved away, and then continue to the same place that we&#8217;d have gone in the fast path. <\/p>\n<p>At that location, we&#8217;ll get the result of the asynchronous operation using <b>GetResult<\/b> and carry on as if we had been running all the time. Notice that all of the thread transitions (if any are required) are hidden away inside the object that is returned by <b>GetAwaiter<\/b>, which is responsible for getting us to the right place before it calls the delegate that was passed into <b>OnCompleted<\/b>.<\/p>\n<h2>Not one compiler, but two<\/h2>\n<p>As I mentioned earlier, part of the challenge in understand all this comes as a result that we&#8217;re targeting at least two, subtly different, compilers. Thus far we&#8217;ve been looking at the results of the compiler used to generate the .NET 4.5 framework libraries, so how does this all change if you use the compiler that ships with the latest Dev11 beta?<\/p>\n<p>First there is now an interface, <b>IAsyncStateMachine<\/b>, that constrains the interface between the state machine and the code that uses it:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-7IAsyncStateMachine.png\" width=\"423\" height=\"101\" alt=\"1489-7IAsyncStateMachine.png\" \/><\/p>\n<p>This is implemented by the compiler generated type which is now a struct instead of a class:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-8CompilerGeneratedType.png\" width=\"437\" height=\"288\" alt=\"1489-8CompilerGeneratedType.png\" \/><\/p>\n<p>The initialization code also looks a little different:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-9InitializationCode.png\" width=\"446\" height=\"189\" alt=\"1489-9InitializationCode.png\" \/><\/p>\n<p>The body of the <b>MoveNext<\/b> is still surrounded by a <b>Try Catch<\/b> block as before, though the code to fire off an asynchronous call now has slightly fewer lines to it, using the builder to do more of the work. As before, if the operation doesn&#8217;t instantly complete, the state is set, and we set up a notification from the called method so that we&#8217;ll be brought back after the operation completes. In order to do this, we need to pass in the awaiter and the state machine object by using the ref modifier on the call:<\/p>\n<p class=\"illustration\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-10Awaiter_sml.png\" width=\"540\" height=\"151\" alt=\"1489-10Awaiter_sml.png\" \/><\/p>\n<p>The idea is the same as the previous implementation, though the mechanics of capturing the relevant synchronization and execution contexts is a little different. If you want to see what I mean, take a look at the code in the <b>AsyncTaskmethodBuilder<\/b> class in <b>System.Runtime.CompilerServices<\/b> in the .NET 4.5 version of <b>mscorlib.dll<\/b>.<\/p>\n<p>By looking out for the pattern of Async code, Reflector can fold code back into the form using async\/await. So, for example, the above example will be displayed as:<\/p>\n<p><a href=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-11AsyncDecompiledBig.png\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1489-11AsyncDecompiled_sml.png\" width=\"540\" height=\"321\" alt=\"1489-11AsyncDecompiled_sml.png\" \/><\/a><br \/><i>Click for an enlarged version<\/i><\/p>\n<h2>Summary<\/h2>\n<p>Async is implemented using a compiler transform to implement code as a state machine, though this requires a few support classes in the runtime library, and that a set of methods need to be implemented on types that support asynchronous calls following the <b>Await<\/b> pattern. No changes are required to the CLR, though some support has been added inside <b>mscorlib<\/b>, and extra methods have been added to the <b>Task&lt;&#8230;&gt;<\/b> type to support the calls of the Awaiter pattern.<\/p>\n<p>From the point of view of a tool like Reflector, having the compiler do a transform, rather than implementing the feature as something built into the CLR, unsurprisingly makes life harder for a decompiler. There&#8217;s no metadata to say some set of IL instructions are here as the result of the translation of an <b>await<\/b>, so instead the decompiler needs to look for the pattern of calls that is generated by the C# compiler. This is exactly the kind of thing that is already done to recognise lambda expressions and iterator blocks, which are also implemented by the compiler rather than the CLR. Given that, as we saw in the previous post, a basic state machine can be lashed together using lambda expressions and iterator blocks, the similarities in the both the implementation and our solution are no surprise.<\/p>\n<p>Async allows you to fairly transparently run non-blocking code on a single thread, and user code looks very much like it would for a straightforward blocking implementation. In fact, you can almost write it that way first, and then change it into non-blocking code by just changing the method&#8217;s return type to <b>Type&lt;&#8230;&gt;<\/b>, marking it with async, and then using <b>await<\/b> and asynchronous versions of methods that you call.<\/p>\n<p>Naturally, it isn&#8217;t quite that simple in practice. For example, having a function return too early might not interact well with constructs such as locks and exception handlers, and potentially offers the chance of re-entrancy in cases that were previously safe. Nevertheless, async is not as opaque as perhaps it first seems, and you could learn a huge amount by using .NET Reflector to start investigating C#5 as soon as possible.<\/p>\n<div class=\"note\">\n<p class=\"note\"> \t<a href=\"http:\/\/www.red-gate.com\/labs\/ants-performance-profiler\/?utm_source=simpletalk&amp;utm_medium=article&amp;utm_campaign=antsperformanceprofiler&amp;utm_content=async-asynchowdoesitwork\"><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/1555-ANTS_60x60_Logo_CP.gif\" class=\"float-left\" alt=\"1555-ANTS_60x60_Logo_CP.gif\" \/><\/a> \tInterested in how your async code performs? The Beta release of ANTS Performance Profiler 8 adds a new async profiling mode to help you understand where applications spend their time while doing async work. <a href=\"http:\/\/www.red-gate.com\/labs\/ants-performance-profiler\/?utm_source=simpletalk&amp;utm_medium=article&amp;utm_campaign=antsperformanceprofiler&amp;utm_content=async-asynchowdoesitwork\">Try the Beta<\/a>.<\/p>\n<\/p><\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>The biggest new feature in C#5 is Async, and its associated Await (contextual) keyword. Anybody who is faced with creating Metro applications for Windows 8 is having to tackle the very different mindset of Async Programming. Clive explains what is happening under the covers and how one can investigate, using .NET Reflector.&hellip;<\/p>\n","protected":false},"author":40093,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[143538],"tags":[4143,4204,4178,4371,4885],"coauthors":[],"class_list":["post-1335","post","type-post","status-publish","format-standard","hentry","category-dotnet-development","tag-net","tag-net-tools","tag-bi","tag-c","tag-reflector"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1335","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/40093"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1335"}],"version-history":[{"count":6,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1335\/revisions"}],"predecessor-version":[{"id":90914,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1335\/revisions\/90914"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1335"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1335"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1335"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1335"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}