I am building my dotnet core webapi service for the point of PoC and I am concerned about setting a proper guidance for other archs/devs moving forward.
There are few variations for the "same" method signature
- public dynamic Get(string name = _defaultName)
- public IActionResult Get(string name = _defaultName)
- public async Task Get(string name = _defaultName)
Leaving discussion alone on why I am using dynamic instead of custom type, I am trying to understand the differences and benefits.
Please correct my (mis)understanding:
- No control over http response, headers, code, etc - all set by the framework in case of success or failure, return type is visible to run-time tools
- Better control over the http response, but it will tie up the threat while executing the method, no definition for the output data type
- Better control over http response, will not tie up the threat while executing the method, but will spin off another thread to compute the result, and no definition for the output type
The implementation for the 3rd option will look like following:
public async Task<IActionResult> Get(string name = _defaultName)
{
return await Task.Run(() => {
dynamic response = new System.Dynamic.ExpandoObject();
response.message = $"Hello {name}!";
response.timestamp = DateTime.Now.ToUniversalTime();
if (name.Equals(_defaultName, StringComparison.CurrentCultureIgnoreCase)) {
response.hint = "Add forward slash and your name to the url, e.g.: hostname:port/my name";
}
return Ok(response);
});
}
I understand that with async dependency such as HttpClient and EntityFramework the implementation for async methods exists already.
I am wondering whether it makes sense without such downstream async dependencies to pursue async webapi methods and the resulting a tad weird looking code.
Task<IActionResult>DO NOT spawn another thread! Alsoasync/awaitkey words DO NOT spawn new threads. Only whenTask.Run(...), TaskFactory.StartNew(...)` etc are called a new thread is spawned (this should be avoided in ASP.NET and ASP.NET Core)IActionResultif necessary (e.g., file downloads); and I keep them synchronous unless they have asynchronous work to do, in which caseTask<TModel>orTask<IActionResult>is appropriate. Trying to enforce a one-size-fits-all guidance will lead to antipatterns likeTask.Run. Any decent dev should be able to figure out an appropriate return type, and be empowered change it if necessary.