If you have previously worked with .NET Core or .NET Framework, you have probably dealt with both Task.FromResult and Task.Run. Both can be used to return Task<T>. The main difference between them is in their input parameters. Take a look at the following Task.Run snippet:
public Task<int> AddAsync(int a, int b) { return Task.Run(() => a + b); }
The Task.Run method will queue the execution as a work item in the thread pool. The work item will immediately complete with the pre-computed value. As a result, we have wasted a thread pool. Furthermore, we should also notice that the initial purpose of Task.Run method was intended for the client-side .NET applications: ASP.NET Core is not optimized for the Task.Run operations and it shouldn't ever be used to offload the execution of a portion of code. On the opposite side, let's examine another case:
public Task<int> AddAsync(int a, int b) { return Task.FromResult(a + b); }
In this case, the Task.FromResult method will wrap the pre-computed result without wasting a thread pool which means that we will not have the overhead provided by the execution of the Task.Run operation.