Archive for the ‘API Team (Red)’ Category
Rolling your own coroutines
This post marks the conclusion of the async programming series I originally started as lead in for my monospace 2011 talk. The remaining subject, as promised in my last article, is the creation of tradtional coroutines using .NET iterators. The example code and Monospace slides talking about it can be found on github. I had hoped to time it with a definite date for async/await arriving in .NET but WinRT has kind of derailed future releases, it would seem.
But before I get into, let's roll up the posts that got us here:
- Tasked To Get Results – Introducing our asynchronous completion handles, DReAM's Result and the Task Parallel Library's Task
- What's Asynchrony Good For? — When should we use these constructs
- Exit … Screen Right — CPS (Continuation Passing Style) asynchronous chaining using Result and Task
- Asynchrony and Sequential Workflows — Using DReAM coroutines and TPL's async/await to bring back sequential flow in asynchronous operations
The canonical example of coroutines are producer/consumer pipelines, in which each stage of the pipeline does some amount of work and yields execution to the next stage once it cannot continue. The benefits of this type of processing pipeline is avoidance of locks and maximum utilization of the processing power given to it, in addition to the loose coupling of the pipeline that easily let you add or remove steps in the chain.
For this processing to work the coroutines must all have the same "shape", e.g. signature. For the Iterator based coroutines I will cover first, I chose the following shape:
The coroutine accepts the Coordinator and yields once it cannot continue with any more work. The Coordinator contains the shared state T that all coroutines have access to. Since only one coroutine is ever executed at a time, the state can be mutated without locks.
The example we'll use is a producer of a 3x4 matrix and a consumer that outputs that matrix transpoed to 6x2. To show the ability to add random stages to this chain, we will have another coroutine that will take every value and square it.
We create a Coordinator<int[]>, i.e. our state is a block of ints, requiring a coroutine signature of IEnumerator Coroutine<T>(Coordinator<T> coordinator), but since the Coordinator accepts the coroutines as an array of Funcs, we can curry signatures of different shapes into the required shape. In our example we capture a source and destination for the Producer and Consumer coroutines, respectively, while the Exponetiator already has the required shape.
Let's look at the Producer:
The Producer takes the input matrix and writes it one row at a time into the state object. After each row, the producer yields execution to the next coroutine. We yield null, since the iterator is just used for its side-effect of letting us suspend a method mid-execution and continue later. And that's the magic of it. Yes, it looks like a regular method, but it really does exit and re-enter multiple times. Every time yield is called, the state of the method is suspended while another coroutine gets to run, and once resumed, the method continues on with all its local state from the point right after the yield. We are stopping in the middle of a loop, letting someone else go and then continue on from that exact same place in the loop, all without blocking a thread.
The Consumer is provided the output matrix and starts a loop that will continue until its output matrix is filled, reading the block of integers from the state, writing it to the new matrix and yielding its execution to the coordinator, so that the a fresh set of integers can be provided.
The last coroutine is the Exponentiator which just continues to square every value in the state integer block each time it is resumed and then yields execution until provided a fresh set of integers to square.
Finally, Coordinator<T> allows the construction of these arbitrary co-operative processing chains. It is simply an inversion of a regular iterator. Instead of receiving a new value, one at a time from an enumerator, we have one enumerator per coroutine that we can command to run to its next yield point with MoveNext(). MoveNext() will return false if it was a yield break, signaling that the coroutine is done or true if it was a yield return, signaling that the coroutine is willing to continue in which case we put the enumerator into our queue, pick the next coroutine from the queue and compel it resume.
In the github project I also implemented the same coroutines using async/await. The one benefit that implementation has over Iterator based coroutines is that once inside an async method, you can await any other async method. Allowing these types of coroutines to suspend the execution chain to let some other async task (such as a web request) execute.
While interesting and useful in a limited set of circumstances the coroutines introduced in this article are not likely going to find themselves into your next project. Far more useful and applicable in any application liable to block on I/O are the asynchronous workflows introduced in Asynchrony and Sequential Workflows since these types of coroutines allow us to use traditional sequential coding styles while never blocking on asynchronous operations.
Asynchrony and sequential workflows
Rather than finishing this series on asynchrony before my Monospace 2011 talk on the same subject, I got busy finishing the materials for the talk instead. The slides and example code from the talk can be found here, and the video will be posted on InfoQ in the near future. Since the examples are slightly different and the slides less explanatory, I will continue this series of posts as a more in-depth version of the content in the slides.
In the last post, Exit… Screen Right, I talked about using the CPS (continuation passing style) to chain asynchronous methods together. While this is a proven way of dealing with asynchrony, it puts the how in front of the what, which makes our code harder to maintain and debug. Ideally we'd continue writing our code in the regular sequential style we've always used but steps that do not happen synchronously, suspend the flow and resume once the step is completed instead of blocking their thread. With a regular method that's not possible, since it controls the flow of execution until it exits, but there exists a variation of the trusty method (which really is just a subroutine), called coroutine:
Coroutines are computer program components that generalize subroutines to allow multiple entry points for suspending and resuming execution at certain locations
With Coroutines, we can suspend the current execution flow, allow an async action to complete and then have its continuation resumes our flow of execution. Great. Except .NET doesn't have Coroutines, right? Not exactly, but it does have generators for building Iterators, in the form of IEnumerator<T> and the yield keyword. Since Generators are a specialized form of Coroutines it is possible to use them to mimic Coroutine behavior. In addtion, the AsyncCTP for C# 5.0 introduces the async/await constructs, which provide a better syntax for suspending and resuming a method.
DReAM Coroutines are built on top an inversion of the Iterator pattern, which allowed us to introduce them in .NET 2.0, while Task based Coroutines won't be possible in production until .NET 5.0 ships. Both provide us the ability to write sequential code that suspends on asynchronous work, preserving our workflow.
Review of our Async Workflow Methods
Below are the asynchronous method signatures from last time:
1. GetUserRecentArticles
This method implements the asynchronous workflow.
// Result Result<DreamMessage> GetUserRecentArticles(int userId, int limit, Result<DreamMessage> response) // Task Task<DreamMessage> GetUserRecentArticles(int userId, int limit)
DreamMessage is DReAM's symmetric Http Request and Response data container, and serves as the value of the synchronization handle seen by the outside caller. The Http Server would call GetUserRecentArticles to start the asynchronous chain and use the synchronization handle to retrieve the final result.
2. GetFeedsForUserFromDb
This method uses asynchronous database queries to get the list of Uri's the user is subscribed to:
// Result Result<IEnumerable<XUri>> GetFeedsForUserFromDb(int userId, Result<IEnumerable<XUri>> result) // Task Task<IEnumerable<XUri>> GetFeedsForUserFromDb(int userId)
3. FetchFeed
This method uses an asynchronous web request to fetch the feed for a given Uri. We will be multiplexing this call to fetch multiple feeds at once.
// Result Result<XDoc> FetchFeed(XUri uri, Result<XDoc> result) //Task Task<XDoc> FetchFeed(XUri uri)
4. FilterViaDb
This method is called once for each feed that we've fetched to turn into a list of only the articles not yet seen by the user
// Result Result<IEnumerable<XDoc>> FilterViaDb(XDoc doc, Result<IEnumerable<XDoc>> result) // Task Task<IEnumerable<XDoc>> FilterViaDb(XDoc doc)
5. MarkAsRead
Step 5 combines the articles, applies the limit and marks the articles to be returned as read. Only the last part is an asynchronous operation, the rest can be performed inline. The method MarkAsRead makes asynchronous calls to the database to insert the canonical Uri's of the articles to be returned to mark them as read.
//Result Result MarkAsRead(int userId, IEnumerable<XDoc> aggregatedArticles, Result result) // Task Task MarkAsRead(int userId, IEnumerable<XDoc> aggregatedArticles)
DReAM coroutine
A DReAM Coroutine must produce an Enumerator of type IYield, which is the coordination construct for Coroutines and is implemented by Result, i.e. any method returning a Result can be yielded to in a Coroutine. Since this signature requirement would change the expected signature of GetUserRecentArticles from the DReAM Asynchronous Method Pattern and the usage of a Coroutine is really an implementation detail, we hide the actual Coroutine:
private Result<DreamMessage> GetUserRecentArticles(int userId, int limit, Result<DreamMessage> response) {
return Coroutine.Invoke(GetUserRecentArticles_Co, userId, limit, response);
}
We use Coroutine.Invoke to execute the enumerator that GetUserRecentArticles_Co returns. The actual implementation now has the familiar sequential flow we are used to:
public Yield GetUserRecentArticles_Co(int userId, int limit, Result response) {
// yield execution to fetch the user's feed uris from the DB
IEnumerable uris = null;
yield return GetFeedsForUserFromDb(userId, new Result>()).Set(x => uris = x);
// start to fetch all feeds
var feeds = uris.Select(uri => FetchFeed(uri, new Result())).ToList();
// yield execution until all fetch calls have signaled completion
yield return feeds.Join(new Result());
// start to filter all feeds to only unread
var allUnreadArticles = feeds
.Select(feedResult => FilterViaDb(feedResult.Value, new Result>()))
.ToList();
// yield execution until all filter calls have signaled completion
yield return allUnreadArticles.Join(new Result());
// combine all filtered articles
var combinedArticles = (from unreadResult in allUnreadArticles
let unreadArticles = unreadResult.Value
from article in unreadArticles
select article).Take(limit).ToList();
// yield execution to async method marking all remaining articles as read
yield return MarkAsRead(userId, combinedArticles, new Result());
var aggregatedDoc = new XDoc("articles").AddAll(combinedArticles);
// signal response with aggregated article document
response.Return(DreamMessage.Ok(aggregatedDoc));
}
Instead of chaining .WhenDone on each async method, we now call them with yield return instead, which resumes the body of the method after the async call completes. We still use response.Return to signal completion, since the Iterator doesn't regular return value. The one caveat causing some syntactic cruft is that we cannot create and assign the value in the yield return. Instead we have to declare it before and use the .Set() extension method, which unwraps the result, allowing us to capture it with a lambda.
Coroutine flow with async/await
async/await allows the same coroutine flow we create with an Iterator and Result, but since it is custom built into the compiler around Task, it achieves additional syntactic magic for very readable and natural code:
public async Task GetUserRecentArticles(int userId, int limit) {
// Await the fetching of the user's feed uris from the DB
var uris = await GetFeedsForUserFromDb(userId);
// start fetch all feeds
var feedTasks = uris.Select(FetchFeed).ToList();
// Await all feeds being fetched
var feeds = await TaskEx.WhenAll(feedTasks);
// start to filter all feeds to only unread
var unreadArticleTasks = feeds.Select(FilterViaDb).ToList();
// Await feeds completing filtering
var allUnreadArticles = await TaskEx.WhenAll(unreadArticleTasks);
// combine all filtered articles
var combinedArticles = (from unreadArticles in allUnreadArticles
from article in unreadArticles
select article).Take(limit).ToList();
// Await the database call to mark all remaining articles as read
await MarkAsRead(userId, combinedArticles);
var aggregatedDoc = new XDoc("articles").AddAll(combinedArticles);
// return the final result, which in turn sets it on the Task
// that had already been returned for us
return DreamMessage.Ok(aggregatedDoc);
}
With async/await, the only difference between a workflow where all of our calls are synchronous is that we have an await in front of every async method now. That's a really low syntax tax to pay for completely non-blocking workflows! The other thing you may notice is that the signature of the method is Task<DreamMessage> while we return just a DreamMessage. This is possible, because the method is marked with async, which tells the compiler to rewrite the method body as a series of continuations interrupted by await barriers.
But how does it work?
Both yield and async/await are constructs that tell the compiler that the body of the subroutine should be rewritten as a state machine. They make it easy for us to think of the flow of execution as a regular sequential flow, while handling the complexities of tracking the local scope when execution is suspended and resumed. In simplistic terms, a new anonymous class is generated with members to capture the locally available variables of the method. The body of the method is broken up into linear blocks of execution at the yield/await barriers. This way each block can be run until the next barrier, store to which point it was last run to and exit and upon the next invocation continue running the next block.
In my next post, I will break down how you can use this behavior to roll your own Coroutines instead of just using yield to return values in a sequence or await to wait for an asynchronous method to complete.
What’s asynchrony good for?
In my previous post, "Tasked to get Results", I covered the use of DReAM's Result and the TPL's Task as waithandles for asynchronously completed work. Except that all examples dealt with blocking behavior to await the completion of the other task, which made the async illustration rather academic.
Blocking for async work does have its applications. The canonical example being a controlling thread firing off a number of workers and waiting for all of them to complete to gather the results. For implementing this example, Task and Result can be thought of as convenient alternatives to WaitHandle.WaitAll() or Thread.Join() or EndInvoke() calls:
// Summing up Results var results = new List>(); for(var i = 0; i < 100; i++) { results.Add(SomeAsyncWork(i)); } var total = results.Sum(x => x.Wait()); // Summing up Tasks var tasks = new List >(); for(var i = 0; i < 100; i++) { tasks.Add(SomeMoreAsyncWork(i)); } var total = tasks.Sum(x => x.Result);
Both rely on implicit blocking behavior to perform the summation. We could just as easily have explicitly waited on all the handles with C#5.0 AsyncCtp's TaskEx.WhenAll() or DReAM's Result.Join(), and then summed the results. One interesting feature to keep in mind about the join constructs in TPL and DReAM is that both return synchronization handles themselves. I'll explain why this is useful in the next article. Either way though, our main thread was blocked until the workers completed.
Finding opportunities for asynchrony
The parallel worker example is a great way to show the power of Task and Result for managing many workers, but in itself is not asynchronous. Asynchrony implies that we do not block waiting for work to complete, whereas the above example explicilty blocks the main thread. Asynchronous behavior may be combined with parallelism to manage resources better, but asynchronous behavior does not mean that we are performing the work in parallel. Quite the opposite, the primary goal of asynchrony is to suspend the caller until the asynchronous operation has completed. This means that most asynchronous workflows are inherently serial even if the steps executed may happen on different threads.
To properly show the benefits of asynchrony let's use something that we deal with every day and is inherently asynchronous: I/O – Whenver we are reading from or writing to a file, making a database call or calling a webservice we are making an I/O request and waiting for the response. We don't think of I/O as asynchronous because most I/O APIs have exposed these operations as synchronous method calls, i.e. they block the thread while waiting for the out-of-context operation to complete:
var command = new SqlCommand(
"SELECT CategoryID, CategoryName FROM Categories;",
connection);
// Blocking!
connection.Open();
//Blocking!
var reader = command.ExecuteReader();
// Blocking!
while(reader.Read()) {
// read row
}
reader.Close();
Most of time, we don't even interact with a DB at this low level, but that doesn't change the fact that in order to get data back from the database, we have to:
- Open a socket to the DB and wait for the connection to be established
- Send our SQL and wait to for a cursor to become readable
- Iterate over the cursor and wait for data to be sent
Each operation sends data over the wire and waits on a response. That waiting time is blocking the current thread.
Why so slow, I/O?
Most I/O operations are quite fast, and much of our optimization work relates to reducing the times of database queries, file reads and web service calls to the single digit milliseconds. However, compared to in-process memory access, which is measured in microseconds, even the best optimized I/O operation is orders of magnitude slower. Every time we treat I/O as synchronous we rely on thread scheduling to utilize the CPU time not utilized by the blocking thread, which in turn costs us in thread context switching and memory footprint.
But we've been doing this for ages and it hasn't been a problem, right? What's changed?
For one thing, it has actually been a problem and for the most part, we've just been throwing larger and larger machines at our server clusters to make up for the resource wastes committed. But all the optimization of I/O aside, in the real world we will always encounter the occasional slow DB query, file read/write blocked by a lock and web service request over a congested network.
For another, on top of those real world concerns, we've received a wake-up call in the form of evented I/O: Suddenly node.js and python's tornado web server have shown us that a single server could handle thousands of simultaneous connections, which would make traditional servers fall over and die. This incredible capacity is not due to some magic optimization or that python and javascript have secretly gotten faster than other languages. What they are doing is deal with I/O as non-blocking. It is easy to keep thousand's of sockets open at the same time when each isn't tied to a process or thread. When node.js boasts 100k+ connections at once, it still is only processing one request at a time, but every time a I/O operation is required, it schedules a callback for completion rather than blocking until the I/O has completed. That this one at a time model ends up with more requests/second shows how much overhead we incur when we rely on thread management. But there's nothing about node.js performance that couldn't be replicated in C# (and Manos de Mono is doing exactly that), as long as we break our addiction to blocking.
…and after you are done with that, could you do this?
Using an asynchronous approach provides a way to mitigate this in-process vs. I/O operation speed differential and stop blocking our threads. What we want is to be notified when the asynchronous operation has completed. While most I/O APIs provide some type of asynchronous calling convention (ADO.NET only provides it on the Execute* members), Task and Result provide a unifying interface for all operations and a way to handle the continuation of work in a non-blocking form in a much simpler way:
// Result
connection.Open();
Async.From(command.BeginExecuteReader,
command.EndExecuteReader,
null,
new Result())
.WhenDone(
result => {
var reader = result.Value;
while(reader.Read()) {
// read row
}
reader.Close();
}
);
// Task
connection.Open();
Task.Factory.FromAsync(command.BeginExecuteReader,
command.EndExecuteReader,null)
.ContinueWith(
task => {
var reader = task.Result;
while(reader.Read()) {
// read row
}
reader.Close();
}
);
The above introduces the continuation constructs Result.WhenDone and Task.ContinueWith, which allow us to chain operations to execute in the context of the asynchronous method's callback. Both Result and Task provide a way to convert the standard Begin*/End* pattern from any API into Result/Task, which we can then attach a continuation to. I should note that in the C#5.0 AsyncCtp Microsoft has added Extension Methods for virtually all Microsoft async patterns to further simplify invocation.
Next time, we'll take a look at a more complex workflow using the continuation passing style possible with Result.WhenDone and Task.ContinueWith and what complications it may introduce.
Tasked to get Results
The second monospace conference has finally been scheduled for July in Boston and I'm honored to have been selected to speak at it again. Back in 2009, i covered the gamut of concurrency tooling available in DReAM. This year, I'm going to concentrate on asynchronous programming and in particular cover both DReAM coroutines and the remarkably similar async/await constructs going into C# 5.0. In preparation for my talk, I thought it would be interesting to run a series of posts presenting my experience working with both async programming models.
Keeping things synchronized
Traditionally when work is being completed outside of the current thread there are a number of different patterns offered. You could spawn a new thread, use the threadpool or use a BackgroundWorker. To synchronize a Waithandle is used to signal completion on the waiting thread and a shared reference is commonly used to communicate the result. In addition, various asynchronous APIs offer Begin* and End* methods to start asynchronous work and be notified of their completion, using an untyped state object to communicate the outcome.
Trying to simplify and unify these patterns, DReAM introduced Result back in 2006 to support asynchronous operations for its REST framework running on .NET 2.0. A very similar construct called Task was added .NET 4.0 via the Task Parallel Library. While there are some semantic differences, both provide virtually identical capabilities. At the heart of both constructs are synchronization handles that serve simultaneously as a completion signal and as a means of marshaling the outcome to the interested party. Both can be queried for completion, used to block execution or attach a continuation handle to capture the outcome.
Let me know when you're done
The basic usage of Result as the party wanting to receive information about some asynchronous work is as follows:
Resultr = SomeAsyncWork(); // check if work is done if(r.HasValue) { ... } // check if work is was cancelled if(r.IsCanceled) { ... } // block until it's done r.Block(); // check if an exception occured if(r.HasException) { Console.WriteLine("work errored out: {0}",r.Exception); } else { // get the resultant value var value = r.Value; }
And the equivalent code using Task:
Taskt = SomeMoreAsyncWork(); // check if work is done if(t.IsCompleted) { ... } // check if work is was cancelled if(t.IsCanceled) { ... } // block until it's done t.Wait(); // check if an exception occured if(t.IsFaulted) { Console.WriteLine("work errored out: {0}", t.Exception); } else { // get the resultant value var value = t.Result; }
Aside from simple semantic differences in usage, Result and Task differ in how blocking behavior is treated. With Result, accessing .Value before work has completed will throw, while with Task accessing the analogous .Result will invoke its .Wait() for you and block. If you prefer Task's behavior, Result provides it's own .Wait() which blocks and returns the value of the result upon completion. Unlike Result.Block() but like Task.Result, the Result.Wait()call with throw if the work is faulted.
Go do some work
Now that we know how we synchronize with the work being done asynchronously, let's get this work started ourselves
Task is built around being provided an expression of the work to perform. There a numerous ways of setting up the task and determining how its execution is to be scheduled, but the simplest method is to use the Task.Factory:
var task = Task.Factory.StartNew(() => { var x = 1; // ... do some time consuming work return x; });
Firing off work is one of the largest differences between Task and Result. Where Task is fundamentally built around wrapping around a unit of work to be executed, Result is just the synchronization handle — firing of the unit of work is left as an execution detail. Since starting work on a threadpool thread is the one of the most common patterns, DReAM provides this functionally via the Async static class:
var result = Async.Fork(() => { var x = 1; // ... do some time consuming work return x; },new Result ());
The signature of Async.Fork shows another philosophical difference between Task and Result: With Result, we use a pattern in which any method returning a Result will take that result as its last argument. This is done primarily because with Result the concept of timeout is fundamental and attached to the handle, whereas with Task it is usually an argument on blocking operations. By requiring that a Result is passed into the method, the opportunity to initialize the handle with timeout and cleanup behaviors is provided before the result is attached to a unit of work.
Everything's synced up
With what I've shown so far, Result and Task might be handy constructs, but we really haven't strayed far from the usual blocking behaviors that are so troublesome and resource intensive. Yes, we've parallelized some things, but we're really still doing synchronous computing. Asynchrony doesn't actually imply any parallelism, it really just refers to our work not blocking a thread and instead suspending execution and resuming it once we're notified of the completion of work.
Next time, I'll cover how continuations can be used to chain operations to create non-blocking, sequential operations.
MindTouch DReAM moves to github
We’ve been using github for some new projects we create at MindTouch and today we’ve migrated the first of our established projects, DReAM, over to github. Using github for DReAM will allow for better collaboration with the community and makes it possible to share work-in-progress experiments.
This does mean that the subversion repository of DReAM is now deprecated and will no longer be updated with changes. Because we’re also changing how we handle our binary distribution, we did not import our svn history into git, instead starting with a snapshot in time.
Branching strategy
The initial master revision at github represents the 2.2 release, code-named Jade. As we continue working, we will create major.minor version branches like the 2.2 branch and we will tag release revisions on those branches, i.e. the initial release of the 2.2 branch has the 2.2.0 tag. Signed binaries will be built from these release tags and added to the repo’s download section.
The master branch will function like our previous subversion trunk, receiving vetted changes that will become the next major.minor branch. Master is considered to be bleeding edge, but functional, so if you want to follow along with current changes that will make it into the next version, it’s the branch to follow.
The real change from our current strategy is that we will create feature and WIP branches off master that allow us to let the community preview code we are considering but have not finalized. We will always try to only push when we think we have something reasonably functional, but these branches may be broken at times.
What’s new in DReAM 2.2 (Jade)
The most recent maintenance release of DReAM 2.1 was 2.1.6. With the github move, we’ve released 2.2.0 which contains all fixes found in the maintenance releases and also has introduces some significant, new features.
Additional Convention based DreamFeature signatures
2.1 introduced optional synchronous DreamFeature signatures, i.e.
DreamMessage Feature(
DreamContext context,
DreamMessage request
)
instead of
Yield Feature(
DreamContext context,
DreamMessage request,
Result<DreamMessage> response
)
as well as the ability to inject virtually any part of the incoming request as an argument by naming and/or attribute conventions such as:
[DreamFeature("POST:foo/{id}", "feature description")]
[DreamFeatureParam("{id}", "required path parameter")]
[DreamFeatureParam("verbose", "optional query parameter")]
DreamMessage Feature([Path] string id, [Query] string verbose, XDoc body)
In the above id is populated from the request Uri path, verbose from the Uri query args and body is the POST body as an Xml document.
In 2.2, we add the ability to use XDoc as a return type, as well as auto-conversion of both path and query parameters, allowing a signature like this:
[DreamFeature("POST:foo/{id}", "feature")]
[DreamFeatureParam("{id}", "required path parameter")]
[DreamFeatureParam("verbose", "optional query parameter")]
XDoc Feature([Path] int id, [Query] bool verbose, XDoc body)
These conventions allow for a significant reduction of repetitive boiler plate.
ASP.NET hosting support for DReAM
The most significant addition is the ability to host DReAM inside of ASP.NET. This allows for development and debugging with the Visual Studio built-in HttpServer, as well as easier deployment under IIS with the DreamHost being governed by ASP.NET application lifetime scope and configuration behavior. This hosting behavior also allows for co-hosting DReAM along side of an ASP.NET MVC 2 or even Webforms application. Being hosted in the same appdomain allows these applications to call DReAM REST services via Plug without ever having to hit the wire.
The simplest way to try this capability out is to create a new empty ASP.NET MVC 2 application, and replace the entire contents of global.asax.cs with
public class MvcApplication : HttpApplication {
protected void Application_Start() {
DreamApplication.CreateInHttpApplication(this);
}
}
Now simply press F5 and the root of the application will come up in your browser showing you the debug listing of running services. To simplify debugging, the hosted instance will by default allow access to private and internal features while the debugger is attached. To add dream services, simply create a folder called Services and drop your IDreamService .cs files in the folder. These services will automatically discovered and started.
The possibilities and configuration options for this setup are beyond the scope of this article. For now you can take a look at the two sample applications in the samples folder of DReAM. We will also follow up with articles about the setup and configuration options added and a walk-through of the MVC/Dream AtomFeed sample application.
Amazon S3 API and Amazon S3 version of StorageService
DReAM has always included a REST file storage abstraction called the StorageService. With 2.2, we’ve added an alternative implementation that serves as drop-in replacement via a simple config change to move that file storage into Amazon S3. As part of this new service we built a simple API for accessing S3, which can be used independently of the S3StorageService. It can even be used independently of DReAM services altogether. The API is:
public interface IAmazonS3Client : IDisposable {
AmazonS3DataInfo GetDataInfo(string path, bool head);
void PutFile(string path, AmazonS3FileHandle fileInfo);
void Delete(string path);
}
where AmazonS3DataInfo serves as a handle to either a directory Xml document or file stream.
What’s in store for vNext?
The first experimental branch on github is reorg, which will likely become DReAM 3.0. Why jump straight from 2.2 to 3.0? We have some significant changes planned, which will require some reference changes to recompile and may introduce some breaking API changes. The current goals for this refactor are documented here.
The reason for this drastic change is to offer the many powerful features that make up the DReAM application server as separate dependencies. Split into their own DLLs people will be able to take advantage of our BCL extensions, our Xml programming interface, our Coroutine framework, as well as our REST client and server infrastructure individually. We hope that separate availability will make these libraries a bit more approachable and to help foster more community involvement.
