Going Interactive with C#

For some time now, C# programmers have gazed enviously at the interactive capabilities of F#, Python and PowerShell. For rapid prototyping work and interactive debugging, dynamic languages are hard to beat. C# Interactive slipped into view quietly, without razzmatazz, in Visual Studio 2015 Update 1. It's good, it's worth knowing about; and Tom Fischer is intent on convincing you of that.

It became easier to explore both C# code snippets and APIs with the release of Visual Studio 2015 C# Interactive, which arrived with Update 1. If you think that it is just a scripting utility then it is likely that you are missing out on a valuable way of becoming more productive as a developer.

It might be more accurate to classify it as C# REPL tool with scripting support. As such, it has obvious value as a great time-saver. Within a REPL environment, C# developers can rapidly do such things as code prototypes, explore unfamiliar data, learn APIs and write complex tests. Readers who are familiar with languages such as F#, PowerShell and Python, already enjoy such capabilities. It’s now available to the C# developer as well.

This article introduces C# Interactive and aims to show how it can boost any C# developer’s productivity.

The Basics

Before showing how developers can take full advantage of C# Interactive, I must first cover some of the basics of getting started with C# Interactive, just in case you are new to it.

Getting Started

C# Interactive is new to Visual Studio 2015 with Update 1. The feature can be loaded either through the Developer Command Prompt for VS2015 command line and executing csi.exe, or from within the Visual Studio IDE via the menu sequence ‘View | Other Windows | C# Interactive’ as pictured below.

Because the Window version of C# Interactive has IntelliSense, this may be more suitable for you than the command line version. However, csi.exe has some valuable uses because, for example, it doesn’t require you to load the Visual Studio IDE in order to execute C# scripts.

Life in a Window

C# code behaves a little differently in the C# Interactive window and some of these differences may be confusing if not frustrating. For example, you’ll find that all top-level variables and members in the C# Interactive window have public modifiers by default. Although this makes sense in a REPL world, it differs from the behavior of statically complied code. You’ll also find that everything executes asynchronously in the interactive mode, even if it appears to be synchronous. We’ll be showing how this may require some tweaks when moving static code to the interactive window..

The Interactive Window GitHub repository summarizes the features.

CSX Files

When Roslyn arrived, so did C# scripts. But until the introduction of C# Interactive, scripting CSX files weren’t much used. It is hardly surprising when you consider the abundance of other more widely-known and mature scripting languages such as PowerShell.

This has now changed, because developers can now cut and paste code between their solution’s CSX files and C# Interactive windows. This allows us to write complex snippets, saving work and rehydrating it later. It also allows us to create test cases that are executable from either Visual Studio or the command line.

The Power Demonstration

This demonstration of the value of using C# Interactive in development is more about developing the end-to-end process. It will allow us to sketch out and assess how the process will work rather than provide the final system. C# Interactive is unlikely to impact the code that is delivered to the customer, but it can make it quicker and easier to prototype, and determine, the best solution. We’ll choose a typical enterprise application assignment to show what we mean.

Getting the Data

Imagine we have been engaged by an energy analytics provider to construct an API that allows them to access electric power consumption data that is provided by the U.S. Energy Information Administration (EIA). To get started with this exercise of prototyping a solution, we first need to complete the brief access request and, in turn, receive our API KEY. With this key, we then need to decide on the most appropriate http request on the Demand page. After viewing a few series, we choose to select the Demand for Portland General Electric Company, Hourly dataset:

  1. http://api.eia.gov/series/?api_key=YOUR_API_KEY_HERE&series_id=EBA.PGE-ALL.D.H

Note: Readers wishing to learn more about the EIA API may find their BETA User Guide helpful.

Building the Solution

We’ll start off by using conventional C#. The solution starts out with the DemoLibrary component referenced and called by a console consumer entitled DemoClient.

GetDemandRaw walks a familiar path for executing an asynchronous http get request. The method leverages the System.Net.Http’s HttpClient to execute our demand query laced via string interpolation with the target company’s seriesId and API key that we obtained earlier from the EAI. Our secret API key is saved in the library because at this stage we are just prototyping.

The consuming Main method in DemoClient indicates that our handiwork proved adequate as shown by the displayed JSON when we execute the compiled command-line program.

Well, there the story could easily end without the need for any more significant development work. However, while we are packing up our laptop for the next assignment, the client’s development team reports dismay. They do not like the JSON data provided by GetDemandRaw. They expected a more digestible .NET version of the data as .NET objects.

GetDemand reflects that wish. Someday it will return a list of lightweight EnergyDemand objects, until then we will settle for an empty one.

It’s at this stage that the development process begins to crawl. While some may find converting raw JSON into a list of .NET objects institutively obvious, others (like me) do not. Traditionally we’d be faced with checking debugger state, probing in the Intermediate window, tweaking code, recompiling the solution, reloading data, either directly or in directly, until happy. It’s not an insurmountable process, just tedious and slow. Time for C# Interactive!

Exploring

