How to call an async Task<ActionResult<>> from another method - c#

I have the following method and I want to call this from another method in the same controller. I have tried Task.Run but I can't seem to get it to work. This is .Net Core.
Here is the method I want to call:
[HttpGet("GetInfo")]
public async Task<ActionResult<InfoModel>> GetInfo()
{
InfoModel si = new InfoModel()
//Do work
return si
}
I then want to call it in another API method (below)
[HttpPost("GetOtherInfo")]
public async Task<ActionResult<NewModel>> GetOtherInfo(RequestInfoModel req)
{
NewModel ret = new NewModel();
//Do some work
//Need some data from the GetInfo() method
InfoModel im1 = GetInfo(); //This does not work
//Do work with im1
return ret;
}
I am looking for help on how to call GetInfo() from within GetOtherInfo(). Thank you in advance.

As a controller action GetInfo() is meant to be called by the framework when satisfying requests.
That fact that it has to be called in addition to that is a violation of SRP/SoC and a code smell. This indicates that a refactor is needed.
Either move that functionality into another method or another class if needed external to just this controller. That way it can be reused as needed.
private Task<InfoModel> getInfoAsync() {
InfoModel model = new InfoModel();
//Do async work
return model;
}
[HttpGet("GetInfo")]
public async Task<ActionResult<InfoModel>> GetInfo() {
InfoModel model = await getInfoAsync();
//and additional work needed specific to this request
return model;
}
[HttpPost("GetOtherInfo")]
public async Task<ActionResult<NewModel>> GetOtherInfo(RequestInfoModel req) {
NewModel ret = new NewModel();
//Do some work
//Need some info data
InfoModel im1 = await getInfoAsync();
//Do work with im1
return ret;
}

If your method is returning a Task<X>, you need to await the results.
[HttpPost("GetOtherInfo")]
public async Task<ActionResult<NewModel>> GetOtherInfo(RequestInfoModel req)
{
NewModel ret = new NewModel();
//Do some work
//Need some data from the GetInfo() method
InfoModel im1 = await GetInfo();
//Do work with im1
return ret;
}
Note that it's usually a good idea to follow conventions and add the Async suffix to methods returning a Task.
ex: GetInfoAsync()

Related

Calling multiple async methods within other method without returning result

