I have written an api end point in asp.net core and getting error cannot convert void to an object
I am getting error in line.What I understand is SendEmailReminder method returns void but how do I handle that in the controller. If I remove await the error goes but then I get the warning that the method would be executed synchronously. Could somebody help
return Ok(await _counterpartyProposalService.SendEmailReminder());
Controller
[HttpPost]
[Route("sendEmailReminder")]
public async Task<IActionResult> SendEmailReminders()
{
return Ok(await _counterpartyProposalService.SendEmailReminder());
}
public async Task SendEmailReminder()
{
var stepCode = StepCodes.BasicInformation;
var command = _commandResolver(stepCode, null);
await command.ExecuteEmailReminder();
}
You can refactor your code in the following manner, assuming that your HTTP call is not returning any content. By doing this, you will return HTTP 204.
[HttpPost]
[Route("sendEmailReminder")]
public async Task<IActionResult> SendEmailReminders()
{
await _counterpartyProposalService.SendEmailReminder();
NoContent();
}
public async Task SendEmailReminder()
{
var stepCode = StepCodes.BasicInformation;
var command = _commandResolver(stepCode, null);
await command.ExecuteEmailReminder();
}
This is the signature of Ok method:
public virtual OkObjectResult Ok([ActionResultObjectValue] object value)
The reason you do not get the error, when you remove the await keyword is because Ok is taking the Task object as input.
Related
I have problem with calling API in my Discord Bot, I am trying to learn async, await but it seems as I am stuck.
This is my Call API class where I am calling API.
public async Task<Root> GetInfoAsync()
{
string path = "https://onemocneni-aktualne.mzcr.cz/api/v2/covid-19/zakladni-prehled.json";
Root data = null;
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
string json = await response.Content.ReadAsStringAsync();
data = JsonConvert.DeserializeObject<Root>(json);
}
return data;
}
public async Task<string> VypisAsync()
{
Root data = await this.GetInfoAsync();
int deaths = data.data[0].umrti,
recovered = data.data[0].vyleceni,
positive = data.data[0].aktivni_pripady,
hospitalized = data.data[0].aktualne_hospitalizovani;
return $"Aktualni situace v ČR:\n" +
$"vyleceni: {recovered}\n" +
$"aktualne nemocni: {positive}\n" +
$"hospitalizovani: {hospitalized}\n" +
$"zemreli: {deaths}";
}
And here is my covid command
public class CovidModule : ModuleBase<SocketCommandContext>
{
// ~void -> current covid situation in CZ
[Command("covid")]
[Summary("shows current covid situation in CZ")]
public async Task<Task> CovidAsync()
{
CovidApi api = new CovidApi();
return ReplyAsync(await api.VypisAsync());
}
}
I know that all others commands return Task, but I don't know how to make it like that.
ReplyAsync() is an async method, so you need to await it.
Your CovidAsync() method isn't returning an actual value, so in the synchronous world its return value would be void. Since it's an async method you return Task instead.
public async Task CovidAsync()
{
CovidApi api = new CovidApi();
await ReplyAsync(await api.VypisAsync());
}
As an aside, it would be better to have CovidApi as a member of your CovidModule. That way you don't need to keep newing it up in each method.
I am using asp.net core web api and I need to execute one task OneTask and on successful execution of OneTask it should return OK staus otherwise error response. I want HttpResponseMessage and can something return return Ok(awit OneTask());
[HttpPost]
public async Task<OkObjectResult> Post()
{
await OneTask;
return Ok(new HttpResponseMessage(HttpStatusCode.OK));
}
public async Task OneTask()
{
await //some task
}
The IActionResult<T> interface is the best practice to respond to the client.
So change the code like this :
[HttpPost]
[Route("PostWithValue")]
public async Task<IActionResult> PostWithValue()
{
var result = await OneTaskWithReturnValue();
return Ok(result);
}
public async Task<bool> OneTaskWithReturnValue()
{
await Task.Delay(100);
return true;
}
Also, beware of async void (Task without <T>) that is a bad idea because you have problem with handling exceptions :
In a nutshell:
[HttpPost]
[Route("PostWithValue")]
public async Task<IActionResult> PostWithValue()
{
var result = await OneTaskWithReturnValue();
if (!result)
{
return BadRequest("Message for Error");
}
return Ok("Message for OK Status");
}
public async Task<bool> OneTaskWithReturnValue()
{
await Task.Delay(100);
// Do you task
return true;
}
What is the correct return type for DELETE HTTP actions when returning a NoContent response?
[HttpDelete]
[ProducesResponseType(StatusCodes.Status204NoContent, Type = typeof(User))]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[Route("{id}")]
public async Task<ActionResult<void>> DeleteUserById(Guid id)
{
return NoContent();
}
Of course I can't use that because void can't be used as a type. But I can't use this either
public async void DeleteUserById(Guid id)
{
return NoContent();
}
because I'm returning something.
If you are going to return NoContent() you should use a prototype like this (remove void):
public async Task<ActionResult> DeleteUserById(Guid id)
{
return NoContent();
}
I am working on a Url Shortener in Asp.Net Core and using MongoDB.
I currently have a working Get method and a working Create method.
I ran into an issue with my Delete method and this is the message I get:
Argument 1: cannot convert from
'MongoDB.Driver.FilterDefinition)', candidates
are: System.Threading.Tasks.Task
DeleteOneAsync(MongoDB.Driver.FilterDefinition,
System.Threading.CancellationToken)(in interface
IMongoCollection)
System.Threading.Tasks.Task
DeleteOneAsync(this
MongoDB.Driver.IMongoCollection,
System.Linq.Expressions.Expression>,
System.Threading.CancellationToken) (in class
IMongoCollectionExtensions)
The error has something to do with this ".DeleteOneAsync(filter);" in my 'ShortUrlRepository' class:
public async Task<ShortUrl> Delete(ShortUrl su)
{
var filter = Builders<Url>.Filter.Eq("Su", su);
return await _db.Urls.DeleteOneAsync(filter);
}
My ShortUrlsController class seems to be working just fine but I will post it in case:
namespace ShortenUrls.Controllers
{
[Route("api/codes")]
public class ShortUrlsController : Controller
{
private readonly ShortUrlRepository _repo;
//private readonly IShortUrlService _service;
public ShortUrlsController(ShortUrlRepository repo /*IShortUrlService service*/)
{
_repo = repo;
//_service = service;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(string id)
{
var su = await _repo.GetAsync(id);
if (su == null)
return NotFound();
return Ok(su);
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] ShortUrl su)
{
await _repo.CreateAsync(su);
return Ok(su);
}
[HttpDelete("{id}")]
public async Task<IActionResult> Delete (ShortUrl su)
{
try
{
if (su == null)
return new NotFoundResult();
await _repo.Delete(su);
return Ok("Deleted Successfully");
}
catch (Exception ex)
{
return BadRequest(ex.ToString());
}
}
}
}
I have tried other remove methods but have gotten similar errors so maybe I am missing something?
If anyone can offer some suggestions I would greatly appreciate it as I am new to Asp.Net Core and I am having very little success finding a solution to this error. If I can provide anymore information please let me know.
Creating the variable 'r' and returning it solved the 'Argument 1 error':
public async Task<bool> Delete(ObjectId id)
{
var filter = Builders<ShortUrl>.Filter.Eq(x => x.Id, id);
var r = await _db.Urls.DeleteOneAsync(filter);
return r.DeletedCount > 0;
}
I made other changes that were unrelated to this error but were necessary to make the Delete method work properly. Here are the changes I had to make to my 'ShortUrlsController' class:
[HttpDelete("{id}")]
public async Task<IActionResult> Delete (string id)
{
return (await _repo.Delete(ObjectId.Parse(id)))
? (IActionResult) Ok("Deleted Successfully")
: NotFound();
}
Code first. This is what I'm trying to do. I'm close, but I think I just need to fix the way I've defined my parameter in the UpdateButton method.
private async void UpdateButton(Action<bool> post)
{
if (!await post())
ErrorBox.Text = "Error posting message.";
}
private void PostToTwitter()
{
UpdateButton(async () => await new TwitterAction().Post("Hello, world!"));
}
private void PostToFacebook()
{
UpdateButton(async () => await new FacebookAction().Post("Hello, world!"));
}
Unfortunately, the !await post() doesn't work because, "Type 'void' is not awaitable." So the question is, how do I define my parameter in this method to support an awaitable parameter?
Here's how the TwitterAction().Post() is defined...
public virtual async Task<bool> Post(string messageId){...}
private async void UpdateButton(Func<Task<bool>> post)
{
if (!await post())
ErrorBox.Text = "Error posting message.";
}
--EDIT--
UpdateButton(()=>Post("ss"));
private async void UpdateButton(Func<Task<bool>> post)
{
if (!await post())
this.Text = "Error posting message.";
}
public virtual async Task<bool> Post(string messageId)
{
return await Task.Factory.StartNew(() => true);
}
You need to pass this as a Task<bool>, not an Action<bool>.
This provides something that's "awaitable".
I believe this will work, given your current code:
private async Task UpdateButtonAsync(Task<bool> post)
{
if (!await post)
ErrorBox.Text = "Error posting message.";
}
// This will work if Post returns Task<bool> in the current API...
private void PostToTwitter()
{
UpdateButtonAsync(new TwitterAction().Post("Hello, world!"));
}
If you do not want to start the Task<bool> immediately, and need to keep it as passing a lambda, there is still no reason for the lambda to be async. In that case, you could use:
private async Task UpdateButtonAsync(Func<Task<bool>> post)
{
if (!await post())
ErrorBox.Text = "Error posting message.";
}
// This will work if Post returns Task<bool> in the current API...
private void PostToTwitter()
{
UpdateButtonAsync(() => new TwitterAction().Post("Hello, world!"));
}
This causes the lambda to return the Task<bool> (no async/await required, as Post already returns Task<bool>), and the update method to run the lambda.
Personally, I find the first option (above) simpler, and suspect it is more likely what you want. Given your API already returns Task<T>, you can just pass that around and await it directly.