We will now switch to using C# Interactive. The process of executing code in C# Interactive does not differ much from that of a console application. The first difference is in telling it how to load DemoLibrary. Once that’s done, we just copy the DemoClient code into the window as shown below.

An odd thing happens after we enter the last line of code; odd in that nothing happens. The window just sits. Did we forget that C# Interactive executes asynchronously while looking synchronous? With that detail in mind a fix becomes obvious. GetDemandRaw needs “prompting” before yielding any secrets as the revised code shows.

Now the fun, in terms of productivity, begins. We can explore the energyDemandRaw object without reloading it or recompiling any code. All we need to do to convert the output JSON string into a dynamic object is to load a serializer. While many libraries serve this function, we keep it simple by using the readily available .NET library, System.Web.Script.Serialization.

Loading System.Web.Script.Serialization follows a similar pattern to the DemoLibrary component. The difference is that we do not specify a file path. After we have created the serializer, we can now explore data with C# as a familiar object-oriented workout. For example, as shown below, after we discover that energyDemand is a dictionary, then the process of identifying keys only requires a C# foreach loop.

Saving Progress

How can we save our work in progress? Imagine that we’ve just been asked to pause working on our current chore in order to address a late-breaking emergency. We have a slight problem though. How do we avoid losing what we just learned about the demand output? Where should we safely save the code snippet? There are some rather awkward-seeming choices such as saving it to DropBox in a text file or hiding it in the library. There’s now a better option – adding it to a C# script file.

In order to save code with the C# Interactive feature, all we need to do is to create a CSX file as noted earlier. Unfortunately, Visual Studio does not make this easy because we have to add the file and change its extension to CSX. Once we’ve done this, we can paste code into it from the C# Interactive window.

In order to save our work, we create the CreateGetDemand.csx file and copy the REPL code onto it. Sadly, pesky red squiggles on lines 9 and 10 inform us of some code issues.

We again encounter one of those quirks that come about because C# lives in slighty different environments. CSX files behave more like compiled code and less like its REPL brethern. In this instance the fix only requires us to move the offending lines to top of the file as suggested by Visual Studio.

The fixed CreateGetDemand.csx that follows now displays without error.

Resuming

Our imaginary emergency passes. How do we resume where we left off, deciphering JSON output in order to complete GetDemand? The value of having saved our prototype work to a C# script file now becomes evident. We effortlessly reload it into an open C# Interactive with the following command.

#load “C:\Temp\DemoScript\DemoLibrary\CreateGetDemand.csx”

The window shows that we have reconstituted energyDemand. This can be seen in the series value assignment that follows it, and our subsequent proddings.

We continue to determine object types, and inspecting values, until we are satisfied that we have a set of data for the Portland General Electric Company’s hourly power-demand.

We update CreateGetDemand.csx to record how we unwrapped the JSON document.

With this prototyping code, our implementation of GetDemand can proceed quickly. We start by adding the Microsoft.CSharp and System.Web.Extensions component references to the solution.

Note:Microsoft.CSharp helps read the serialized object that System.Web.Extensions created. C# Interactive did not require it for reasons that we will cover shortly.

Notice how our investigatory REPL eased the data variable assignment. Transitioning from the complex JSON string in energyDemandRaw to data (almost) makes us look like EIA API experts.

After updating DemoClient to call GetDemand, we see everything behaving as expected.

Only one problem remains. How can we more thoroughly test our API?

Testing

For testing, C# Interactive can to the rescue again! After writing some test code via REPL we add it the following TestGetDemand.csx file. While the tests are far from rigorous, they do check a few different companies and some different values. It also allows us to alter and add new tests as warranted.

Another bonus of having a CSX script file is that there are options for running it. Earlier we saw how they can be executed in a C# Interactive window. This time we run it via Developer Command Prompt for VS2015 by calling csi.exe with the link to the script file as a parameter.

C:\Temp\DemoScript\DemoLibray>csi TestGetDemand.csx

The demonstration’s solution as shown below is completed. Our imaginary energy analytics company developers can now obtain the data from the U.S. Energy Information Administration API, formatted just as they wanted it.

Referencing

It is sometimes confusing to figuring out references when working within C# Interactive. For example, has anyone who is reading this noticed that the REPL code never included the obligatory System enabling Console.WriteLine? Nonetheless, it certainly does write. Turns out that C# Interactive creates and manages its own environment as evidenced by the second line that is displayed after first loading the window.

A quick visit to the Roslyn GitHub site informs us that CSharpInteractive.rsp loads three components: System, System.Core, and Microsoft.CSharp. (Remember that we had to manually add it to our solution for GetDemand?) It also takes care of inserting several common using statements.

Conclusion

With Interactive C#, developers are no longer constrained to statically-compiled code. They can now apply their .NET expertise within scripting and REPL environments. Unfortunately, these different environments are not completely compatible with each other and Visual Studio only offers some help to address the incompatibilities. Nonetheless, .NET developers comfortable with Interactive C# are likely to find themselves writing code faster and having more fun doing so.