1779 lines · 103.4 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.Data;using System.Linq;using System.Net.Http;using System.Text;using System.Web.Routing;using GSF.Collections;using GSF.ComponentModel.DataAnnotations;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 = UrlValidationAttribute.ValidationPattern;         // Fields        private AdoDataConnection m_connection;        private readonly IRazorEngine m_razorEngine;        private readonly Dictionary<Type, ITableOperations> m_tableOperationsCache;        private ConcurrentDictionary<Type, DataTable> m_primaryKeySessionCache;        private readonly Action<Exception> m_exceptionHandler;        private Dictionary<Type, IEnumerable<KeyValuePair<string, string>>> m_customTableOperationTokens;        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_exceptionHandler = exceptionHandler;            m_tableOperationsCache = new Dictionary<Type, ITableOperations>();            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_exceptionHandler = exceptionHandler;            m_tableOperationsCache = new Dictionary<Type, ITableOperations>();            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 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;            }        }         /// <summary>        /// Gets dictionary of per-model custom tokens to use with <see cref="AmendExpressionAttribute"/> values for <see cref="TableOperations{T}"/> in this <see cref="DataContext"/> .        /// </summary>        /// <remarks>        /// The returned dictionary can be used to apply run-time tokens to any defined <see cref="AmendExpressionAttribute"/> values,        /// for example, given the following amendment expression applied to a modeled class:        /// <code>        /// [AmendExpression("TOP {count}",         ///     TargetExpression = TargetExpression.FieldList,        ///     AffixPosition = AffixPosition.Prefix,        ///     StatementTypes = StatementTypes.SelectSet)]]        /// public class MyTable        /// {        ///     string MyField;        /// }        /// </code>        /// The per-model key/value pairs could be set as follows at run-time:        /// <code>        /// int count = 200;        /// dataContext.CustomTableOperationTokens[typeof(MyTable)] = new[] { new KeyValuePair&lt;string, string&gt;("{count}", $"{count}") };        /// </code>        /// </remarks>                public Dictionary<Type, IEnumerable<KeyValuePair<string, string>>> CustomTableOperationTokens => m_customTableOperationTokens ?? (m_customTableOperationTokens = new Dictionary<Type, IEnumerable<KeyValuePair<string, string>>>());         /// <summary>        /// Gets table operations cache for data context.        /// </summary>        internal Dictionary<Type, ITableOperations> TableOperationsCache => m_tableOperationsCache;         /// <summary>        /// Gets or sets session based primary key cache of table operations, creating it if needed.        /// </summary>        internal ConcurrentDictionary<Type, DataTable> PrimaryKeySessionCache        {            get            {                return m_primaryKeySessionCache ?? (m_primaryKeySessionCache = new ConcurrentDictionary<Type, DataTable>());            }            set            {                m_primaryKeySessionCache = 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()        {            IEnumerable<KeyValuePair<string, string>> customTokens = null;             if ((object)m_customTableOperationTokens != null)                m_customTableOperationTokens.TryGetValue(typeof(TModel), out customTokens);             return m_tableOperationsCache.GetOrAdd(typeof(TModel), type =>            {                DataTable primaryKeyCache;                TableOperations<TModel> tableOperations = new TableOperations<TModel>(Connection, m_exceptionHandler, customTokens);                 if (PrimaryKeySessionCache.TryGetValue(type, out primaryKeyCache))                    tableOperations.PrimaryKeyCache = primaryKeyCache;                 return tableOperations;            })            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)        {            IEnumerable<KeyValuePair<string, string>> customTokens = null;             if ((object)m_customTableOperationTokens != null)                m_customTableOperationTokens.TryGetValue(model, out customTokens);             return m_tableOperationsCache.GetOrAdd(model, type =>            {                DataTable primaryKeyCache;                ITableOperations tableOperations = Activator.CreateInstance(typeof(TableOperations<>).MakeGenericType(model), Connection, m_exceptionHandler, customTokens) as ITableOperations;                 // ReSharper disable once PossibleNullReferenceException                if (PrimaryKeySessionCache.TryGetValue(type, out primaryKeyCache))                    tableOperations.PrimaryKeyCache = primaryKeyCache;                 return tableOperations;            });        }         /// <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="securityPrincipal">Principal that provides role-based security.</param>        /// <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(SecurityPrincipal securityPrincipal, string role)        {            if ((object)securityPrincipal == null)                return false;             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(securityPrincipal, roles);             ISecurityProvider securityProvider = securityPrincipal.Identity.Provider;            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="securityPrincipal">Security principal that provides role-based security.</param>        /// <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(SecurityPrincipal securityPrincipal, string[] roles)        {            return roles.Any(role => UserIsInRole(securityPrincipal, role));        }         /// <summary>        /// Determines if user is in a specific group or list of groups (comma separated).        /// </summary>        /// <param name="securityPrincipal">Security principal that provides role-based security.</param>        /// <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(SecurityPrincipal securityPrincipal, string group)        {            if ((object)securityPrincipal == null)                return false;             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(securityPrincipal, groups);             ISecurityProvider securityProvider = securityPrincipal.Identity.Provider;            List<string> userGroups = securityProvider?.UserData?.Groups ?? new List<string>();             if (group.Equals("*") && userGroups.Count > 0)                return true; 

Lines 1–500 of 1779.

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