I need to write a method like below to return a text document (.txt, pdf, .doc, .docx etc) While there are good examples of posting file in Web API 2.0 on the web , I couldn
Methods are asynchronous if return a Task object, not because are decorated with async keyword. async is only a syntactical sugar to replace this syntax what can get rather complex when there are more tasks combined or more continuations:
public Task<int> ExampleMethodAsync()
{
var httpClient = new HttpClient();
var task = httpClient.GetStringAsync("http://msdn.microsoft.com")
.ContinueWith(previousTask =>
{
ResultsTextBox.Text += "Preparing to finish ExampleMethodAsync.\n";
int exampleInt = previousTask.Result.Length;
return exampleInt;
});
return task;
}
Original sample with async: http://msdn.microsoft.com/en-us/library/hh156513.aspx
async always requires await, this is enforced by compiler.
Both implementations are asynchroous, the only difference is that async+await replaces expands the ContinueWith into "synchronous" code.
Returning Task from controller methods what do IO (99% of cases I estimate) is important because the runtime can suspend and reuse the request thread to serve other requests while the IO operation is in progress. This lowers the chances of running out of thread pool threads. Here's an article on the topic: http://www.asp.net/mvc/overview/performance/using-asynchronous-methods-in-aspnet-mvc-4
So the answer to your question "Does the above needs to be async at all? I am only looking to return stream. (Is that okay?)" is that it makes no difference to the caller, it only changes how your code looks (but not how it works).
Right, for your above scenario the action does not need to return an async action result. Here I am creating a custom IHttpActionResult. You can check my comments in the below code here.
public IHttpActionResult GetFileAsync(int fileId)
{
// NOTE: If there was any other 'async' stuff here, then you would need to return
// a Task<IHttpActionResult>, but for this simple case you need not.
return new FileActionResult(fileId);
}
public class FileActionResult : IHttpActionResult
{
public FileActionResult(int fileId)
{
this.FileId = fileId;
}
public int FileId { get; private set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new StreamContent(File.OpenRead(@"<base path>" + FileId));
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
// NOTE: Here I am just setting the result on the Task and not really doing any async stuff.
// But let's say you do stuff like contacting a File hosting service to get the file, then you would do 'async' stuff here.
return Task.FromResult(response);
}
}