I am working on an ASP.NET Core 2.2 application with Dapper. Virtually all methods follows the async/await pattern returning some sort of Task as a result.
Due to an issue we had with Dapper (I haven't personally investigated it, this part of the code I use as it is) but basically it boils down to the fact that if you want to execute in Transaction multiple async methods, which internally are calling other async methods and you may have several levels of nesting this way, you need to wrap all those method invocations within a single method which would be executed in a transaction.
The method that handles this is as follows:
public async Task<TOut> ExecuteInTransactionAsync<TOut>(
Delegate function,
params object[] parameters)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await ((Task<TOut>)function.DynamicInvoke(parameters))
.ConfigureAwait(false);
scope.Complete();
return result;
}
}
So I have a very complex Entity which is saved by calling Save to a lot of smaller entities. This part of the code is working OK and looks like this:
public async SaveEntireEntity(EntityDTO entityDTO)
{
return await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task<dynamic>>(async dto => await SaveInTransaction(dto)),
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age });
}
And the SaveInTransaction method looks like:
private async Task<dynamic> SaveInTransaction(dynamic dto)
{
var entityId = await nameService.Add(dto.Name);
await addressService.Add(dto.Address);
await ageService.Add(dto.Age);
return entityId;
}
so this is simplified, but indeed I am calling a multiple services here, which on their part are calling multiple repositories and this works fine.
The Problem I have is when it comes to updating the same entity within a transaction. The whole purpose of showing the Save logic was to point out that at the end because I have this return entityId; I am able to chain everything together without any problems. However, as it is right now, by default our Update methods are not returning anything and this is where I can't figure out how to implement the Update logic.
Currently I have this:
public async Task UpdateEntireEntity(UpdateEntityDTO, entityDTO)
{
await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task<dynamic>>(async dto => await UpdateInTransaction(dto)),
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age });
}
And UpdateInTransaction looks like this:
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return await Task.FromResult<dynamic>(null);
}
This seems to work at least based on the several tests I made, however I really don't like this part:
return await Task.FromResult<dynamic>(null);
To me it seems like an ugly hack. The Update methods were thought not to return any value and this is just too artificial.
And even the worst part is that I can not figure out how implement the update method without having to return something.
One thing I've tried is to change the declaration of UpdateInTransaction to
private async Task UpdateInTransaction(dynamic dto)
and when I call the method I change it to:
await _transactionProvider.ExecuteInTransactionAsync<dynamic>(
new Func<object, Task>( async dto => await UpdateInTransaction(dto)..
But I got the following exception:
AsyncStateMachineBox1[System.Threading.Tasks.VoidTaskResult,
<fully-qualified- name>.<<UpdateEntireEntity>b__0>d] to type
'System.Threading.Tasks.Task1[System.Threading.Tasks.Task]'
.
So basically that's it. Sorry for the long post. I would really appreciate some well explained answer.
I would avoid the use of Delegate since it isn't typed:
public async Task<TOut> ExecuteInTransactionAsync<TOut>(Func<Task<TOut>> function)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
var result = await (function()).ConfigureAwait(false);
scope.Complete();
return result;
}
}
This signature would mean you'd need to capture parameters rather than pass them:
public async Task<dynamic> SaveEntireEntity(EntityDTO entityDTO)
{
return await _transactionProvider.ExecuteInTransactionAsync(
async () => await SaveInTransaction(
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age }));
}
Once you're using the strongly-typed Func<Task<T>> instead of Delegate in your method signature, you can create an overload for ExecuteInTransactionAsync as such:
public async Task ExecuteInTransactionAsync(Func<Task> function)
{
using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
await (function()).ConfigureAwait(false);
scope.Complete();
}
}
which can be used as such:
public async Task UpdateEntireEntity(UpdateEntityDTO entityDTO)
{
await _transactionProvider.ExecuteInTransactionAsync(
async () => await UpdateInTransaction(
new { Name = entityDTO.Name, Address = entityDTO.Address, Age = entityDTO.Age }));
}
private async Task UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
}
You can change
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return await Task.FromResult<dynamic>(null);
}
to
private async Task<dynamic> UpdateInTransaction(dynamic dto)
{
await UpdateName(dto.Name);
await UpdateAddress(dto.Address);
await UpdateAge(dto.Age);
return null;
}

Cannot make RestSharp send parameter of object to web api controller (always null)?

