//****************************************************************************************************** // RazorView.cs - Gbtc // // Copyright © 2016, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this // file except in compliance with the License. You may obtain a copy of the License at: // // http://opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 01/13/2016 - J. Ritchie Carroll // Generated original version of source code. // //****************************************************************************************************** using System; using System.Collections.Generic; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using System.Web; using GSF.Collections; using GSF.Data; using GSF.Web.Hosting; using GSF.Web.Security; using RazorEngine.Templating; // ReSharper disable StaticMemberInGenericType namespace GSF.Web.Model { /// /// Defines a view class for data context based Razor template implementations. /// public class RazorView { #region [ Members ] // Fields private readonly IRazorEngine m_razorEngine; private readonly DynamicViewBag m_viewBag = new DynamicViewBag(); private Dictionary m_parameters; #endregion #region [ Constructors ] /// /// Creates a new . /// /// instance to use. /// Name of template file, typically a .cshtml or .vbhtml file. /// Delegate to handle exceptions, if any. public RazorView(IRazorEngine razorEngine, string templateName, Action exceptionHandler = null) : this(razorEngine, templateName, null, null, null, null, null, exceptionHandler) { } /// /// Creates a new . /// /// instance to use. /// Name of template file, typically a .cshtml or .vbhtml file. /// Reference to model to use when rendering template. /// Type of . /// Type of data class for views based on paged view model, if any. /// Type of SignalR hub for views based on paged view model, if any. /// to use, if any. /// Delegate to handle exceptions, if any. /// Web server options currently in use. public RazorView(IRazorEngine razorEngine, string templateName, object model = null, Type modelType = null, Type pagedViewModelDataType = null, Type pagedViewModelHubType = null, AdoDataConnection database = null, Action exceptionHandler = null, ReadonlyWebServerOptions webServerOptions = null) { m_razorEngine = razorEngine; TemplateName = templateName; Model = model; ModelType = modelType; PagedViewModelDataType = pagedViewModelDataType; PagedViewModelHubType = pagedViewModelHubType; Database = database; ExceptionHandler = exceptionHandler; WebServerOptions = webServerOptions; } #endregion #region [ Properties ] /// /// Gets or sets name of template file. /// public string TemplateName { get; set; } /// /// Gets or sets reference to model to use when rendering template. /// public object Model { get; set; } /// /// Gets or sets type of . /// public Type ModelType { get; set; } /// /// Gets or sets type of data model for views based on paged view model. /// public Type PagedViewModelDataType { get; set; } /// /// Gets or sets type of SignalR hub for views based on paged view model. /// public Type PagedViewModelHubType { get; set; } /// /// Gets reference to view bag used when rendering template. /// public dynamic ViewBag => m_viewBag; /// /// Gets query string parameter specified by . /// /// Name of query string parameter to retrieve. /// Query string parameter specified by . public string this[string key] => Parameters[key]; /// /// Gets a dictionary of query string parameters passed to rendered view. /// public Dictionary Parameters { get { if ((object)m_parameters == null) { HttpRequestMessage request = ViewBag.Request; m_parameters = HttpUtility.ParseQueryString(request.RequestUri.Query).ToDictionary(); } return m_parameters; } } /// /// Gets reference to used by this . /// public IRazorEngine RazorEngine => m_razorEngine; /// /// Gets or sets database connection to provide to , if any. /// public AdoDataConnection Database { get; set; } /// /// Gets or sets delegate used to handle exceptions. /// public Action ExceptionHandler { get; set; } /// /// Gets or sets to use for the provided to the view; defaults to null. /// /// /// This should typically not be changed. When value is null, the data context will use the default /// instance for which is used /// to generate template based HTML input fields for a view. The default HTML input templates are defined /// as embedded resources in GSF.Web. /// public IRazorEngine DataContextEngine { get; set; } /// /// Gets or sets the web server options currently in use. /// public ReadonlyWebServerOptions WebServerOptions { get; set; } #endregion #region [ Methods ] /// /// Compiles and executes view template. /// /// Rendered result. public string Execute() { using (DataContext dataContext = new DataContext(Database, razorEngine: DataContextEngine, exceptionHandler: ExceptionHandler)) { if ((object)PagedViewModelDataType != null && (object)PagedViewModelHubType != null) dataContext.ConfigureView(PagedViewModelDataType, PagedViewModelHubType, null as string, m_viewBag); m_viewBag.AddValue("DataContext", dataContext); return m_razorEngine.RunCompile(TemplateName, ModelType, Model, m_viewBag); } } /// /// Compiles and executes view template for specified request message and post data. /// /// HTTP request message. /// HTTP response message. /// Rendered result. public string Execute(HttpRequestMessage request, HttpResponseMessage response) { using (DataContext dataContext = new DataContext(Database, razorEngine: DataContextEngine, exceptionHandler: ExceptionHandler)) { // Need to add the security principal to the view bag before configuring the view m_viewBag.AddValue("SecurityPrincipal", request.GetRequestContext().Principal); if ((object)PagedViewModelDataType != null && (object)PagedViewModelHubType != null) dataContext.ConfigureView(PagedViewModelDataType, PagedViewModelHubType, request, m_viewBag); m_viewBag.AddValue("Application", s_applicationCache); m_viewBag.AddValue("DataContext", dataContext); m_viewBag.AddValue("Request", request); m_viewBag.AddValue("Response", response); m_viewBag.AddValue("IsPost", request.Method == HttpMethod.Post); m_viewBag.AddValue("WebServerOptions", WebServerOptions); m_viewBag.AddValue("AuthenticationOptions", request.GetAuthenticationOptions()); DynamicViewBag sessionState; // See if a client session has been defined for this execution request if (SessionHandler.TryGetSessionState(request, WebServerOptions?.SessionToken, out sessionState)) m_viewBag.AddValue("Session", sessionState); return m_razorEngine.RunCompile(TemplateName, ModelType, Model, m_viewBag); } } /// /// Asynchronously compiles and executes view template for specified request message and post data. /// /// HTTP request message. /// HTTP response message. /// Propagates notification from client that operations should be canceled. /// Task that will provide rendered result. public Task ExecuteAsync(HttpRequestMessage request, HttpResponseMessage response, CancellationToken cancellationToken) { return Task.Run(() => Execute(request, response), cancellationToken); } #endregion #region [ Static ] // Static Fields private static readonly DynamicViewBag s_applicationCache; // Static Constructor static RazorView() { s_applicationCache = new DynamicViewBag(); } #endregion } }