1505 lines · 84.6 KB · C#
RawDownload
//******************************************************************************************************//  DataContext.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://  ----------------------------------------------------------------------------------------------------//  02/01/2016 - J. Ritchie Carroll//       Generated original version of source code.////****************************************************************************************************** using System;using System.Collections.Concurrent;using System.Collections.Generic;using System.ComponentModel.DataAnnotations;using System.Linq;using System.Net.Http;using System.Text;using System.Web.Routing;using GSF.Collections;using GSF.Data;using GSF.Data.Model;using GSF.Reflection;using GSF.Security;using GSF.Web.Hubs;using RazorEngine.Templating; // ReSharper disable once StaticMemberInGenericTypenamespace GSF.Web.Model{    /// <summary>    /// Defines a data context for Razor views.    /// </summary>    /// <remarks>    /// This class is used by views to render HTML form input templates, paged view model configurations,    /// provide access to modeled table operations and general database access.    /// </remarks>    public class DataContext : IDisposable    {        #region [ Members ]         // Constants         /// <summary>        /// Defines the regular expression used to validate URLs.         /// </summary>        public const string UrlValidation = @"^(?:(?:[a-zA-Z][a-zA-Z0-9.+-]*:\/\/)?[a-zA-Z0-9][a-zA-Z0-9.-]*(?::[0-9]+)?(?:\/[^ ""]*)?|mailto:[a-zA-Z0-9!#$%&'*+-\/=?^_`{|}~][a-zA-Z0-9!#$%&'*+-\/=?^_`{|}~.]*@[a-zA-Z0-9][a-zA-Z0-9.-]*)$";         // Fields        private AdoDataConnection m_connection;        private readonly IRazorEngine m_razorEngine;        private readonly Dictionary<Type, object> m_tableOperations;        private readonly Action<Exception> m_exceptionHandler;        private readonly Dictionary<string, Tuple<string, string>> m_fieldValidationParameters;        private readonly List<Tuple<string, string>> m_fieldValueInitializers;        private readonly List<Tuple<string, string, string, bool>> m_readonlyHotLinkFields;        private readonly List<string> m_definedDateFields;         private readonly string m_settingsCategory;        private readonly bool m_disposeConnection;        private string m_initialFocusField;        private string m_addDateFieldTemplate;        private string m_addInputFieldTemplate;        private string m_addTextAreaFieldTemplate;        private string m_addSelectFieldTemplate;        private string m_addCheckBoxFieldTemplate;        private bool m_disposed;         #endregion         #region [ Constructors ]         /// <summary>        /// Creates a new <see cref="DataContext"/>.        /// </summary>        /// <param name="connection"><see cref="AdoDataConnection"/> to use; defaults to a new connection.</param>        /// <param name="disposeConnection">Set to <c>true</c> to dispose the provided <paramref name="connection"/>.</param>        /// <param name="razorEngine">Razor engine instance to use for data context; set to <c>null</c> to use default embedded resources instance.</param>        /// <param name="exceptionHandler">Delegate to handle exceptions.</param>        public DataContext(AdoDataConnection connection = null, bool disposeConnection = false, IRazorEngine razorEngine = null, Action<Exception> exceptionHandler = null)        {            m_connection = connection;            m_razorEngine = razorEngine ?? RazorEngine<CSharpEmbeddedResource>.Default;            m_tableOperations = new Dictionary<Type, object>();            m_exceptionHandler = exceptionHandler;            m_fieldValidationParameters = new Dictionary<string, Tuple<string, string>>();            m_fieldValueInitializers = new List<Tuple<string, string>>();            m_readonlyHotLinkFields = new List<Tuple<string, string, string, bool>>();            m_definedDateFields = new List<string>();            m_settingsCategory = "systemSettings";            m_disposeConnection = disposeConnection || connection == null;        }         /// <summary>        /// Creates a new <see cref="DataContext"/> using the specified <paramref name="settingsCategory"/>.        /// </summary>        /// <param name="settingsCategory">Setting category that contains the connection settings.</param>        /// <param name="razorEngine">Razor engine instance to use for data context; set to <c>null</c> to use default embedded resources instance.</param>        /// <param name="exceptionHandler">Delegate to handle exceptions.</param>        public DataContext(string settingsCategory, IRazorEngine razorEngine = null, Action<Exception> exceptionHandler = null)        {            m_razorEngine = razorEngine ?? RazorEngine<CSharpEmbeddedResource>.Default;            m_tableOperations = new Dictionary<Type, object>();            m_exceptionHandler = exceptionHandler;            m_fieldValidationParameters = new Dictionary<string, Tuple<string, string>>();            m_fieldValueInitializers = new List<Tuple<string, string>>();            m_readonlyHotLinkFields = new List<Tuple<string, string, string, bool>>();            m_definedDateFields = new List<string>();            m_settingsCategory = settingsCategory;            m_disposeConnection = true;        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets reference to <see cref="IRazorEngine"/> used by this <see cref="DataContext"/>.        /// </summary>        public IRazorEngine RazorEngine => m_razorEngine;         /// <summary>        /// Gets the <see cref="AdoDataConnection"/> for this <see cref="DataContext"/>, creating a new one if needed.        /// </summary>        public AdoDataConnection Connection => m_connection ?? (m_connection = new AdoDataConnection(m_settingsCategory));         /// <summary>        /// Gets reference to user specific security provider instance.        /// </summary>        public AdoSecurityProvider SecurityProvider => SecurityProviderCache.CurrentProvider as AdoSecurityProvider;         /// <summary>        /// Gets validation pattern and error message for rendered fields, if any.        /// </summary>        public Dictionary<string, Tuple<string, string>> FieldValidationParameters => m_fieldValidationParameters;         /// <summary>        /// Gets field value initializers, if any.        /// </summary>        public List<Tuple<string, string>> FieldValueInitializers => m_fieldValueInitializers;         /// <summary>        /// Gets any text input fields that should render clickable URLs and e-mail addresses when in view mode.        /// </summary>        public List<Tuple<string, string, string, bool>> ReadonlyHotLinkFields => m_readonlyHotLinkFields;         /// <summary>        /// Gets defined date fields, if any.        /// </summary>        public List<string> DefinedDateFields => m_definedDateFields;         /// <summary>        /// Gets field name designated for initial focus.        /// </summary>        public string InitialFocusField => m_initialFocusField;         /// <summary>        /// Gets or sets the date field razor template file name.        /// </summary>        public string AddDateFieldTemplate        {            get            {                return m_addDateFieldTemplate ?? (m_addDateFieldTemplate = $"{m_razorEngine.TemplatePath}AddDateField.cshtml");            }            set            {                m_addDateFieldTemplate = value;            }        }         /// <summary>        /// Gets or sets the input field razor template file name.        /// </summary>        public string AddInputFieldTemplate        {            get            {                return m_addInputFieldTemplate ?? (m_addInputFieldTemplate = $"{m_razorEngine.TemplatePath}AddInputField.cshtml");            }            set            {                m_addInputFieldTemplate = value;            }        }         /// <summary>        /// Gets or sets the text area field razor template file name.        /// </summary>        public string AddTextAreaFieldTemplate        {            get            {                return m_addTextAreaFieldTemplate ?? (m_addTextAreaFieldTemplate = $"{m_razorEngine.TemplatePath}AddTextAreaField.cshtml");            }            set            {                m_addTextAreaFieldTemplate = value;            }        }         /// <summary>        /// Gets or sets the select field razor template file name.        /// </summary>        public string AddSelectFieldTemplate        {            get            {                return m_addSelectFieldTemplate ?? (m_addSelectFieldTemplate = $"{m_razorEngine.TemplatePath}AddSelectField.cshtml");            }            set            {                m_addSelectFieldTemplate = value;            }        }         /// <summary>        /// Gets or sets the check box field razor template file name.        /// </summary>        public string AddCheckBoxFieldTemplate        {            get            {                return m_addCheckBoxFieldTemplate ?? (m_addCheckBoxFieldTemplate = $"{m_razorEngine.TemplatePath}AddCheckBoxField.cshtml");            }            set            {                m_addCheckBoxFieldTemplate = value;            }        }         #endregion         #region [ Methods ]         /// <summary>        /// Releases all the resources used by the <see cref="DataContext"/> object.        /// </summary>        public void Dispose()        {            Dispose(true);            GC.SuppressFinalize(this);        }         /// <summary>        /// Releases the unmanaged resources used by the <see cref="DataContext"/> object and optionally releases the managed resources.        /// </summary>        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>        protected virtual void Dispose(bool disposing)        {            if (!m_disposed)            {                try                {                    if (disposing)                    {                        if (m_disposeConnection)                            m_connection?.Dispose();                    }                }                finally                {                    m_disposed = true;  // Prevent duplicate dispose.                }            }        }         /// <summary>        /// Gets the table operations for the specified modeled table <typeparamref name="TModel"/>.        /// </summary>        /// <typeparam name="TModel">Modeled database table (or view).</typeparam>        /// <returns>Table operations for the specified modeled table <typeparamref name="TModel"/>.</returns>        public TableOperations<TModel> Table<TModel>() where TModel : class, new()        {            return m_tableOperations.GetOrAdd(typeof(TModel), type => new TableOperations<TModel>(Connection, m_exceptionHandler)) as TableOperations<TModel>;        }         /// <summary>        /// Gets the table operations for the specified modeled table type <paramref name="model"/>.        /// </summary>        /// <param name="model">Modeled database table (or view) type.</param>        /// <returns>Table operations for the specified modeled table type <paramref name="model"/>.</returns>        public ITableOperations Table(Type model)        {            return m_tableOperations.GetOrAdd(model, type => Activator.CreateInstance(typeof(TableOperations<>).MakeGenericType(model), Connection, m_exceptionHandler)) as ITableOperations;        }         /// <summary>        /// Gets the field name targeted as the primary label for the modeled table.        /// </summary>        /// <typeparam name="TModel">Modeled database table (or view).</typeparam>        /// <returns>Field name targeted as the primary label for the modeled table.</returns>        public string GetPrimaryLabelField<TModel>() where TModel : class, new()        {            return GetPrimaryLabelField(typeof(TModel));        }         /// <summary>        /// Gets the field name targeted as the primary label for the modeled table.        /// </summary>        /// <param name="model">Modeled database table (or view) type.</param>        /// <returns>Field name targeted as the primary label for the modeled table.</returns>        public string GetPrimaryLabelField(Type model)        {            PrimaryLabelAttribute primaryLabelAttribute;             if (model.TryGetAttribute(out primaryLabelAttribute) && !string.IsNullOrWhiteSpace(primaryLabelAttribute.FieldName))                return primaryLabelAttribute.FieldName;             string[] fieldNames = Table(model).GetFieldNames(false);            return fieldNames.Length > 0 ? fieldNames[0] : "";        }         /// <summary>        /// Gets the field name targeted to mark a record as deleted.        /// </summary>        /// <typeparam name="TModel">Modeled database table (or view).</typeparam>        /// <returns>Field name targeted to mark a record as deleted.</returns>        public string GetIsDeletedFlag<TModel>() where TModel : class, new()        {            return GetIsDeletedFlag(typeof(TModel));        }         /// <summary>        /// Gets the field name targeted to mark a record as deleted.        /// </summary>        /// <param name="model">Modeled database table (or view) type.</param>        /// <returns>Field name targeted to mark a record as deleted.</returns>        public string GetIsDeletedFlag(Type model)        {            IsDeletedFlagAttribute isDeletedFlagAttribute;             if (model.TryGetAttribute(out isDeletedFlagAttribute) && !string.IsNullOrWhiteSpace(isDeletedFlagAttribute.FieldName))                return isDeletedFlagAttribute.FieldName;             return null;        }         /// <summary>        /// Determines if user is in a specific role or list of roles (comma separated).        /// </summary>        /// <param name="role">Role or comma separated list of roles.</param>        /// <returns><c>true</c> if user is in <paramref name="role"/>(s); otherwise, <c>false</c>.</returns>        /// <remarks>        /// Set to * for any role.        /// </remarks>        public bool UserIsInRole(string role)        {            if (string.IsNullOrWhiteSpace(role))                return false;             role = role.Trim();             string[] roles = role.Split(',').Where(value => !string.IsNullOrWhiteSpace(value)).ToArray();             if (roles.Length > 1)                return UserIsInRole(roles);             List<string> userRoles = SecurityProvider?.UserData?.Roles ?? new List<string>();             if (role.Equals("*") && userRoles.Count > 0)                return true;             foreach (string userRole in userRoles)                if (userRole.Equals(role, StringComparison.OrdinalIgnoreCase))                    return true;             return false;        }         /// <summary>        /// Determines if user is in one of the provided of roles.        /// </summary>        /// <param name="roles">List of role names.</param>        /// <returns><c>true</c> if user is in one of the <paramref name="roles"/>; otherwise, <c>false</c>.</returns>        public bool UserIsInRole(string[] roles)        {            return roles.Any(UserIsInRole);        }         /// <summary>        /// Determines if user is in a specific group or list of groups (comma separated).        /// </summary>        /// <param name="group">Group or comma separated list of groups.</param>        /// <returns><c>true</c> if user is in <paramref name="group"/>(s); otherwise, <c>false</c>.</returns>        /// <remarks>        /// Set to * for any group.        /// </remarks>        public bool UserIsInGroup(string group)        {            if (string.IsNullOrWhiteSpace(group))                return false;             group = group.Trim();             string[] groups = group.Split(',').Where(value => !string.IsNullOrWhiteSpace(value)).ToArray();             if (groups.Length > 1)                return UserIsInGroup(groups);             List<string> userGroups = SecurityProvider?.UserData?.Groups ?? new List<string>();             if (group.Equals("*") && userGroups.Count > 0)                return true;             foreach (string userGroup in userGroups)                if (userGroup.Equals(group, StringComparison.OrdinalIgnoreCase))                    return true;             return false;        }         /// <summary>        /// Determines if user is in one of the provided of groups.        /// </summary>        /// <param name="groups">List of group names.</param>        /// <returns><c>true</c> if user is in one of the <paramref name="groups"/>; otherwise, <c>false</c>.</returns>        public bool UserIsInGroup(string[] groups)        {            return groups.Any(UserIsInGroup);        }         /// <summary>        /// Configures a simple view with common view bag parameters.        /// </summary>        /// <param name="request">HTTP request message for view used to derive route ID, if any.</param>        /// <param name="viewBag">Current view bag.</param>        /// <remarks>        /// This is normally called from controller before returning view action result.        /// For self-hosted web servers, route ID is passed as a command line parameter, e.g.: myview.cshtml?RouteID=ShowDeleted        /// </remarks>        public void ConfigureView(HttpRequestMessage request, dynamic viewBag)        {            string routeID;            request.QueryParameters().TryGetValue("RouteID", out routeID);            ConfigureView(routeID, viewBag);        }         /// <summary>        /// Configures a view establishing user roles based on modeled table <typeparamref name="TModel"/> and SignalR <typeparamref name="THub"/>.        /// </summary>        /// <param name="request">HTTP request message for view used to derive route ID, if any.</param>        /// <param name="viewBag">Current view bag.</param>        /// <typeparam name="TModel">Modeled database table (or view).</typeparam>        /// <typeparam name="THub">SignalR hub that implements <see cref="IRecordOperationsHub"/>.</typeparam>        /// <remarks>        /// This is normally called from controller before returning view action result.        /// For self-hosted web servers, route ID is passed as a command line parameter, e.g.: myview.cshtml?RouteID=ShowDeleted        /// </remarks>        public void ConfigureView<TModel, THub>(HttpRequestMessage request, dynamic viewBag) where TModel : class, new() where THub : IRecordOperationsHub, new()        {            ConfigureView(typeof(TModel), typeof(THub), request, viewBag);        }         /// <summary>        /// Configures a view establishing user roles based on modeled table <paramref name="model"/> and SignalR <paramref name="hub"/>.        /// </summary>        /// <param name="model">Modeled database table (or view) type.</param>        /// <param name="hub">Type of SignalR hub that implements <see cref="IRecordOperationsHub"/>.</param>        /// <param name="request">HTTP request message for view used to derive route ID, if any.</param>        /// <param name="viewBag">Current view bag.</param>        /// <remarks>        /// This is normally called from controller before returning view action result.        /// For self-hosted web servers, route ID is passed as a command line parameter, e.g.: myview.cshtml?RouteID=ShowDeleted        /// </remarks>        public void ConfigureView(Type model, Type hub, HttpRequestMessage request, dynamic viewBag)        {            string routeID;            request.QueryParameters().TryGetValue("RouteID", out routeID);            ConfigureView(model, hub, routeID, viewBag);        }         /// <summary>        /// Configures a simple view with common view bag parameters.        /// </summary>        /// <param name="requestContext">Url.RequestContext for view used to derive route ID, if any.</param>        /// <param name="viewBag">Current view bag.</param>        /// <remarks>        /// This is normally called from controller before returning view action result.        /// For normal MVC views the common route is "{controller}/{action}/{id}", the {id} of        /// the route is the route ID parameter derived from the route data. In many use        /// cases this is a primary key or action value for the page, e.g., "ShowDeleted".        /// </remarks>        public void ConfigureView(RequestContext requestContext, dynamic viewBag)        {            ConfigureView(requestContext.RouteData.Values["id"] as string, viewBag);        }         /// <summary>

Lines 1–500 of 1505.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t