//******************************************************************************************************// 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. Load more
//****************************************************************************************************** // 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 StaticMemberInGenericType namespace 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>