I have a simple controller method like this:
public IEnumerable<IEntity> GetEntities(ParamsModel args)
{
//set break point here to examine the args
return null;
}
And here is my ParamsModel:
public class ParamsModel {
public string Test;
}
And here is my client's method to send get request:
//_client here is an instance of RestClient
public async Task<IEnumerable<T>> GetEntitiesAsync()
{
var request = new RestRequest("somePath");
var o = new {
Test = "OK"
};
request.AddJsonBody(o);
return await _client.GetAsync<List<T>>(request);
}
After running the method GetEntitiesAsync, the break point (in the controller's method) is hit. However the args is null, really?
I've also tried the following:
public async Task<IEnumerable<T>> GetEntitiesAsync()
{
var request = new RestRequest("somePath");
request.AddParameter("Test", "OK");
return await _client.GetAsync<List<T>>(request);
}
However that did not work as well (args is null in the controller's method).
If I change the controller's method to something like this (and use the client code as right above), I can see the single simple argument of string has value parsed OK ("OK") inside the controller's method:
public IEnumerable<IEntity> GetEntities(string Test)
{
//here we can see that Test has value of "OK"
return null;
}
Really I don't understand what's wrong with my code.
Actually I worked with RestSharp at least a year ago but now it seems to have some new methods (such as the GetAsync as I used in my code), as before I used the Execute and ExecuteAsync.
Could you spot anything wrong here? Thanks!
PS: I'm using RestSharp 106.6.7
Update action to state explicitly where to look for and bind data using [FromUri]
public IHttpActionResult GetEntities([FromUri]ParamsModel args) {
//...
return Ok(entities);
}
To force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter.
Reference Parameter Binding in ASP.NET Web API
The example with AddParameter
public async Task<IEnumerable<T>> GetEntitiesAsync() {
var request = new RestRequest("somePath");
request.AddParameter("Test", "OK");
return await _client.GetAsync<List<T>>(request);
}
Should work now.
Note that the model should use properties instead of fields
public class ParamsModel {
public string Test { get; set; }
}

Should Semaphoreslim be in the controller instead of further down in the chain?

We have a deadlock like behaviour in our production-environment and I wonder if we use SemaphoreSlim correctly.
In our restapi the code looks like this:
public async Task<IActionResult> CreateAsync([FromBody] SomeModel someModel)
{
var result = await _someClass.CreateArende(someModel);
return result;
}
public async Task<IActionResult> RegisterAsync([FromBody] SomeModel someModel)
{
var result = await _someClass.RegisterArende(someModel);
return result;
}
No SemphoreSlim in controller level of our API but in someClass looks like this:
public class SomeClass
{
protected static SemaphoreSlim _semphoreSlimCreateArende = new SemaphoreSlim(1, 1);
public async virtual Task<SomeResponseDto> CreateArende(SomeModel someModel)
{
try
{
await _semphoreSlimCreateArende.WaitAsync();
}
finally
{
try
{
_semphoreSlimCreateArende.Release();
}
catch (Exception)
{
}
}
return new SomeResponseDto()
{
...
};
}
public async virtual Task<SomeResponseDto> RegisterArende(SomeModel someModel)
{
try
{
await _semphoreSlimCreateArende.WaitAsync();
}
finally
{
try
{
_semphoreSlimCreateArende.Release();
}
catch (Exception)
{
}
}
return new SomeResponseDto()
{
...
};
}
}
Should the SemaphoreSlim be in the controller level instead? Or should I change the controllers actions to not be async?
This question is a little disjointed, however lets try to make sense of it a little
Firstly lets get the pattern right
try
{
await _semphoreSlimCreateArende.WaitAsync();
// do your sync work here
}
finally
{
// if this throws you are certainly doing something wrong
_semphoreSlimCreateArende.Release();
}
Secondly, you should have your keyboard taken away from you for this
catch (Exception)
{
}
Don't ever blindly eat exceptions, and if you are getting them on _semphoreSlimCreateArende.Release you have serious problems already and you have to work out why
Should the semaphoreslim be in the controller level instead?
Use them at the level that makes the most sense, i mean if you need to sync a piece of code sync it there, not 13 levels up.
Or should i change the controllers actions to not be async?
if you have asnyc work make your controller async and let it propagate down the stack to your async code
We have a deadlock like behaviour in our production-environment and i
wonder if we use semaphoreslim correctly.
Woah, are we talking DataBase Deadlocks, or Context DeadLocks. Either way this all sounds a little fishy

Invoke Async Funcs

I've made a nice controller helper in my MVC project that allows me to return similarly structured result payloads when I make any ajax request. It looks like this:
public static JsonNetResult Responsify<T>(Func<T> func)
{
AjaxResponse response;
var result = new JsonNetResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
try
{
var resp = func();
response = AjaxResponse.SuccessResponse(resp);
result.Data = response;
}
catch (Exception e)
{
response = AjaxResponse.ErrorResponse(e.Message);
result.Data = response;
}
return result;
}
and it gets used like this:
[HttpPost]
public JsonNetResult Link(LinkInstruction instruction)
{
return ControllerHelper.Responsify(() => _linkHandler.Link(instruction));
}
where _linkHandler.Link is not async.
My issue is I have some async handlers that I would like to invoke using this pattern and I can't figure out how to await the function. I've tried Task.Factory.StartNew as well as wrapping the lambda in async/await and I can't quite figure it out.
Create a version of Responsify - call it ResponsifyAsync - that specifies that the passed Func must return a Task<T> (therefore meaning you can await it):
public async static JsonNetResult ResponsifyAsync<T>(Func<Task<T>> func)
{
...
}
This would do much what your current function does, but would await func() instead of just executing it.
You must then pass a Func delegate that returns a Task to this method. When calling an async library in the delegate, since the async method you're calling already returns a Task, this will simply take the form:
var x = await ResponsifyAsync(() => _someClass.MyMethodAsync(someParameter));
Or, if the method is parameterless...
var x = await ResponsifyAsync(_someclass.MyMethodAsync);
I'll let you flesh out the method but this format should set you off on the right lines.

How to return data using await function in C# windows phone 8?

I'm new to C#. I
I've a problem related to async methods and await function in C# windows phone 8.0.
I've this http request and can get response. This is working fine and There is no issue...
public async static Task<List<MyAccountData>> GetBalance()
{
HttpClient = new HttpClient();
string response = await client.GetStringAsync("http://xxxx/xxx/xxx");
List<MyAccountData> data = JsonConvert.DeserializeObject<List<MyAccountData>>(response);
return data;
}
I've another class call MainModel
public class MainModel
{
public void LoadData()
{
}
}
So My problem is, I want to call that GetBalance method with in MainModel class and parse data to LoadData method(simply want 2 access Data with in LoadData method). LoadData method can't change return type or can't use async. So how is this possible?
If you want a responsive UI - i.e., one that has a chance of being accepted in the store - then blocking on the async operation is not an option.
Instead, you have to think a bit about how you want your UI to look while the operation is in progress. And while you're thinking about that, also think about how you would want your UI to respond if the operation errors out.
Then you can code up a solution. It's possible to do this with async void, if you catch all exceptions and handle them cleanly:
public async void LoadData()
{
try
{
... // Set up "loading" UI state.
var balance = await GetBalanceAsync();
... // Set up "normal" UI state.
Balance = balance;
}
catch
{
... // Set up "error" UI state.
}
}
However, I prefer to use a type I created called NotifyTaskCompletion, which is a data-bindable wrapper for Task<T> (described in my MSDN article). Using NotifyTaskCompletion, the LoadData becomes much simpler:
public void LoadData()
{
GetBalanceOperation = new NotifyTaskCompletion<Balance>(GetBalanceAsync());
}
public NotifyTaskCompletion<Balance> GetBalanceOperation // Raises INotifyPropertyChanged when set
Then your UI can data-bind to properties on NotifyTaskCompletion<T>, such as IsNotCompleted (for the "loading" state), IsSuccessfullyCompleted and Result (for the "normal" state), and IsFaulted and ErrorMessage (for the "error" state).
There is no difference to use async await in Windows Phone 8 dev:
public class MainModel
{
public async void LoadData()
{
var data = await Foo.GetBalance();
}
}
Depends on whether you want LoadData to be synchronous (not returning until all the data has been streamed in over HTTP, and locking up the UI until then), or to begin the process and return immediately. If you can't change LoadData to async, then those are your only two options.
If you want LoadData to be synchronous:
public void LoadData() {
var task = GetBalance();
var result = task.Result; // will lock up the UI until the HTTP request returns
// now do something with result
}
If you want it to start a background process and return immediately, but for some reason don't want to mark LoadData as async:
public void LoadData() {
BeginLoadData();
}
private async void BeginLoadData() {
var result = await GetBalance();
// now do something with result
}
Though really, there's no reason not to go ahead and make LoadData async. async void does not force you to change the callers in any way (unlike Async<Task<T>>), and it's assignment-compatible with plain old non-async delegates:
public async void LoadData() {
var result = await GetBalance();
// now do something with result
}
// ...
LoadData(); // works just fine
Action myAction = LoadData; // works just fine
As you are working on asynchronus operations you need to wait until the operation is completed.The return type async/await method is always Task(TResult), to access the result of the async/await you need to use Result Property.The get accessor of Result property ensures that the asynchronous operation is complete before returning.
public void LoadData()
{
var data = GetBalance().Result;
}

Categories