How To Delete A File Being Used By Another Process? - c#

Before I begin, I should mention that this isn't really something I want to do, I'm simply curious about how it works.
I have this method called AddLayer(), which opens a local geodatabase file and creates a map with it:
public async void AddLayer()
{
try
{
// open a geodatabase on the local device
gdb = await Geodatabase.OpenAsync(#"..\..\..\test.geodatabase");
// get the first geodatabase feature table
var gdbFeatureTable = gdb.FeatureTables.FirstOrDefault();
//create a layer for the feature table
lyr = new FeatureLayer
{
ID = gdbFeatureTable.Name,
DisplayName = gdbFeatureTable.Name,
FeatureTable = gdbFeatureTable
};
// add the graphics to the map
MyMapView.Map.Layers.Add(lyr);
}
catch (Exception ex)
{
MessageBox.Show("Unable to create offline database: " + ex.Message);
}
return;
}
I also have another method called RemoveLayer(), which simply un-does everything AddLayer() did and then calls GC.Collect().
My question is, why, even after no longer using the resources in the file and calling the garbage collector, can I not delete the file (the geodatabase file) while the program is running?
Is this normal behavior for all programs in Windows? Is it to avoid somehow corrupting the program?
Thank you all for helping me understand this.

This code below ended up working for me:
public void OpenGeodatabase()
{
Geodatabase gdb = null;
// path to .geodatabase
var gdbPath = #"..\..\..\test.geodatabase";
// wrap OpenAsync call in Task
Task.Run(async () =>
{
// open a geodatabase on the local device
gdb = await Geodatabase.OpenAsync(gdbPath);
}).Wait();
// get the first geodatabase feature table
var gdbFeatureTable = gdb.FeatureTables.FirstOrDefault();
// create a layer for the feature table
var lyr = new FeatureLayer
{
ID = gdbFeatureTable.Name,
DisplayName = gdbFeatureTable.Name,
FeatureTable = gdbFeatureTable
};
// add the graphics to the map
MyMapView.Map.Layers.Add(lyr);
// remove the layer - to make it similar to case explanation
MyMapView.Map.Layers.Remove(lyr);
// make gdb reference null
gdb = null;
gdbFeatureTable = null;
lyr = null;
// call garbage collector
GC.Collect();
GC.WaitForPendingFinalizers();
// If the works, the lock has been removed
System.IO.File.Delete(#"..\..\..\test.geodatabase");
}
Basically I did everything inside of a non-async method, wrapped the call to OpenAsync within a Task, then set everything made from the geodatabase to null after use. Finally, I called the garbage collector and deleted the file.

Related

How to await multiple possibly uninitialized Tasks in C#?

I have an API POST endpoint creating a resource, that resource may have multiple relationships. To make sure the resource is created with valid relationships first I need to check if the given IDs exist. There are multiple such relations, and I don't want to await each sequentially. Here's my code:
[HttpPost]
public async Task<ActionResult<Person>> PostPerson(Person person)
{
ValueTask<Person> master, apprentice;
ValueTask<Planet> planet;
ValueTask<Models.LifeFormType> lifeFormType;
if (person.MasterId.HasValue)
{
master = _context.People.FindAsync(person.MasterId);
}
if (person.ApprenticeId.HasValue)
{
apprentice = _context.People.FindAsync(person.ApprenticeId);
}
if (person.FromPlanetId.HasValue)
{
planet = _context.Planets.FindAsync(person.FromPlanetId);
}
if (person.LFTypeId.HasValue)
{
lifeFormType = _context.LifeFormTypes.FindAsync(person.LFTypeId);
}
List<ValueTask> tasks = new List<ValueTask> {master, apprentice, planet, lifeFormType};
// if the above worked I'd process the tasks as they completed and throw errors
// if the given id was not found and such
_context.Attach(person);
// _context.People.Add(person);
await _context.SaveChangesAsync();
return CreatedAtAction("GetPerson", new { id = person.Id }, person);
}
As shown here I want to await the list of [master,apprentice,planet,lifeFormType] as they complete, but I get an error during the creation of the list that Local variable 'master' might not be initialized before accessing. So I tried in each check if the resource has that value to create an else block and somehow add a ValueTask.CompletedTask like so:
if (person.MasterId.HasValue)
{
master = _context.People.FindAsync(person.MasterId);
}
else
{
master = ValueTask.CompletedTask;
}
but then I get an error saying that Cannot convert source type 'System.Threading.Tasks.ValueTask' to target type 'System.Threading.Tasks.ValueTask<Models.Person>'.
How to do this? I guess I'll just await each and every request for now.
You can avoid this by initializing master at the declaration site.
The easiest way is using the default keyword.
ValueTask<Person> master = default;

How to download data from Firebase?

I'm attempting to retrieve some data from a Firebase database. I've been able to do it fine in the past, but there's something wrong with my GetValueAsync() code below. When debugging it gets stuck at the "await reference.Database" line, but I'm not sure what I'm doing wrong. When running without debugging, none of the information is ever retrieved.
I'm uncertain if the problem is with the path, or the await/async function. Debugging shows that loggedUserId is storing the value before referencing it in the next line, but the rest of the function never completes or faults. The application compiles but I'm never able to capture any info from the snapshot.
The format of my database is "users" -> 78cVqzA8qNTNigsao3VvdnM0Qol2 (Which is correct) -> (several data pairs such as level : 1, lives : 3, etc)
public static async void GetUserData()
{
FirebaseApp app = FirebaseApp.DefaultInstance;
app.SetEditorDatabaseUrl("https://narwhaltrivia.firebaseio.com/");
if (app.Options.DatabaseUrl != null) app.SetEditorDatabaseUrl(app.Options.DatabaseUrl);
DatabaseReference reference = Firebase.Database.FirebaseDatabase.DefaultInstance.RootReference;
loggedUserId = FirebaseAuth.DefaultInstance.CurrentUser.UserId;
await reference.Database.GetReference("users").Child(loggedUserId).GetValueAsync().ContinueWith(task =>
{
if (task.IsFaulted)
{
Debug.LogError("Error retrieving user data");
return;
}
if (task.IsCompleted)
{
DataSnapshot userSnapshot = task.Result;
loggedEmail = userSnapshot.Child("email").GetRawJsonValue();
loggedCurrentScore = userSnapshot.Child("currentScore").GetRawJsonValue();
loggedLevel = userSnapshot.Child("level").GetRawJsonValue();
loggedLives = userSnapshot.Child("lives").GetRawJsonValue();
loggedRound = userSnapshot.Child("round").GetRawJsonValue();
loggedTotalScore = userSnapshot.Child("totalScore").GetRawJsonValue();
return;
}
});
}

Cannot load instance of StateMachineStateTracker. Maybe its reach Final State in WF

First I'm totally new to WorkFlow Foundation 4.5. We use the WF engine for managing States in our Case entities. Instead of building our own state machine we decided to use WF. Mostly due to the fact that our customer have large process flows (not that complicated) that we wanted to draw in xaml. Easy for everybody to actually understand the process and talk about it.
The problem is that our transitions to the end state, Final state, results in that StateMachineStateTracker instance is null when we load it. This code below works perfectly for all transitions and we can load up tracker instance after resuming bookmark to see what the new current state is.
private void ConfigureWorkflowApplication(WorkflowApplication wfApp, SqlWorkflowInstanceStore store)
{
wfApp.InstanceStore = store;
var tracker = new StateMachineStateTracker(wfApp.WorkflowDefinition);
wfApp.Extensions.Add(tracker);
wfApp.Extensions.Add(new StateTrackerPersistenceProvider(tracker));
wfApp.Completed = delegate { Debug.WriteLine("Workflow completed."); };
wfApp.Aborted =
delegate(WorkflowApplicationAbortedEventArgs e)
{
Debug.WriteLine("Workflow Aborted. Exception: {0}\r\n{1}", e.Reason.GetType().FullName,
e.Reason.Message);
};
wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e)
{
Debug.WriteLine("Unhandled Exception: {0}\r\n{1}", e.UnhandledException.GetType().FullName,
e.UnhandledException.Message);
return UnhandledExceptionAction.Terminate;
};
wfApp.PersistableIdle = delegate { return PersistableIdleAction.Unload; };
}
Code above instantiate a WorkFlowApplication instance.
protected bool Execute(Activity process, Case #case, string transition)
{
WorkflowApplicationInstance instance = null;
using (var store = new DisposableStore())
{
instance = WorkflowApplication.GetInstance(#case.InstanceId, store.Store);
var wfApp = new WorkflowApplication(process, WorkflowIdentity);
ConfigureWorkflowApplication(wfApp, store.Store);
var trackerInstance = StateMachineStateTracker.LoadInstance(#case.InstanceId, wfApp.WorkflowDefinition,
_connectionString);
if (!trackerInstance.Transitions.Any(x => x.DisplayName.Equals(transition))) return false;
}
using (var store = new DisposableStore())
{
var wfApp = new WorkflowApplication(process, instance.DefinitionIdentity);
ConfigureWorkflowApplication(wfApp, store.Store);
wfApp.Load(#case.InstanceId);
var sync = new AutoResetEvent(false);
wfApp.ResumeBookmark(transition, null);
wfApp.Unloaded = x => sync.Set();
sync.WaitOne();
// Set case to new state
var trackerInstance = StateMachineStateTracker.LoadInstance(#case.InstanceId, wfApp.WorkflowDefinition,
_connectionString);
#case.ChangeToNewState(trackerInstance.CurrentState);
}
return true;
}
The code above have the intention to Make a transition from one State to next (string transition) and we also want to set the new state to our Case class.
This fails when we want to do this from our State before Final state. No exception. No Logging in output window. Nothing. Just that the row
var trackerInstance = StateMachineStateTracker.LoadInstance(#case.InstanceId, wfApp.WorkflowDefinition,
_connectionString);
Returns null. Is this due to the fact that you cannot Load StateMachineStateTracker with an instance that is on final state (not sure if it actually reaches final state).
Do anybody have any clue about the problem? I have a feeling that this is something basic that we've forgot.
Ok. I found the problem. It was as I though. Not a problem. Just me being rookie on WF.
When you do transitions to final state, WF remove all data about case since its finished. This means SurrogateInstance is removed from DB and state machine state tracker are of course not working since there is no case to load into tracker.
BUT however I did a delegate method on Completed event for WorkflowApplication that can handle closure and finalize our case.
wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e)
{
Debug.WriteLine("Workflow completed.");
Debug.WriteLine("State" + e.CompletionState);
if (e.CompletionState == ActivityInstanceState.Closed)
{
_caseIsCompleted = true;
}
};

An elegant / performant way to "Touch" a file in (update ModifiedTime) in WinRT?

An elegant / performant way to "Touch" a file in (update ModifiedTime) WinRT?
I have some code which needs to delete files that are older than 30 days. This works well, but in some cases, I need to update the time on the file to reset the 30 day window, and prevent deletion. On the basicProperties list, the ModifiedTime is read-only, so I need to find another way to update it...
Method 1: Rename twice
// Ugly, and may have side-effects depending on what's using the file
// Sometimes gives access denied...
public static async Task TouchFileAsync(this StorageFile file)
{
var name = file.Name;
await file.RenameAsync("~" + name).AsTask().ContinueWith(
async (task) => { await file.RenameAsync(name); }
);
}
Method 2: Modify a file property
// Sometimes works, but currently throwing an ArgumentException for
// me, and I have no idea why. Also tried many other properties:
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb760658(v=vs.85).aspx
public static async Task TouchFileAsync(this StorageFile file)
{
var prop = new KeyValuePair<string, object>("System.Comment", DateTime.Now.Ticks.ToString());
await file.Properties.SavePropertiesAsync(new[] { prop });
}
Method 3: Use a Win32 API via P/Invoke?
Not sure if this would work on ARM devices?
Pass certification?
Be performant?
Is there a best way to do this? Code sample?
Anyone got any other ideas? I'm a bit stuck :-)
Many thanks,
Jon
I just had a need for this and here is my solution.
usage
await storageFileToTouch.TouchAsync();
code
public static class StorageFileExtensions
{
/// <summary>
/// Touches a file to update the DateModified property.
/// </summary>
public static async Task TouchAsync(this StorageFile file)
{
using (var touch = await file.OpenTransactedWriteAsync())
{
await touch.CommitAsync();
}
}
}
Assuming you're planning on combing a list of files that exist locally on an RT machine, and not somewhere in that cloud (otherwise we woudln't have to worry about the WinRT doc mod process), You could easily use the Application Data Container provided to each app to store very thin data (key value pairs fit very well).
In this way you would store a future delete date for each file that needed to be persisted, so that the next time it was raised for deletion, before the deletion process occurs, the app checks the App Storage Data. Then you wont need to worry about the permissions of the files you're iterating over, when you're only trying to make sure they don't get deleted from your process.
Windows.Storage.ApplicationDataContainer localSettings = Windows.Storage.ApplicationData.Current.LocalSettings;
// Create a setting in a container
Windows.Storage.ApplicationDataContainer container =
localSettings.CreateContainer("FilesToPersist", Windows.Storage.ApplicationDataCreateDisposition.Always);
StorageFile file = fileYouWantToPersist;
if (localSettings.Containers.ContainsKey("FilesToPersist"))
{
localSettings.Containers["FilesToPersist"].Values[file.FolderRelativeId] = DateTime.Now.AddDays(30);
}
// Read data from a setting in a container
bool hasContainer = localSettings.Containers.ContainsKey("FilesToPersist");
bool hasSetting = false;
if (hasContainer)
{
hasSetting = localSettings.Containers["FilesToPersist"].Values.ContainsKey(file.FolderRelativeId);
if(hasSettings)
{
string dt = localSettings.Containers["FilesToPersist"].Values[file.FolderRelativeId];
if(Convert.ToDateTime(dt) < DateTime.Now)
{
//Delete the file
}
}
}
Resources:
http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.applicationdata.aspx
http://lunarfrog.com/blog/2011/10/10/winrt-storage-accesscache/

Multi-threading with Linq to SQL

I am building an application which requires me to make use of DataContext's inside threads. My application keeps throwing InvalidOperationException's similar to:
There is already an open DataReader associated with this Command which must be closed first
ExecuteReader requires an open and available Connection. The connection's current state is connecting
These exceptions are intermittant.
Here is a snippet of my code:
var repo = new Repository();
var entities = repo.GetAllEntities();
foreach (var entity in entities)
{
ThreadPool.QueueUserWorkItem(
delegate
{
try
{
ProcessEntity(entity);
}
catch (Exception)
{
throw;
}
});
}
I think it may have something to with passing an entity to a thread from the main thread as the error seems to throw as soon as I try and access a property of entity.
Anyone have any idea's why this is happening and how I can resolve it?
Update
Here is what I decided to go with:
var events = new Dictionary<int, AutoResetEvent>();
var repo = new Repository();
var entities = repo.GetAllEntities();
foreach (var entity in entities)
{
events.Add(entity.ID, new AutoResetEvent(false));
ThreadPool.QueueUserWorkItem(
delegate
{
var repo = new Repository();
try
{
ProcessHierarchy(repo.GetEntity(entity.ID), ReportRange.Weekly);
}
catch (Exception)
{
throw;
}
finally
{
events[entity.ID].Set();
}
});
}
WaitHandle.WaitAll(events.Values.ToArray());
Improvements/Suggestions welcome, but this seems to have done the trick.
The exception is thrown since some properties of entity executes new query while a previous reader has not been closed yet. You cannot execute more than one query on the data context at the same time.
As a workaround you can "visit" the properties you access in ProcessEntity() and make the SQL run prior to the thread.
For example:
var repo = new Repository();
var entities = repo.GetAllEntities();
foreach (var entity in entities)
{
var localEntity = entity; // Verify the callback uses the correct instance
var entityCustomers = localEntity.Customers;
var entityOrders = localEntity.Orders;
var invoices = entityOrders.Invoices;
ThreadPool.QueueUserWorkItem(
delegate
{
try
{
ProcessEntity(localEntity);
}
catch (Exception)
{
throw;
}
});
}
This workaround will execute the SQL only on the main thread and the processing will be done in other threads. You loose here some of the efficiency since all the queries are done in the single thread. This solution is good if you have a lot of logic in ProcessEntity() and the queries are not very heavy.
Try creating the Repository inside the new thread instead of passing it in.
Be aware that a SqlConnection instance is NOT thread safe. Whether you still have an open reader or not. In general, the access of a SqlConnection instance from multiple threads will cause you unpredictable intermittent problems.
See: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.aspx
The solution for me was LightSpeed Persistence framework, which is free until 8 entities. Per thread create the unitwork.
http://www.mindscapehq.com/products/LightSpeed/default.aspx

Categories