Race condition in Rhino DSL? - race-condition

In my current project I am working with Boo/Rhino DSL (what a great thing(s) by the way).
In digging in the code I came across the following piece of code:
engine.Cache.WriteLock( () =>
{
engine.Storage.NotifyOnChange(urls, delegate(string invalidatedUrl)
{
engine.Cache.Remove(invalidatedUrl);
if (!standAloneCompilation.Contains(invalidatedUrl))
standAloneCompilation.Add(invalidatedUrl);
});
});
the intention here is pretty clear: the engine.Cache has to be protected from race condition when a url is removed from it. The problem I see here is that what is really protected is a call to the Storage.NotifyOnChange - not the Cache.Remove.
And all NotifyOnChange does is taking the supplied delegate and attach it as an event handler to the 'FileWatcher' it creates. So instead of protecting the Cache.Remove the write lock here protects creating the the FileWatcher, and leaves the Cache.Remove unprotected.
I have great respect to both Boo and Rhino, which makes me wonder - am missing something here? or the write lock should be really moved inside the delegate?
Here is the NotifyOnChange code if you are wondering:
public virtual void NotifyOnChange(IEnumerable<string> urls, Action<string> action)
{
lock (pathToFileWatchers)
{
string[] commonPaths = GatherCommonPaths(urls);
foreach (string path in commonPaths)
{
FileSystemWatcher watcher;
if(pathToFileWatchers.TryGetValue(path, out watcher)==false)
{
pathToFileWatchers[path] = watcher = new FileSystemWatcher(path, FileNameFormat);
watcher.EnableRaisingEvents = true;
}
watcher.Changed += delegate(object sender, FileSystemEventArgs e)
{
action(e.FullPath);
};
}
}
}

Related

Outlook Add-In :: COM object that has been separated from its underlying RCW cannot be used

While I have found many instances of this question on SO, none of the solutions I have implemented have solved my problem; hopefully you can help me solve this riddle. Note: This is my first foray into the world of COM objects, so my ignorance is as deep as it is wide.
As a beginning, I am using Adrian Brown's Outlook Add-In code. I won't duplicate his CalendarMonitor class entirely; here are the relevant parts:
public class CalendarMonitor
{
private ItemsEvents_ItemAddEventHandler itemAddEventHandler;
public event EventHandler<EventArgs<AppointmentItem>> AppointmentAdded = delegate { };
public CalendarMonitor(Explorer explorer)
{
_calendarItems = new List<Items>();
HookupDefaultCalendarEvents(session);
}
private void HookupDefaultCalendarEvents(_NameSpace session)
{
var folder = session.GetDefaultFolder(OlDefaultFolders.olFolderCalendar);
if (folder == null) return;
try
{
HookupCalendarEvents(folder);
}
finally
{
Marshal.ReleaseComObject(folder);
folder = null;
}
}
private void HookupCalendarEvents(MAPIFolder calendarFolder)
{
var items = calendarFolder.Items;
_calendarItems.Add(items);
// Add listeners
itemAddEventHandler = new ItemsEvents_ItemAddEventHandler(CalendarItems_ItemAdd);
items.ItemAdd += itemAddEventHandler;
}
private void CalendarItems_ItemAdd(object obj)
{
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
AppointmentAdded(this, new EventArgs<AppointmentItem>(appointment));
}
finally
{
Marshal.ReleaseComObject(appointment);
appointment = null;
}
}
Bits not relevant to adding appointments have been redacted.
I instantiate the CalendarMonitor class when I spool up the Add-in, and do the work in the AppointmentAdded event, including adding a UserProperty to the AppointmentItem:
private void ThisAddIn_Startup(object sender, EventArgs e)
{
_calendarMonitor = new CalendarMonitor(Application.ActiveExplorer());
_calendarMonitor.AppointmentAdded += monitor_AppointmentAdded;
}
private async void monitor_AppointmentAdded(object sender, EventArgs<AppointmentItem> e)
{
var item = e.Value;
Debug.Print("Outlook Appointment Added: {0}", item.GlobalAppointmentID);
try
{
var result = await GCalUtils.AddEventAsync(item);
//store a reference to the GCal Event for later.
AddUserProperty(item, Resources.GCalId, result.Id);
Debug.Print("GCal Appointment Added: {0}", result.Id);
}
catch (GoogleApiException ex)
{
PrintToDebug(ex);
}
finally
{
Marshal.ReleaseComObject(item);
item = null;
}
}
The error is thrown here, where I try to add a UserProperty to the AppointmentItem. I have followed the best example I could find:
private void AddUserProperty(AppointmentItem item, string propertyName, object value)
{
UserProperties userProperties = null;
UserProperty userProperty = null;
try
{
userProperties = item.UserProperties;
userProperty = userProperties.Add(propertyName, OlUserPropertyType.olText);
userProperty.Value = value;
item.Save();
}
catch (Exception ex)
{
Debug.Print("Error setting User Properties:");
PrintToDebug(ex);
}
finally
{
if (userProperty != null) Marshal.ReleaseComObject(userProperty);
if (userProperties != null) Marshal.ReleaseComObject(userProperties);
userProperty = null;
userProperties = null;
}
}
... but it chokes on when I try to add the UserProperty to the AppointmentItem. I get the ever-popular error: COM object that has been separated from its underlying RCW cannot be used. In all honesty, I have no idea what I'm doing; so I'm desperately seeking a Jedi Master to my Padawan.
The main problem here is using Marshal.ReleaseComObject for RCW's that are used in more than one place by the managed runtime.
In fact, this code provoked the problem. Let's see class CalendarMonitor:
private void CalendarItems_ItemAdd(object obj)
{
var appointment = (obj as AppointmentItem);
if (appointment == null) return;
try
{
AppointmentAdded(this, new EventArgs<AppointmentItem>(appointment));
}
finally
{
Marshal.ReleaseComObject(appointment);
After the event returns, it tells the managed runtime to release the COM object (from the point of view of the whole managed runtime, but no further).
appointment = null;
}
}
Then, an async event is attached, which will actually return before using the appointment, right at the await line:
private async void monitor_AppointmentAdded(object sender, EventArgs<AppointmentItem> e)
{
var item = e.Value;
Debug.Print("Outlook Appointment Added: {0}", item.GlobalAppointmentID);
try
{
var result = await GCalUtils.AddEventAsync(item);
This method actually returns here. C#'s async code generation breaks async methods at await points, generating continuation passing style (CPS) anonymous methods for each block of code that handles an awaited result.
//store a reference to the GCal Event for later.
AddUserProperty(item, Resources.GCalId, result.Id);
Debug.Print("GCal Appointment Added: {0}", result.Id);
}
catch (GoogleApiException ex)
{
PrintToDebug(ex);
}
finally
{
Marshal.ReleaseComObject(item);
Look, it's releasing the COM object again. No problem, but not optimal at all. This is an indicator of not knowing what is going on by using ReleaseComObject, it's better to avoid it unless proven necessary.
item = null;
}
}
In essence the use of ReleaseComObject should be subject to a thorough review of the following points:
Do I need to actually make sure the managed environment releases the object right now instead of at an indeterminate time?
Occasionally, some native objects need to be released to cause relevant side effects.
For instance, under a distributed transaction to make sure the object commits, but if you find the need to do that, then perhaps you're developing a serviced component and you're not enlisting objects in manual transactions properly.
Other times, you're iterating a huge set of objects, no matter how small each object is, and you may need to free them in order to not bring either your application or the remote application down. Sometimes, GC'ing more often, switching to 64-bit and/or adding RAM solves the problem in one way or the other.
Am I the sole owner of/pointer to the object from the managed environment's point of view?
For instance, did I create it, or was the object provided indirectly by another object I created?
Are there no further references to this object or its container in the managed environment?
Am I definitely not using the object after ReleaseComObject, in the code that follows it, or at any other time (e.g. by making sure not to store it in a field, or closure, even in the form of an iterator method or async method)?
This is to avoid the dreaded disconnected RCW exception.

When calling a WCF RIA Service method using Invoke, does the return type affect when the Completed callback is executed?

