//******************************************************************************************************
// 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
}
}