private static async Task ApplyV3SessionProperties(
            IUpstreamEdFiApiInvoker invoker,
            HttpRequestHeaders headers,
            V3SectionReference source,
            V2SectionReference destination,
            short schoolYearFromRoute)
        {
            var termDescriptorLookupKey = new TermDescriptorKey(source.SchoolId, source.SchoolYear, source.SessionName);

            await Task.Run(() =>
            {
                var value = _termDescriptorByNaturalKey.GetOrAdd(termDescriptorLookupKey, k =>
                                                                 GetTermDescriptorValueFromV3Session(invoker, headers, k, schoolYearFromRoute)
                                                                 .ConfigureAwait(false)
                                                                 .GetAwaiter()
                                                                 .GetResult());

                // Is the retrieved value stale?
                if ((DateTime.Now - value.RetrievedDateTime).TotalSeconds > _cacheDurationSeconds.Value)
                {
                    // Refresh the values
                    TermDescriptorValue ignored;
                    _termDescriptorByNaturalKey.TryRemove(termDescriptorLookupKey, out ignored);

                    value = _termDescriptorByNaturalKey.GetOrAdd(termDescriptorLookupKey, k =>
                                                                 GetTermDescriptorValueFromV3Session(invoker, headers, k, schoolYearFromRoute)
                                                                 .ConfigureAwait(false)
                                                                 .GetAwaiter()
                                                                 .GetResult());
                }

                destination.TermDescriptor = value.TermDescriptor;
            })
            .ConfigureAwait(false);
        }
        private static async Task <SectionValues> GetV3SectionValuesAsync(
            IUpstreamEdFiApiInvoker invoker,
            HttpRequestHeaders headers,
            SectionLookupKey lookupKey,
            short schoolYearFromRoute)
        {
            // Get the referenced section by natural key
            var response = await invoker.Get(
                typeof(V3Section),
                headers,
                new[]
            {
                new KeyValuePair <string, string>("localCourseCode", lookupKey.LocalCourseCode),
                new KeyValuePair <string, string>("schoolId", lookupKey.SchoolId.ToString()),
                new KeyValuePair <string, string>("schoolYear", lookupKey.SchoolYear.ToString()),
                new KeyValuePair <string, string>("sectionIdentifier", lookupKey.SectionIdentifier),
                new KeyValuePair <string, string>("sessionName", lookupKey.SessionName),
            },
                schoolYearFromRoute)
                           .ConfigureAwait(false);

            StreamReader sr = new StreamReader(response.ResponseStream);
            string       responseContent = await sr.ReadToEndAsync().ConfigureAwait(false);

            if (response.Status == HttpStatusCode.OK)
            {
                // Get the Section-derived members
                var v3Section = JsonConvert.DeserializeObject <V3Section[]>(responseContent, _serializerSettings).SingleOrDefault();

                if (v3Section == null)
                {
                    throw new Exception($"Unable to find referenced Section using the following values: {JsonConvert.SerializeObject(lookupKey, Formatting.Indented)}");
                }

                // Invasive defensive validation against "invalid" data for V2
                if (lookupKey.SchoolId != v3Section.LocationReference.SchoolId)
                {
                    throw new Exception($"Unable to convert the SectionReference from host (v3.1) to client (v2.5) because the LocationReference contains a School that differs from the containing Section, which is not supported under v2.5.");
                }

                // TODO: Validate presence of V2 required values, or ensure that V3 requires them (i.e. via required collections)

                var sectionValues = new SectionValues(
                    classPeriodName: v3Section.SectionClassPeriods.FirstOrDefault()?.ClassPeriodReference.ClassPeriodName ?? "Undefined",
                    classroomIdentificationCode: v3Section.LocationReference.ClassroomIdentificationCode ?? "Undefined",
                    sectionIdentifier: v3Section.SectionIdentifier,
                    sequenceOfCourse: v3Section.SequenceOfCourse ?? -1,
                    retrievedDateTime: DateTime.Now);

                return(sectionValues);
            }

            throw new Exception($"Error obtaining V3 Section resource during mapping of V2 SectionReference: {response.Status} - {responseContent}");
        }
        private static async Task ApplyPropertiesFromV3SectionAsync(
            IUpstreamEdFiApiInvoker invoker,
            HttpRequestHeaders headers,
            V3SectionReference source,
            V2SectionReference destination,
            short schoolYearFromRoute)
        {
            var sectionLookupKey = new SectionLookupKey(source.LocalCourseCode, source.SchoolId, source.SchoolYear, source.SectionIdentifier, source.SessionName);

            await Task.Run(() =>
            {
                var values = _sectionValuesByNaturalKey.GetOrAdd(sectionLookupKey, k =>
                                                                 GetV3SectionValuesAsync(invoker, headers, k, schoolYearFromRoute)
                                                                 .ConfigureAwait(false)
                                                                 .GetAwaiter()
                                                                 .GetResult());

                // Are the retrieved values stale?
                if ((DateTime.Now - values.RetrievedDateTime).TotalSeconds > _cacheDurationSeconds.Value)
                {
                    // Refresh the values
                    SectionValues ignored;
                    _sectionValuesByNaturalKey.TryRemove(sectionLookupKey, out ignored);

                    values = _sectionValuesByNaturalKey.GetOrAdd(sectionLookupKey, k =>
                                                                 GetV3SectionValuesAsync(invoker, headers, k, schoolYearFromRoute)
                                                                 .ConfigureAwait(false)
                                                                 .GetAwaiter()
                                                                 .GetResult());
                }

                // Straight mappings from source
                destination.LocalCourseCode = source.LocalCourseCode;
                destination.SchoolId        = source.SchoolId;
                destination.SchoolYear      = source.SchoolYear;

                // Mappings from upstream host's Section
                destination.ClassPeriodName             = values.ClassPeriodName;
                destination.ClassroomIdentificationCode = values.ClassroomIdentificationCode;
                destination.SequenceOfCourse            = values.SequenceOfCourse;

                // NOTE: Assumes UniqueSectionCode is unique enough to use as the SectionIdentifier.
                destination.UniqueSectionCode = values.SectionIdentifier;
            })
            .ConfigureAwait(false);
        }
        private static async Task <TermDescriptorValue> GetTermDescriptorValueFromV3Session(
            IUpstreamEdFiApiInvoker invoker,
            HttpRequestHeaders headers,
            TermDescriptorKey key,
            short schoolYearFromRoute)
        {
            // Get the referenced section by natural key
            var response = await invoker.Get(
                typeof(V3Session),
                headers,
                new[]
            {
                new KeyValuePair <string, string>("schoolId", key.SchoolId.ToString()),
                new KeyValuePair <string, string>("schoolYear", key.SchoolYear.ToString()),
                new KeyValuePair <string, string>("sessionName", key.SessionName),
            },
                schoolYearFromRoute)
                           .ConfigureAwait(false);

            StreamReader sr = new StreamReader(response.ResponseStream);
            string       responseContent = await sr.ReadToEndAsync().ConfigureAwait(false);

            if (response.Status == HttpStatusCode.OK)
            {
                // Get the Session-derived members
                var v3Session = JsonConvert.DeserializeObject <V3Session[]>(responseContent, _serializerSettings)
                                .SingleOrDefault();

                if (v3Session == null)
                {
                    throw new Exception(
                              $"Session with schoolId '{key.SchoolId}', schoolYear '{key.SchoolYear}' and sessionName '{key.SessionName}' was not found in host. Unable to support termDescriptor conversion for v2.5 API client.");
                }

                return(new TermDescriptorValue(
                           VersionConverter.DescriptorV3ToV2("TermDescriptor", v3Session.TermDescriptor),
                           DateTime.Now));
            }

            throw new Exception(
                      $"Error obtaining V3 Session resource during mapping of TermDescriptor: {response.Status} - {responseContent}");
        }