I inherited a Silverlight 5 application. On the server side, it has a DomainContext (service) with a method marked as
[Invoke]
public void DoIt
{
do stuff for 10 seconds here
}
On the client side, it has a ViewModel method containing this:
var q = Context.DoIt(0);
var x=1; var y=2;
q.Completed += (a,b) => DoMore(x,y);
My 2 questions are
1) has DoIt already been activated by the time I attach q.Completed, and
2) does the return type (void) enter into the timing at all?
Now, I know there's another way to call DoIt, namely:
var q = Context.DoIt(0,myCallback);
This leads me to think the two ways of making the call are mutually exclusive.
Although DoIt() is executed on a remote computer, it is best to attach Completed event handler immediately. Otherwise, when the process completes, you might miss out on the callback.
You are correct. The two ways of calling DoIt are mutually exclusive.
If you have complicated logic, you may want to consider using the Bcl Async library. See this blog post.
Using async, your code will look like this:
// Note: you will need the OperationExtensions helper
public async void CallDoItAndDosomething()
{
this.BusyIndicator.IsBusy = true;
await context.DoIt(0).AsTask();
this.BusyIndicator.IsBusy = false;
}
public static class OperationExtensions
{
public static Task<T> AsTask<T>(this T operation)
where T : OperationBase
{
TaskCompletionSource<T> tcs =
new TaskCompletionSource<T>(operation.UserState);
operation.Completed += (sender, e) =>
{
if (operation.HasError && !operation.IsErrorHandled)
{
tcs.TrySetException(operation.Error);
operation.MarkErrorAsHandled();
}
else if (operation.IsCanceled)
{
tcs.TrySetCanceled();
}
else
{
tcs.TrySetResult(operation);
}
};
return tcs.Task;
}
}

What the right time for registering listener for Share/Search charms

I need to register different share charm listener for every page. I have 2 pages. I added following code in every one:
DataTransferManager.GetForCurrentView().DataRequested += App_DataRequested;
I added it in constructor of one page and in UserControl_Loaded event of another (first page just doesn't have UserControl_Loaded so why I added it directly to constructor). At the moment when second page tryting to load, I got exception:
WinRT information: An event handler has already been registered
Additional information: A method was called at an unexpected time.
Where should I place it and what is "right" time to do this??
Also it looks confusing that we have different DataTransferManager for every view, but only one is active at current time. Ever more, I noticed, if you add only one listener for first page, other pages will share this listener anyway. If I have only one shared listener for all pages, is it correct register it in app.xaml.cs?
The way I resolved this issue was to deregister the event in the onNavigatedfrom event as below:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
DataTransferManager.GetForCurrentView().DataRequested -= App_DataRequested;
base.OnNavigatedFrom(e);
}
In BasePage.cs in constructor I added
public BasePage()
{
if (!_isListenToDataRequested)
{
_isListenToDataRequested = true;
DataTransferManager manager = DataTransferManager.GetForCurrentView();
manager.DataRequested += AppDataRequested;
}
}
private async void AppDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
IShareable shareable = Frame.Content as IShareable;
if (shareable != null)
{
DataRequestDeferral deferral = args.Request.GetDeferral();
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => shareable.AppDataRequested(sender, args));
deferral.Complete();
}
}
And all my pages look like
public sealed partial class ContentPage : IShareable
{
public void AppDataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{...}
}
Another solution was run this as below
private DataTransferManager dataTransferManager;
Put this in page loaded event
this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
{
this.dataTransferManager = DataTransferManager.GetForCurrentView();
this.dataTransferManager.DataRequested += new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>(this.OnDataRequested);
}));
And
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
// Unregister the current page as a share source.
this.dataTransferManager.DataRequested -=
new TypedEventHandler<DataTransferManager, DataRequestedEventArgs>
(this.OnDataRequested);
}
I'd suggest doing it in the navigating events, the OnNavigatingFrom event will be triggered before the OnNavigatingTo of the page you're going to so you won't have this problem.
protected override Task OnNavigatingTo(WinRTXamlToolkit.Controls.AlternativeNavigationEventArgs e)
{
DataTransferManager.GetForCurrentView().DataRequested += dataTransfer_DataRequested;
return base.OnNavigatingTo(e);
}
protected override Task OnNavigatingFrom(WinRTXamlToolkit.Controls.AlternativeNavigatingCancelEventArgs e)
{
DataTransferManager.GetForCurrentView().DataRequested -= dataTransfer_DataRequested;
return base.OnNavigatingFrom(e);
}
//Note: This is the WinRT Xaml Toolkit version of the events, but the standard events will work the same way.

