Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CalendarCollection.GetOccurrences throws "Collection was modified; enumeration operation may not execute." #148

Closed
ostruk opened this issue Sep 30, 2016 · 6 comments

Comments

@ostruk
Copy link

ostruk commented Sep 30, 2016

at System.Collections.Generic.HashSet1.Enumerator.MoveNext() at System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext()
at System.Collections.Generic.HashSet1.ExceptWith(IEnumerable1 other)
at Ical.Net.Calendar.GetOccurrences[T](IDateTime startTime, IDateTime endTime) in C:\dev\ical.net\ical.NET\Calendar.cs:line 406
at Ical.Net.Calendar.GetOccurrences(DateTime startTime, DateTime endTime) in C:\dev\ical.net\ical.NET\Calendar.cs:line 370
at Ical.Net.CalendarCollection.GetOccurrences(DateTime startTime, DateTime endTime) in C:\dev\ical.net\ical.NET\CalendarCollection.cs:line 60

for ical of this form:

BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:name
X-WR-TIMEZONE:America/New_York
BEGIN:VTIMEZONE
TZID:America/New_York
X-LIC-LOCATION:America/New_York
BEGIN:DAYLIGHT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
TZNAME:EDT
DTSTART:19700308T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
TZNAME:EST
DTSTART:19701101T020000
RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU
END:STANDARD
END:VTIMEZONE

BEGIN:VEVENT
DTSTART;TZID=America/New_York:20161011T170000
DTEND;TZID=America/New_York:20161011T180000
DTSTAMP:20160930T115710Z
UID:blablabla
RECURRENCE-ID;TZID=America/New_York:20161011T170000
CREATED:20160830T144559Z
DESCRIPTION:
LAST-MODIFIED:20160928T142659Z
LOCATION:Location1
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Summary1
TRANSP:OPAQUE
END:VEVENT

END:VCALENDAR

Using 2.2.14

@ostruk ostruk changed the title CalendarCollection.GetOccurrences throws Collection was modified; enumeration operation may not execute. CalendarCollection.GetOccurrences throws "Collection was modified; enumeration operation may not execute." Sep 30, 2016
@rianjs
Copy link
Collaborator

rianjs commented Sep 30, 2016

Do you have an example of the code that caused the exception to be thrown?

Commentary for my future self: I find it weird that asking questions about occurrences is allowed at the CalendarCollection level. This "capability" may be something to look at for v3. Questions about occurrences should be VEVENT, VALARM, VTODO, etc based. (I.e. anything that supports RRULEs. That said, the collection mutation during occurrence evaluation is concerning.

@ostruk
Copy link
Author

ostruk commented Sep 30, 2016

var client = new HttpClient();
var responseStream = await client.GetStreamAsync(url);
calendar = Calendar.LoadFromStream(responseStream) as CalendarCollection;
var date = new DateTime(2016, 10, 11);
var occurrences = calendar.GetOccurrences(date);

doing

var occurrences = calendar[0].GetOccurrences(date);

throws same.

It also happens if using GetOccurances(startDate,endDate) and range includes offending date.
Thanks!

@ghentsch
Copy link

Was there a resolution or a workaround for this problem?

@ostruk
Copy link
Author

ostruk commented Nov 2, 2016

If you do a .toList() on the internal selector, it doesn't crash anymore:

occurrences.ExceptWith( occurrences.Where(o => o.Source is IUniqueComponent) .Where(o => o.Source.RecurrenceId != null) .Where(o => o.Source.RecurrenceId.Equals(o.Period.StartTime)).ToList());

But I don't think code itself makes sense.. it removes overridden recurrences if their time didn't change. But what if the description/title etc. changed? I'll create a separate issue for this.

@MartinRothschink
Copy link

MartinRothschink commented Nov 22, 2016

I have a similar issue in 2.2.18 where it throws the same exception.

[Test]
      public void GetOccurrencesShouldEnumerate()
      {
         const string ical =
@"BEGIN:VCALENDAR
PRODID:-/rianjs/ical.net//NONSGML ical.net 2.2//EN
VERSION:2.0
BEGIN:VTIMEZONE
TZID:W. Europe Standard Time
BEGIN:STANDARD
DTSTART:16010101T030000
RRULE:FREQ=YEARLY;BYDAY=SU;BYMONTH=10;BYSETPOS=-1
TZNAME:Mitteleuropäische Zeit
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
END:STANDARD
BEGIN:DAYLIGHT
DTSTART:00010101T020000
RRULE:FREQ=YEARLY;BYDAY=SU;BYMONTH=3;BYSETPOS=-1
TZNAME:Mitteleuropäische Sommerzeit
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
END:DAYLIGHT
END:VTIMEZONE
BEGIN:VEVENT
BACKGROUND:BUSY
DESCRIPTION:Backup Daten
DTEND;TZID=W. Europe Standard Time:20150305T043000
DTSTAMP:20161122T120652Z
DTSTART;TZID=W. Europe Standard Time:20150305T000100
RESOURCES:server
RRULE:FREQ=WEEKLY;BYDAY=MO
SUMMARY:Server
UID:a30ed847-8000-4c53-9e58-99c8f9cf7c4b
X-LIGHTSOUT-ACTION:START=WakeUp\;END=Reboot\,Force
X-LIGHTSOUT-MODE:TimeSpan
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
END:VEVENT
BEGIN:VEVENT
BACKGROUND:BUSY
DESCRIPTION:Backup Daten
DTEND;TZID=W. Europe Standard Time:20161128T043000
DTSTAMP:20161122T120652Z
DTSTART;TZID=W. Europe Standard Time:20161128T000100
RECURRENCE-ID:20161128T000100
RESOURCES:server
SEQUENCE:0
SUMMARY:Server
UID:a30ed847-8000-4c53-9e58-99c8f9cf7c4b
X-LIGHTSOUT-ACTION:START=WakeUp\;END=Reboot\,Force
X-LIGHTSOUT-MODE:TimeSpan
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
END:VEVENT
END:VCALENDAR
";

         var collection = Calendar.LoadFromStream(new StringReader(ical));
         var startCheck = new DateTime(2016, 11, 11);
         var occurrences = collection.GetOccurrences<Event>(startCheck, startCheck.AddMonths(1));

         Assert.IsTrue(occurrences.Count == 4);
      }

@rianjs
Copy link
Collaborator

rianjs commented Dec 15, 2016

@ghentsch and @ostruk - I just committed the workaround and published 2.2.25 which incorporates it. I added unit tests, too.

5c766b5

@rianjs rianjs closed this as completed Dec 15, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants