/// <summary> /// Initialize information for the hidden controls and script. This sets up the information to create hidden fields in the form /// and to update the framesetMgr on page load. /// </summary> private void InitHiddenControlInfo(RenderContext context, StringBuilder onLoadScript) { // Should only do this if this is LRM content. Other content does not allow writing to the page. if (this.Session.CurrentActivityResourceType != ResourceType.Lrm) { return; } IDictionary<string, string> controls = context.FormHiddenControls; // Write the script to define frameMgr in script. WriteFindFrameMgr(onLoadScript); // If the session is attempt-based, then write attempt information if (this.Session != null) { controls.Add( HiddenFieldNames.AttemptId, FramesetUtil.GetStringInvariant(this.Session.AttemptId.GetKey())); onLoadScript.AppendFormat( "frameMgr.SetAttemptId(document.getElementById({0}).value);\r\n", JScriptString.QuoteString(HiddenFieldNames.AttemptId, false)); } // If the session has ended (that is, is suspended, completed or abandoned), then we're // done. Just return. if (this.SessionIsEnded) { return; } // Write view to display. controls.Add(HiddenFieldNames.View, FramesetUtil.GetString(this.Session.View)); onLoadScript.AppendFormat( "frameMgr.SetView(document.getElementById({0}).value);\r\n", JScriptString.QuoteString(HiddenFieldNames.View, false)); // Write frame to post. controls.Add(HiddenFieldNames.PostFrame, "frameContent"); onLoadScript.AppendFormat( "frameMgr.SetPostFrame(document.getElementById({0}).value);\r\n", JScriptString.QuoteString(HiddenFieldNames.PostFrame, false)); // Set contentFrameUrl to be null. This prevents the content frame from being re-loaded. onLoadScript.Append("frameMgr.SetContentFrameUrl(null);\r\n"); // If a new activity has been identified, then instruct frameMgr to reinitialize the RTE. // BE CAREFUL to do this before setting any other data related to the rte! if (this.ActivityHasChanged) { string initNewActivity = "false"; if (this.Session.HasCurrentActivity) { initNewActivity = (this.CurrentActivityRequiresRte ? "true" : "false"); } onLoadScript.AppendFormat("frameMgr.InitNewActivity( {0} );\r\n", initNewActivity); } // Write the current activity Id. Write -1 if there isn't one. var currentActivityId = this.Session.HasCurrentActivity ? FramesetUtil.GetStringInvariant(this.Session.CurrentActivityId) : "-1"; controls.Add( HiddenFieldNames.ActivityId, currentActivityId); onLoadScript.AppendFormat( "frameMgr.SetActivityId(document.getElementById({0}).value);\r\n", JScriptString.QuoteString(HiddenFieldNames.ActivityId, false)); // Write the navigation control state. Format of the control state is a series of T (to show) or F (to hide) // values, separated by semi-colons. The order of controls is: // showNext, showPrevious, showAbandon, showExit, showSave StringBuilder sb = new StringBuilder(10); sb.Append((this.Session.ShowNext) ? "T" : "F"); sb.Append(";"); sb.Append((this.Session.ShowPrevious) ? "T" : "F"); sb.Append(";"); sb.Append((this.Session.ShowAbandon) ? "T" : "F"); sb.Append(";"); sb.Append((this.Session.ShowExit) ? "T" : "F"); sb.Append(";"); sb.Append((this.Session.ShowSave) ? "T" : "F"); sb.Append(";"); onLoadScript.AppendFormat( "frameMgr.SetNavVisibility( {0}, {1}, {2}, {3}, {4});\r\n", (this.Session.ShowNext ? "true" : "false"), (this.Session.ShowPrevious ? "true" : "false"), (this.Session.ShowAbandon ? "true" : "false"), (this.Session.ShowExit ? "true" : "false"), (this.Session.ShowSave ? "true" : "false")); controls.Add(HiddenFieldNames.ShowUI, sb.ToString()); context.Script = onLoadScript.ToString(); }
// catching all exceptions in order to return http response code private void RenderPackageContent(string resPath) { // If this is the primary resource of the current activity, then process it for rendering, including (in the case of // LRM content) injecting script to notify client script of page load. if (this.IsPrimaryResource(resPath)) { // If the resPath is empty or it matches the xmlBase value of the resource of the current activity, // that means it's asking for the default resource associated with the current // activity. Check if there is one. If there isn't, then show a message that indicates the content can't be shown // because there's no resource. if (this.Session.CurrentActivityResourceType == ResourceType.None) { this.RegisterError( ResHelper.GetMessage(Localization.GetMessage("CON_ResourceNotFoundTitle")), ResHelper.GetMessage(Localization.GetMessage("CON_ResourceNotFoundMsg")), false); return; } // If the entry point for the current activity is an absolute Uri, then we should not be here (the // hidden frame should have loaded the absolute Uri into the content frame). if (this.Session.CurrentActivityEntryPoint.IsAbsoluteUri) { this.RegisterError( ResHelper.GetMessage(Localization.GetMessage("CON_ResourceNotFoundTitle")), ResHelper.GetMessage(Localization.GetMessage("CON_ResourceNotFoundMsg")), false); return; } bool fileNotFound = false; // Check if we got an exception indicating the file could not be found try { string filePath = this.Session.CurrentActivityEntryPoint.OriginalString.Replace("%20", " "); RenderContext context = new RenderContext(filePath, this.Response); StringBuilder scriptBlock = new StringBuilder(1000); // Initialize the hidden control and script for the page this.InitHiddenControlInfo(context, scriptBlock); // Allow application to modify the context. this.UpdateRenderContext(context, scriptBlock, this.Session); this.FinishOnLoadScript(scriptBlock); // Save script to context, if neeed if (scriptBlock.Length > 0) { context.Script = scriptBlock.ToString(); } // Clear any previous page information and render the page this.Session.Render(context); // When the primary resource is rendered, the session may be changed, so save any changes. if (!this.SessionIsReadOnly) { this.Session.CommitChanges(); } } catch (FileNotFoundException) { fileNotFound = true; } catch (DirectoryNotFoundException) { fileNotFound = true; } if (fileNotFound) { // The entry point defined in the package was a relative Uri but does not map to a file in the package. this.RegisterError( ResHelper.GetMessage(Localization.GetMessage("CON_ResourceNotFoundTitle")), ResHelper.GetMessage(Localization.GetMessage("CON_ResourceNotFoundMsg")), false); return; } } else { long pageId; if (this.IsPrimaryResourceOfLrmActivity(resPath, out pageId)) { // If this is LRM content and is a request for the primary resource of another activity, then // move to that activity and render a 'please wait' // message that tells the frameset about the new activity. ProcessNavigationRequests(this.Session); string activityId = "ITEM" + FramesetUtil.GetStringInvariant(pageId); this.Session.MoveToActivity(activityId); if (!this.SessionIsReadOnly) { this.Session.CommitChanges(); } this.Response.Clear(); this.Response.Redirect(this.GetRedirectLocation()); } else { // There was a relative path provided. Write it to the output stream. If this method fails because the path was not // in the package or could not be accessed for some reason, return an error code. try { RenderContext context = new RenderContext(resPath.Replace("%20", " "), this.Response); this.UpdateRenderContext(context, null, this.Session); this.Session.Render(context); // Session is not changed in non-Execute views, so no need to call CommitChanges(). } catch (ThreadAbortException) { // Do nothing } catch (FileNotFoundException) { this.Response.StatusCode = 404; this.Response.StatusDescription = "Not Found"; } catch (HttpException) { // Something wrong with the http connection, so in this case do not set the response // headers. } catch { // This could fail for any number of reasons: invalid content that // refers to non-existant file, or a problem somewhere in the server // code. Return generic error code. this.Response.StatusCode = 500; this.Response.StatusDescription = "Internal Server Error"; } } } }
/// <summary> /// Allow the application to modify the RenderContext before content is rendered. /// </summary> /// <param name="context">The context to render. Note: If app needs to change context.Script, /// it should do so by adding to the scriptBlock buffer. </param> /// <param name="scriptBlock">The script that will be written in the onLoad handler of LRM content. /// If this value is null, then the app /// cannot modify the onload script. (This happens when the resource being rendered is not /// the primary resource of an activity that is in LRM format.)</param> /// <param name="session">The session in which content is being rendered.</param> public void UpdateRenderContext(RenderContext context, StringBuilder scriptBlock, LearningSession session) { // Set values other than Response and RelativePath context.EmbeddedUIResourcePath = new Uri(Request.Url, "Images/"); // Set values that map to file extensions SetMappings(context.MimeTypeMapping, context.IisCompatibilityModeExtensions); if (scriptBlock == null) // This is not the primary resource, so nothing else matters return; // Basic Web Player never shows correct answers or reviewer info context.ShowCorrectAnswers = false; context.ShowReviewerInformation = false; }
/// <summary> /// Reads a file from within the package associated with this session and writes it to an HttpResponse. /// </summary> /// <param name="context">The context within which to render the file.</param> /// <remarks> /// At a minimum, the caller must set the following properties in the <paramref name="context"/>: /// <ul> /// <li><c>RelativePath</c></li> /// <li><c>Response</c></li> /// </ul> /// /// On return, the following values in <paramref name="context"/> may have been set by the session: /// <ul> /// <li><c>MimeType</c></li> /// <li><c>FormId</c>, if a default was used.</li> /// </ul> /// In addition, the content was rendered into the <c>Response</c> of <paramref name="context"/>. /// /// <p>This method will not read and write content that is not contained within the package. For instance, /// if the entry point for an activity is an absolute URL and the caller passes it as the /// <c>context.RelativePath</c>, this method will not succeed. It also will not render the package manifest.</p> /// /// </remarks> /// <exception cref="ArgumentNullException">Thrown if <paramref name="context"/> is not provided.</exception> /// <exception cref="InvalidOperationException">Thrown if <c>context.RelativePath</c> or one of /// <c>Response</c>is not provided, or there is no current activity identitified in the session. /// Also thrown if an Execute session requests to render content when the attempt is not active.</exception> /// <exception cref="FileNotFoundException">Thrown if the file referenced in <c>context.RelativePath</c> /// cannot be found, or if the caller requests to render the package manifest.</exception> /// <exception cref="DirectoryNotFoundException">Thrown if the file refernced in <c>context.RelativePath</c> /// includes a directory that does not exist in the package.</exception> public abstract void Render(RenderContext context);
/// <summary> /// Create a context to send to an RloHandler when calling <c>RloHandler.Render</c>. /// </summary> /// <param name="session">The session that is being rendered.</param> /// <param name="renderContext">Information required to render the current file. /// </param> internal RloRenderContext(LearningSession session, RenderContext renderContext) : base(session) { m_context = renderContext; }