MVVM-Light and WP7 ViewModel tombstoning isn't working

I've tried following the steps in Joost Van Schaik's article on tombstoning but was unable to get it to work for me. I'm no doubt doing something wrong. In my ViewModel:
private string _foobar ="init";
public string testStr
{
get
{
return _foobar;
}
set
{
_foobar = value;
}
}
And in my page:
<TextBox x:Name="tBoxTest" Text="{Binding testStr, Mode=TwoWay}" />
While the application is running, changing the value in tBoxTest sets _foobar just fine, but try to serialize it and it’s as if it has forgotten the instance??? Any help would be greatly appreciated.
I was able to get tombstoning to work, along with having an object be visible to all my ViewModels, by doing the following:
In a Model class, I added:
private static Model1 _instance;
public static Model1 Instance
{
get { return _instance; }
set { _instance = value; }
}
public static void CreateNew()
{
if (_instance == null)
{
_instance = new Model1();
_instance.FirstString = "init";
}
}
Then in ApplicationExtensions.cs I added:
public static void SaveToIsolatedStorage(this Application app, Model1 model)
{
var dataFileName = GetIsFile((model.GetType()));
using (var userAppStore =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (userAppStore.FileExists(dataFileName))
{
userAppStore.DeleteFile(dataFileName);
}
using (var iss = userAppStore.CreateFile(dataFileName))
{
SilverlightSerializer.Serialize(model, iss);
}
}
}
And in App.xaml.cs I changed LoadModel() to:
private void LoadModel()
{
try
{
Model1.Instance = this.RetrieveFromIsolatedStorage<Model1>();
}
catch (Exception) { }
if (Model1.Instance == null) Model1.CreateNew();
}
That all made things like this work in my ViewModel files:
public string TestStr
{
get
{
return Model1.Instance.FirstString;
}
set
{
Model1.Instance.FirstString = value;
}
}
And by that, I mean that the Model1 object is getting serialized and tombstoning is working - at least I’m getting what I think I want. I’ve tested it a lot by navigating between apps, phone settings, turning the phone off and on, locking it and calling it while in the app from another phone. Performance when deserializing is great. And I can work with the vars.
That said, Mr. Van Schaik replied to a request for assistance with: "If you are subclassing from an MVVMLight ViewModelBase it does, and then you should call RaisePropertyChanged from your setter like this:
private string _foobar ="init";
public string TestStr
{
get
{
return _foobar;
}
set
{
RaisePropertyChanged("TestStr");
_foobar = value;
}
}
RaisePropertyChanged notifies any listenings views (i.e. the TextBox you bound to it) that a property is changed and that the should update their contents. This is a crucial mechanism."
So I will work with what I was originally trying but with the addition of RaisePropertyChanged to see what that does.
UPDATE
Although I implemented RaisedPropertyChanged (using the code snippet mvvminpc) in my MainViewModel.cs file, that still had no effect (as good as it may be for other things) on serializing anything created within the ViewModel. I'm probably still doing something wrong, but it may also be because view models inherit from a protected class (answer from Laurent Bugnion). I (very reluctantly) tried changing that class from protected to public and recompiling, but it didn't help in my case and I hate to fork a referenced library like that. Anyway, I'm just forging ahead for now with creating the Model1 instance in App.xaml.cs. Seems to work. While I was at it, I modified one of Van Schaik's methods to accept any type of object:
public static void SaveToIsolatedStorage<T>(this Application app, T obj)
where T : class
{
var dataFileName = GetIsFile(typeof(T));
using (var userAppStore =
IsolatedStorageFile.GetUserStoreForApplication())
{
if (userAppStore.FileExists(dataFileName))
{
userAppStore.DeleteFile(dataFileName);
}
using (var iss = userAppStore.CreateFile(dataFileName))
{
SilverlightSerializer.Serialize(obj, iss);
}
}
}
From the code you've posted there isn't an instant answer.
My advice to debug this is:
if you've copied the code exactly from that article then add something (a messagebox?) to the empty catch handler - `catch (Exception){ }
use the debugger to put breakpoints in the LoadModel and SaveToIsolatedStorage methods
use these breakpoints to step through the Load and Save code - is the code correctly loading and saving?
To be honest, with problems like this, doing a little investigation yourself is much better than asking questions on here (IMO!)

