Somehow I end up with the rare situation that an id is returned, but the blob hasn't been saved. Is there anything I'm missing in below code regarding C# 6 async in catch-statements or maybe an odd bug in the Azure libraries?
private async Task<string> Save(Stream stream)
{
var id = Guid.NewGuid();
var blob = ...;
try
{
await blob.UploadFromStreamAsync(stream);
}
catch
{
if (await blob.ExistsAsync())
{
await blob.DeleteAsync();
}
throw;
}
return id;
}
Related
Is it possible to use EF Core interceptors for catching database connection issues, like invalid username/password, update them by using an API call and re-try the same query?
Perhaps perform a check once in your app before running current code, here is a language extension.
public static class Extensions
{
public static async Task<(bool success, Exception exception)> CanConnectAsync(this DbContext context)
{
try
{
var result = await Task.Run(async () => await context.Database.CanConnectAsync());
return (result, null);
}
catch (Exception localException)
{
return (false, localException);
}
}
}
Usage
public static async Task Demo()
{
await using var cn = new CustomerContext();
var (success, exception) = await cn.CanConnectAsync();
if (success)
{
// connected
}
else
{
// examine exception variable
}
}
I have some PDFs stored in my dropbox location and want users to be able to retrieve them via a call to an API.
[HttpGet("{key}")]
public async Task<ActionResult> GetPDF(string key) {
string? path = GetPath(key);
if (path == null) {
return NotFound();
}
using(System.Net.Http.HttpClient wc = new System.Net.Http.HttpClient()) {
try {
using(System.IO.Stream stream = await wc.GetStreamAsync(path)) {
// using(System.IO.Stream stream = wc.GetStreamAsync(path).GetAwaiter().GetResult()) {
return new FileStreamResult(stream, "application/pdf");
}
} catch(System.Exception ex) {
return NotFound();
}
}
}
It runs right through, without hitting the exception, and returns, then gives the error
The ReadAsync method cannot be called when another read operation is pending.
Waiting for the async method didn't help.
Your primary issue appears to be that the stream has been disposed before the function returns. FileStreamResult will dispose the stream, you don't need to do that.
Also, HttpClient should be a global field, otherwise you could get socket exhaustion issues.
HttpClient wc = new HttpClient();
[HttpGet("{key}")]
public async Task<ActionResult> GetPDF(string key)
{
string? path = GetPath(key);
if (path == null)
{
return NotFound();
}
try
{
var stream = await wc.GetStreamAsync(path);
return new FileStreamResult(stream, "application/pdf");
}
catch(System.Exception ex)
{
return NotFound();
}
}
I appreciate this question has been asked. But I seem to have done what people are suggesting to fix it and I am still having the same issue. I can't see where I am going wrong. Any help would be greatly appreciated.
I am getting the following error:
InvalidOperationException: A second operation started on this context
before a previous operation completed. This is usually caused by
different threads using the same instance of DbContext
In these specific areas:
return await _dbContext.Set<T>().FindAsync(id);
var editPost = await _postRepository.GetByIdAsync(postModel.Id);
await _postAppService.Update(mapped);
await _postPageService.UpdatePost(Post);
Here is my code:
Just to add a bit more detail. I will list the exact steps:
First I select the post I would like to edit. The following gets called:
public async Task<IActionResult> OnGetAsync(int? postId)
{
if (postId == null)
{
return NotFound();
}
Post = await _postPageService.GetPostById(postId.Value);
if (Post == null)
{
return NotFound();
}
return Page();
}
public async Task<PostViewModel> GetPostById(int postId)
{
var post = await _postAppService.GetPostById(postId);
var mapped = _mapper.Map<PostViewModel>(post);
return mapped;
}
public async Task<PostModel> GetPostById(int postId)
{
var post = await _postRepository.GetByIdAsync(postId);
var mapped = ObjectMapper.Mapper.Map<PostModel>(post);
return mapped;
}
public virtual async Task<T> GetByIdAsync(int id)
{
return await _dbContext.Set<T>().FindAsync(id);
}
I then make my changes and click the update button:
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
try
{
await _postPageService.UpdatePost(Post);
}
catch (DbUpdateConcurrencyException)
{
if (!PostExists(Post.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
public async Task UpdatePost(PostViewModel postViewModel)
{
var mapped = _mapper.Map<PostModel>(postViewModel);
if (mapped == null)
throw new Exception($"Entity could not be mapped.");
await _postAppService.Update(mapped);
_logger.LogInformation($"Entity successfully added - IndexPageService");
}
public async Task Update(PostModel postModel)
{
ValidatePostIfNotExist(postModel);
var editPost = await _postRepository.GetByIdAsync(postModel.Id);
if (editPost == null)
throw new ApplicationException($"Entity could not be loaded.");
ObjectMapper.Mapper.Map<PostModel, Post>(postModel, editPost);
await _postRepository.UpdateAsync(editPost);
_logger.LogInformation($"Entity successfully updated - AspnetRunAppService");
}
public async Task UpdateAsync(T entity)
{
_dbContext.Entry(entity).State = EntityState.Modified;
await _dbContext.SaveChangesAsync();
}
I have also set the lifetime of my DbContext to Transient.
services.AddDbContext<MyJourneyContext>(c => c.UseSqlServer(_config.GetConnectionString("MyJourneyConnectionString")),
ServiceLifetime.Transient);
So I am using await and have set the lifetime of my DbContext to Transient. But I am clearly still doing something wrong. Can anyone help me with this?
I learning Xamarin, I use a function to delete all my sqlite database, add new elements and refesh my listview.
the code stop, I thinks it is because it has not time for delete first,add in database then refresh thelist view. When I add a timer (2 seconds) it works.
Here is the error at the line "mywordsdatabase.DeleteAllWords();" : System.ArgumentOutOfRangeException: 'Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index'
I am using this sqlite plugin enter link description here
Here is the function :
public async void DeleteAndUpdate(){
mywordsdatabase.DeleteAllWords(); // the error occur here
List<MyWords> WordUserList = await wordmanager.GetWordAsync(UserConnected.MyId);
foreach (MyWords w in WordUserList)
{
mywordsdatabase.AddWord(w);
}
var WordList = await mywordsdatabase.GetWords();
Device.BeginInvokeOnMainThread(() => { WordSList.ItemsSource = WordList; });
}
Here is the Delete function for sqlite:
class MyWordsDatabase
{
private SQLiteAsyncConnection conn;
//CREATE
public MyWordsDatabase()
{
conn = DependencyService.Get<ISQLite>().GetConnection();
conn.CreateTableAsync<MyWords>();
}
public string AddWord(MyWords mywords)
{
conn.InsertAsync(mywords);
return "success";
}
public string DeleteAllWords()
{
conn.DeleteAllAsync<MyWords>();
return "success";
}
}
Thanks for your help
Few things to check, first of ensure the database actually has words to delete, as the error would suggest that it tried to operate upon a null element. Secondly, since the method is async, see if changing the signature will help.
So instead of public string DeleteAllWords() it becomes public async string DeleteAllWords() then inside of the method we can say await conn.DeleteAllAsync<MyWords>(); and where we call it we can then do await mywordsdatabase.DeleteAllWords();
As jmcil said, async code won't wait for its operation to stop execution unless told to do so.
The whole point of asynchronous methods is that they are asynchronous, i.e. they return immediately while the work they initiated continues in the background. If you call that DeleteAllAsync method and then immediately start executing code as though it has finished deleting everything then of course you'll have issues. If you need the deletion to be completed before subsequent code is executed then you need to wait until the deletion is completed before executing that subsequent code. The way to do that is most likely to await the awaitable methods in your code. This:
public string DeleteAllWords()
{
conn.DeleteAllAsync<MyWords>();
return "success";
}
probably ought to be this:
public async Task<string> DeleteAllWordsAsync()
{
await conn.DeleteAllAsync<MyWords>();
return "success";
}
That means that you can either await the call to that method:
await mywordsdatabase.DeleteAllWordsAsync();
or you can trap the Task it returns, execute some code that doesn't depend on it completing and then await the Task later:
var t = mywordsdatabase.DeleteAllWordsAsync();
// ...
await t;
Please change your DeleteAllWords method like following method.
public Task<int> DeleteAllNotesAsync()
{
return conn.DeleteAllAsync<MyWords>();
}
Then judge the return value if it greater than 0, it the return value greater than 0, it means delete success like this simple code.
private async void Button_Clicked(object sender, EventArgs e)
{
int deleteRecord= await App.Database.DeleteAllNotesAsync();
if (deleteRecord>0)
{
await DisplayAlert("Success", "delete" + deleteRecord, "OK");
}
}
public async Task<string> AddWord(MyWords mywords)
{
string result=string.Empty;
try
{
await conn.InsertAsync(mywords);
}
catch (Exception ex)
{
}
return result;
}
public async Task<string> DeleteAllWords()
{
string result = string.Empty;
try
{
await conn.DeleteAllAsync<MyWords>();
}
catch (Exception ex)
{
}
return result;
}
public async void DeleteAndUpdate()
{
try
{
await mywordsdatabase.DeleteAllWords(); // the error occur here
List<MyWords> WordUserList = await wordmanager.GetWordAsync(UserConnected.MyId);
foreach (MyWords w in WordUserList)
{
await mywordsdatabase.AddWord(w);
}
var WordList = await mywordsdatabase.GetWords();
Device.BeginInvokeOnMainThread(() => { WordSList.ItemsSource = WordList; });
}
catch (Exception ex)
{
}
}
I'm trying to wrap my Operations Contracts to the try-catch block. The problem is that my EF context destroyed in the same time scope. I guess the problem compiler doesn't know what to do properly. Also my catch block doesn't handle any exceptions. Sorry for my English, I hope my code show what I mean:
private static async Task<T> SurroundWithTryCatch<T>(Action t, T response) where T : BaseResponse
{
try
{
await Task.Run(t);
}
catch (Exception e)
{
response.Success = false;
response.Errors.Add(e.Message);
}
return response;
}
public async Task<CreateResponse> CreateAsync(CreateRequest request)
{
var response = new CreateResponse();
return await SurroundWithTryCatch(async delegate
{
var newUser = new ApplicationUser { UserName = request.UserName, Email = request.Email };
await Database.UserManager.CreateAsync(newUser, request.Password);
//Some another logic...
await Database.CommitAsync();
}, response);
}
The problem in the second line of CreateAsync method. UserManager was cleaned by GC earlier. So I have ObjectDisposedException. Database is the IUnitOfWork implementation and injected by Autofac.
You're breaking the await chain - t no longer returns a task. Since you no longer have a task, the execution will continue after the first await, rather than after the whole method is done. Think of await as return - if you don't return (and await/wait for) a Task, you lose your chance at synchronization.
Instead, you want to pass Func<Task>, and await it directly:
private static async Task<T> SurroundWithTryCatch<T>(Func<Task> t, T response) where T : BaseResponse
{
try
{
await t();
}
catch (Exception e)
{
response.Success = false;
response.Errors.Add(e.Message);
}
return response;
}
public async Task<CreateResponse> CreateAsync(CreateRequest request)
{
var response = new CreateResponse();
return await SurroundWithTryCatch(async () =>
{
var newUser = new ApplicationUser { UserName = request.UserName, Email = request.Email };
await Database.UserManager.CreateAsync(newUser, request.Password);
//Some another logic...
await Database.CommitAsync();
}, response);
}
Task.Run also works, but you probably don't want that anyway - your code is asynchronous, and (a guess) you're running in a ASP.NET request, so there's no benefit to launching a task just to wait on the result of another task. Task.Run is used for doing CPU work in a separate thread, something you usually want to avoid in ASP.NET.