Reputation: 38130
I'm attempting to write to a file but "occasionally" I run into issues that I think are down to concurrency, as some of the time, I'm getting a System.UnauthorizedAccessException
with message:
Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
...from the following:
public async void SubmitChanges()
{
DataContractSerializer serializer =
new DataContractSerializer(typeof(LocalCache<T>));
StorageFile file = await ApplicationData.Current.LocalFolder
.CreateFileAsync(GetFileNameForType(),
CreationCollisionOption.ReplaceExisting);
//Occasionally throws here
using (var fi = await file.OpenTransactedWriteAsync())
{
serializer.WriteObject(fi.Stream.AsStreamForWrite(), this);
await fi.CommitAsync();
}
}
I can only assume that this is down to some concurrency, or it being still open for read somewhere else, but I can't seem to find a way to wait for it to become available - I'd normally lock
around it, but this is not allowed with await
so what are the other options?
Upvotes: 1
Views: 2209
Reputation: 3550
There are a number of things that could be happening here. As Stephen mentioned above, your encapsulating method does not return a task. This means that whatever method is calling SubmitChanges is calling it with a "fire and forget" pattern and code that follows this call can be run in parallel. This is probably not what you want.
In addition, I notice you're using StorageFile.OpenTransacted. I've not used this before but the notes indicate OpenTransacted is only supported on operating systems that support ReplaceFile. This feature literally allows the new file to assume the identity of the old file, but I'm pretty sure that operation would fail if the old file is open.
I don't think the attempt to swap file identities would happen until the transacted file is closed, which would happen on Dispose, which happens automatically due to the using statement, which is the line you're sometimes seeing the exception.
I would recommend you return a Task instead and I would also consider using the regular StorageFile.OpenAsync.
Upvotes: 1
Reputation: 456507
Usually, you just don't start the next operation until the previous operation is complete.
Tip: avoid async void
; use async Task
instead. That enables you to know when the previous operation is complete.
Upvotes: 6