Best practices for converting WCF calls to async WCF calls

I am running into issues when trying to convert all my normal WCF calls to async WCF calls. I'm finding I have a refactor a lot of code and not sure exactly how to do it. I have used the method that I found here but running into issues where I need things to happen in order.
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach(Item i in itemList)
{
DoSomeWork(i);
if(i.SomeID == 0)
{
DoSomeMoreWork(i);
}
UpdateRecord(i) // this can't execute until the above code is complete
}
}
private void DoSomeWork(Item i)
{
// call async method
}
private void DoSomeMoreWork(i)
{
// call async method
}
private void UpdateRecord(item i)
{
// call async method
}
What is the best way to refactor code to work in an asyncronous way, or do I need to completely rethink my logic? Do I really have to insert counters and switches everywhere to make sure certain things are done before other things execute?
EDIT: The reason I'm doing this is in the next couple months, we are converting this WPF application to Silverlight, which requires async calls. So I'm trying to convert our regular WCF calls to async in preparation. I'm finding it requires a different way of thinking.
For what you're doing, I'd say the real place to handle things is to make a single call to the service per item, not 3.
Preferably, if the list of items is not huge, make a single call to the service with the whole list...
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach(Item i in itemList)
{
DoAllTheWorkAndUpdate(i);
}
}
or...
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach(Item i in itemList)
{
if(i.Id == 0)
{
DoLotsOfWorkAndUpdate(i);
}
else
{
DoSomeWorkAndUpdate(i);
}
}
}
or...
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
DoTheWorkOnTheWholeList(itemList);
}
In other words, it feels like some of your responsibilities may be misplaced - I generally prefer to make services where I can make a single call to them. Then, the asynchronous nature is irrelevant, because you're not performing a sequence of events.
Take a look at Juval Lowy's (author of Programming WCF Services) website for examples of how to achieve asynchronous programming in WCF. The downloads are free; you just have to provide your email address.
I am perhaps a bit puzzled as to why you need to use asynchronous WCF operations when you need things to be synchronous inside the loop.
If you are just using the async methods to help keep the UI from hanging, then you could just use a BackgroundWorker that supports progress updates to keep the UI up to date, and not use Async WCF calls.
You should also be able to call your various functions from the Completed events for the Async methods.
Just hook up event handlers to the completed events and then pass your Item object as the userState parameter when you start the async WCF call. This way you will have it as a parameter when each of the Completed events fires. That way you will only be doing the next step in your processing as the previous async call completes.
I don't know if this really is answering your question though.
Try using this
http://ayende.com/Blog/archive/2008/03/29/WCF-Async-without-proxies.aspx
the approach that definitely works.
If you're not using Silverlight, you can block your thread in one method until the other methods complete, using, say, a ManualResetEvent. But that won't work in Silverlight, since all WCF calls happen on the main UI thread, so if you block that thread, everything blocks. A better approach is to do something like this, using callbacks:
public delegate void OperationCallback();
private void btnSave_Click(object sender, RoutedEventArgs e)
{
List<Item> itemList = GetList();
foreach (Item i in itemList)
{
DoSomeWork(i, () =>
{
if (i.SomeID == 0)
{
DoSomeMoreWork(i, () =>
{
UpdateRecord(i);
});
}
else
{
UpdateRecord(i);
}
});
}
}
private void DoSomeWork(Item i, OperationCallback callback)
{
// call async method then callback when it completes.
callback();
}
private void DoSomeMoreWork(Item i, OperationCallback callback)
{
// call async method, then callback when it completes.
callback();
}
private void UpdateRecord(Item i)
{
// call async method
}
It's certainly not as clear as the synchronous version, but if you use lambda expressions as much as possible, it's still possible to keep the control flow fairly readable.
Add 2 properties to Item called SomeWorkDone and SomeMoreWorkDone both as booleans. Create methods to handle both DoSomeWorkCompleted and DoSomeMoreWorkCompleted. In those methods, set the respective boolean properties to true and call UpdateRecord. Within UpdateRecord, ensure that both Done properties are true and then complete the calls.
You'll have some possible contention issues but this should get you going.