Exemple #5
0
        private static async Task <string> GetSessionName(
            IUpstreamEdFiApiInvoker invoker,
            HttpRequestHeaders headers,
            V2SectionReference source,
            short schoolYear)
        {
            // Get the referenced session by example
            var response = await invoker.Get(
                typeof(V3Session),
                headers, new[]
            {
                new KeyValuePair <string, string>("schoolId", source.SchoolId.ToString()),
                new KeyValuePair <string, string>("schoolYear", source.SchoolYear.ToString()),
                new KeyValuePair <string, string>("termDescriptor",
                                                  VersionConverter.DescriptorV2ToV3("TermDescriptor", source.TermDescriptor))
            },
                schoolYear)
                           .ConfigureAwait(false);

            StreamReader sr = new StreamReader(response.ResponseStream);
            string       responseContent = sr.ReadToEnd();

            if (response.Status == HttpStatusCode.OK)
            {
                var v3Sessions = JsonConvert.DeserializeObject <V3Session[]>(responseContent, _serializerSettings);

                var distinctSessionNames = v3Sessions.Select(x => x.SessionName).Distinct().ToList();

                if (distinctSessionNames.Count() > 1)
                {
                    throw new Exception($"Error obtaining SessionName from remote API due to multiple values matching in the Sessions for the supplied TermDescriptor.");
                }

                return(distinctSessionNames.FirstOrDefault());
            }

            throw new Exception(
                      $"Error obtaining V3 Session resource during mapping of SessionName: {response.Status} - {responseContent}");
        }