/// <summary> /// Registers the <see cref="EmbeddedResourceProvider"/> within a <see cref="HostingEnvironment"/>. /// </summary> /// <remarks> /// This function will properly register the <see cref="EmbeddedResourceProvider"/> even when being run from /// within a pre-compiled web application. /// </remarks> public static void Register() { #if MONO HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedResourceProvider()); #else if (BuildManager.IsPrecompiledApp) { // HACK: Call internal registration function for virtual path provider in pre-compiled web application Type hostingEnvironment = AssemblyInfo.FindType("System.Web.Hosting.HostingEnvironment"); if ((object)hostingEnvironment == null) { throw new InvalidOperationException("Failed to register EmbeddedResourceProvider: could not find type \"System.Web.Hosting.HostingEnvironment\"."); } MethodInfo internalRegisterVirtualPathProvider = hostingEnvironment.GetMethod("RegisterVirtualPathProviderInternal", BindingFlags.NonPublic | BindingFlags.Static); if ((object)internalRegisterVirtualPathProvider == null) { throw new InvalidOperationException("Failed to register EmbeddedResourceProvider: could not find internal static method \"System.Web.Hosting.HostingEnvironment.RegisterVirtualPathProviderInternal()\"."); } internalRegisterVirtualPathProvider.Invoke(null, new object[] { new EmbeddedResourceProvider() }); } else { HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedResourceProvider()); } #endif }
/// <summary> /// Controls the binding of a serialized object to a type. /// </summary> /// <param name="assemblyName">Specifies the <see cref="Assembly"/> name of the serialized object.</param> /// <param name="typeName">Specifies the <see cref="Type"/> name of the serialized object.</param> /// <returns>The type of the object the formatter creates a new instance of.</returns> public override Type BindToType(string assemblyName, string typeName) { // Perform namespace transformations that occurred when migrating to the Grid Solutions Framework // from various older versions of code with different namespaces string newTypeName = typeName .Replace("TVA.", "GSF.") .Replace("TimeSeriesFramework.", "GSF.TimeSeries.") .Replace("ConnectionTester.", "GSF.PhasorProtocols.") // PMU Connection Tester namespace .Replace("TVA.Phasors.", "GSF.PhasorProtocols.") // 2007 TVA Code Library namespace .Replace("Tva.Phasors.", "GSF.PhasorProtocols.") // 2008 TVA Code Library namespace .Replace("BpaPdcStream", "BPAPDCstream") // 2013 GSF uppercase phasor protocol namespace .Replace("FNet", "FNET") // 2013 GSF uppercase phasor protocol namespace .Replace("Iec61850_90_5", "IEC61850_90_5") // 2013 GSF uppercase phasor protocol namespace .Replace("Ieee1344", "IEEE1344") // 2013 GSF uppercase phasor protocol namespace .Replace("IeeeC37_118", "IEEEC37_118"); // 2013 GSF uppercase phasor protocol namespace // Check for 2009 TVA Code Library namespace if (newTypeName.StartsWith("PhasorProtocols", StringComparison.Ordinal)) { newTypeName = "GSF." + newTypeName; } // Check for 2014 LineFrequency type in the GSF phasor protocol namespace if (newTypeName.Equals("GSF.PhasorProtocols.LineFrequency", StringComparison.Ordinal)) { newTypeName = "GSF.Units.EE.LineFrequency"; } try { // Search each assembly in the current application domain for the type with the transformed name return(AssemblyInfo.FindType(newTypeName)); } catch { // Fall back on more brute force search when simple search fails foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) { try { Type newType = assembly.GetType(newTypeName); if ((object)newType != null) { return(newType); } } catch { // Ignore errors that occur when attempting to load // types from assemblies as we may still be able to // load the type from a different assembly } } } // No type found; return null return(null); }
private async Task ProcessHTTPHandlerAsync(string pageName, bool embeddedResource, HttpRequestMessage request, HttpResponseMessage response, CancellationToken cancellationToken) { string fileName = GetResourceFileName(pageName, embeddedResource); if (!m_handlerTypeCache.TryGetValue(fileName, out Type handlerType)) { if (!ResourceExists(fileName, embeddedResource)) { response.StatusCode = HttpStatusCode.NotFound; return; } using (Stream source = await OpenResourceAsync(fileName, embeddedResource, cancellationToken)) { string handlerHeader; // Parse class name from ASHX handler header parameters using (StreamReader reader = new StreamReader(source)) handlerHeader = (await reader.ReadToEndAsync()).RemoveCrLfs().Trim(); // Clean up header formatting to make parsing easier handlerHeader = handlerHeader.RemoveDuplicateWhiteSpace().Replace(" =", "=").Replace("= ", "="); string[] tokens = handlerHeader.Split(' '); if (!tokens.Any(token => token.Equals("WebHandler", StringComparison.OrdinalIgnoreCase))) { throw new InvalidOperationException($"Expected \"WebHandler\" file type not found in ASHX file header: {handlerHeader}"); } Dictionary <string, string> parameters = handlerHeader.ReplaceCaseInsensitive("WebHandler", "").Replace("<%", "").Replace("%>", "").Replace("@", "").Trim().ParseKeyValuePairs(' '); if (!parameters.TryGetValue("Class", out string className)) { throw new InvalidOperationException($"Missing \"Class\" parameter in ASHX file header: {handlerHeader}"); } // Remove quotes from class name className = className.Substring(1, className.Length - 2).Trim(); handlerType = AssemblyInfo.FindType(className); if (m_handlerTypeCache.TryAdd(fileName, handlerType)) { OnStatusMessage($"Cached handler type [{handlerType?.FullName}] for file \"{fileName}\""); } } } IHostedHttpHandler handler = null; if ((object)handlerType != null) { handler = Activator.CreateInstance(handlerType) as IHostedHttpHandler; } if ((object)handler == null) { throw new InvalidOperationException($"Failed to create hosted HTTP handler \"{handlerType?.FullName}\" - make sure class implements IHostedHttpHandler interface."); } if (m_options.ClientCacheEnabled && handler.UseClientCache) { if (PublishResponseContent(request, response, handler.GetContentHash(request))) { await handler.ProcessRequestAsync(request, response, cancellationToken); } } else { await handler.ProcessRequestAsync(request, response, cancellationToken); } }
private void CopyModelAsCsvToStream(SecurityPrincipal securityPrincipal, NameValueCollection requestParameters, Stream responseStream, Action flushResponse, CompatibleCancellationToken cancellationToken) { string modelName = requestParameters["ModelName"]; string hubName = requestParameters["HubName"]; string connectionID = requestParameters["ConnectionID"]; string filterText = requestParameters["FilterText"]; string sortField = requestParameters["SortField"]; bool sortAscending = requestParameters["SortAscending"].ParseBoolean(); bool showDeleted = requestParameters["ShowDeleted"].ParseBoolean(); string[] parentKeys = requestParameters["ParentKeys"].Split(',').Select(parentKey => parentKey.Replace(','.RegexEncode(), ",")).ToArray(); if (string.IsNullOrEmpty(modelName)) { throw new ArgumentNullException(nameof(modelName), "Cannot download CSV data: no model type name was specified."); } if (string.IsNullOrEmpty(hubName)) { throw new ArgumentNullException(nameof(hubName), "Cannot download CSV data: no hub type name was specified."); } Type modelType = AssemblyInfo.FindType(modelName); if ((object)modelType == null) { throw new InvalidOperationException($"Cannot download CSV data: failed to find model type \"{modelName}\" in loaded assemblies."); } Type hubType = AssemblyInfo.FindType(hubName); if ((object)hubType == null) { throw new InvalidOperationException($"Cannot download CSV data: failed to find hub type \"{hubName}\" in loaded assemblies."); } IRecordOperationsHub hub; // Record operation tuple defines method name and allowed roles Tuple <string, string> queryRecordCountOperation; Tuple <string, string> queryRecordsOperation; string queryRoles; try { // Create a local record operations hub instance so that CSV export can query same record set that is visible in active hub context hub = Activator.CreateInstance(hubType) as IRecordOperationsHub; if ((object)hub == null) { throw new SecurityException($"Cannot download CSV data: hub type \"{hubName}\" is not a IRecordOperationsHub, access cannot be validated."); } // Assign provided connection ID from active hub context to our local hub instance so that any session based data will be available to query functions hub.ConnectionID = connectionID; Tuple <string, string>[] recordOperations; try { // Get any authorized query roles as defined in hub records operations for modeled table, default to read allowed for query recordOperations = hub.RecordOperationsCache.GetRecordOperations(modelType); if ((object)recordOperations == null) { throw new NullReferenceException(); } } catch (KeyNotFoundException ex) { throw new SecurityException($"Cannot download CSV data: hub type \"{hubName}\" does not define record operations for \"{modelName}\", access cannot be validated.", ex); } // Get record operation for querying record count queryRecordCountOperation = recordOperations[(int)RecordOperation.QueryRecordCount]; if ((object)queryRecordCountOperation == null) { throw new NullReferenceException(); } // Get record operation for querying records queryRecordsOperation = recordOperations[(int)RecordOperation.QueryRecords]; if ((object)queryRecordsOperation == null) { throw new NullReferenceException(); } // Get any defined role restrictions for record query operation - access to CSV download will based on these roles queryRoles = string.IsNullOrEmpty(queryRecordsOperation.Item1) ? "*" : queryRecordsOperation.Item2 ?? "*"; } catch (Exception ex) { throw new SecurityException($"Cannot download CSV data: failed to instantiate hub type \"{hubName}\" or access record operations, access cannot be validated.", ex); } DataContext dataContext = hub.DataContext; // Validate current user has access to requested data if (!dataContext.UserIsInRole(securityPrincipal, queryRoles)) { throw new SecurityException($"Cannot download CSV data: access is denied for user \"{securityPrincipal?.Identity.Name ?? "Undefined"}\", minimum required roles = {queryRoles.ToDelimitedString(", ")}."); } const int TargetBufferSize = 524288; StringBuilder readBuffer = new StringBuilder(TargetBufferSize * 2); ManualResetEventSlim bufferReady = new ManualResetEventSlim(false); List <string> writeBuffer = new List <string>(); object writeBufferLock = new object(); bool readComplete = false; ITableOperations table; string[] fieldNames; bool hasDeletedField; table = dataContext.Table(modelType); fieldNames = table.GetFieldNames(false).Where(field => (!(table.FieldHasAttribute <GSF.Data.Model.CSVExcludeFieldAttribute>(field)))).ToArray(); hasDeletedField = !string.IsNullOrEmpty(dataContext.GetIsDeletedFlag(modelType)); Task readTask = Task.Factory.StartNew(() => { try { const int PageSize = 250; // Get query operation methods MethodInfo queryRecordCount = hubType.GetMethod(queryRecordCountOperation.Item1); MethodInfo queryRecords = hubType.GetMethod(queryRecordsOperation.Item1); // Setup query parameters List <object> queryRecordCountParameters = new List <object>(); List <object> queryRecordsParameters = new List <object>(); // Add current show deleted state parameter, if model defines a show deleted field if (hasDeletedField) { queryRecordCountParameters.Add(showDeleted); } // Add any parent key restriction parameters if (parentKeys.Length > 0 && parentKeys[0].Length > 0) { queryRecordCountParameters.AddRange(parentKeys.Select((value, i) => { Type type = queryRecordCount.GetParameters()[i].ParameterType; if (type == typeof(string)) { return((object)value); } if (type == typeof(Guid)) { return((object)Guid.Parse(value)); } return(Convert.ChangeType(value, type)); })); } // Add parameters for query records from query record count parameters - they match up to this point queryRecordsParameters.AddRange(queryRecordCountParameters); // Add sort field parameter queryRecordsParameters.Add(sortField); // Add ascending sort order parameter queryRecordsParameters.Add(sortAscending); // Track parameter index for current page to query int pageParameterIndex = queryRecordsParameters.Count; // Add page index parameter queryRecordsParameters.Add(0); // Add page size parameter queryRecordsParameters.Add(PageSize); // Add filter text parameter queryRecordCountParameters.Add(filterText); queryRecordsParameters.Add(filterText); // Read queried records in page sets so there is not a memory burden and long initial query delay on very large data sets int recordCount = (int)queryRecordCount.Invoke(hub, queryRecordCountParameters.ToArray()); int totalPages = Math.Max((int)Math.Ceiling(recordCount / (double)PageSize), 1); // Read data pages for (int page = 0; page < totalPages && !cancellationToken.IsCancelled; page++) { // Update desired page to query queryRecordsParameters[pageParameterIndex] = page + 1; // Query page records IEnumerable records = queryRecords.Invoke(hub, queryRecordsParameters.ToArray()) as IEnumerable ?? Enumerable.Empty <object>(); int exportCount = 0; // Export page records foreach (object record in records) { // Periodically check for client cancellation if (exportCount++ % (PageSize / 4) == 0 && cancellationToken.IsCancelled) { break; } readBuffer.AppendLine(string.Join(",", fieldNames.Select(fieldName => $"\"{table.GetFieldValue(record, fieldName)}\""))); if (readBuffer.Length < TargetBufferSize) { continue; } lock (writeBufferLock) writeBuffer.Add(readBuffer.ToString()); readBuffer.Clear(); bufferReady.Set(); } } if (readBuffer.Length > 0) { lock (writeBufferLock) writeBuffer.Add(readBuffer.ToString()); } } finally { readComplete = true; bufferReady.Set(); } }, cancellationToken); Task writeTask = Task.Factory.StartNew(() => { using (StreamWriter writer = new StreamWriter(responseStream)) { //Ticks exportStart = DateTime.UtcNow.Ticks; string[] localBuffer; Action flushStream = () => { writer.Flush(); if ((object)flushResponse != null) { flushResponse(); } }; // Write column headers writer.WriteLine(string.Join(",", fieldNames.Select(fieldName => $"\"{fieldName}\""))); flushStream(); while ((writeBuffer.Count > 0 || !readComplete) && !cancellationToken.IsCancelled) { bufferReady.Wait(cancellationToken); bufferReady.Reset(); lock (writeBufferLock) { localBuffer = writeBuffer.ToArray(); writeBuffer.Clear(); } foreach (string buffer in localBuffer) { writer.Write(buffer); } } // Flush stream flushStream(); //Debug.WriteLine("Export time: " + (DateTime.UtcNow.Ticks - exportStart).ToElapsedTimeString(3)); } }, cancellationToken); Task.WaitAll(readTask, writeTask); }
private async Task CopyModelAsCsvToStreamAsync(NameValueCollection requestParameters, Stream responseStream, Func <bool> isCancelled, Func <Task> flushResponseAsync = null) { SecurityProviderCache.ValidateCurrentProvider(); string modelName = requestParameters["ModelName"]; string hubName = requestParameters["HubName"]; string filterText = requestParameters["FilterText"]; string sortField = requestParameters["SortField"]; bool sortAscending = requestParameters["SortAscending"].ParseBoolean(); bool showDeleted = requestParameters["ShowDeleted"].ParseBoolean(); string[] parentKeys = requestParameters["ParentKeys"].Split(','); const int PageSize = 250; if (string.IsNullOrEmpty(modelName)) { throw new ArgumentNullException(nameof(modelName), "Cannot download CSV data: no model type name was specified."); } if (string.IsNullOrEmpty(hubName)) { throw new ArgumentNullException(nameof(hubName), "Cannot download CSV data: no hub type name was specified."); } Type modelType = AssemblyInfo.FindType(modelName); if ((object)modelType == null) { throw new InvalidOperationException($"Cannot download CSV data: failed to find model type \"{modelName}\" in loaded assemblies."); } Type hubType = AssemblyInfo.FindType(hubName); if ((object)hubType == null) { throw new InvalidOperationException($"Cannot download CSV data: failed to find hub type \"{hubName}\" in loaded assemblies."); } IRecordOperationsHub hub; // Record operation tuple defines method name and allowed roles Tuple <string, string> queryRecordCountOperation; Tuple <string, string> queryRecordsOperation; string queryRoles; try { hub = Activator.CreateInstance(hubType) as IRecordOperationsHub; if ((object)hub == null) { throw new SecurityException($"Cannot download CSV data: hub type \"{hubName}\" is not a IRecordOperationsHub, access cannot be validated."); } Tuple <string, string>[] recordOperations; try { // Get any authorized query roles as defined in hub records operations for modeled table, default to read allowed for query recordOperations = hub.RecordOperationsCache.GetRecordOperations(modelType); if ((object)recordOperations == null) { throw new NullReferenceException(); } } catch (KeyNotFoundException ex) { throw new SecurityException($"Cannot download CSV data: hub type \"{hubName}\" does not define record operations for \"{modelName}\", access cannot be validated.", ex); } // Get record operation for querying record count queryRecordCountOperation = recordOperations[(int)RecordOperation.QueryRecordCount]; if ((object)queryRecordCountOperation == null) { throw new NullReferenceException(); } // Get record operation for querying records queryRecordsOperation = recordOperations[(int)RecordOperation.QueryRecords]; if ((object)queryRecordsOperation == null) { throw new NullReferenceException(); } // Get any defined role restrictions for record query operation - access to CSV download will based on these roles queryRoles = string.IsNullOrEmpty(queryRecordsOperation.Item1) ? "*" : queryRecordsOperation.Item2 ?? "*"; } catch (Exception ex) { throw new SecurityException($"Cannot download CSV data: failed to instantiate hub type \"{hubName}\" or access record operations, access cannot be validated.", ex); } using (DataContext dataContext = new DataContext()) using (StreamWriter writer = new StreamWriter(responseStream)) { // Validate current user has access to requested data if (!dataContext.UserIsInRole(queryRoles)) { throw new SecurityException($"Cannot download CSV data: access is denied for user \"{Thread.CurrentPrincipal.Identity?.Name ?? "Undefined"}\", minimum required roles = {queryRoles.ToDelimitedString(", ")}."); } AdoDataConnection connection = dataContext.Connection; ITableOperations table = dataContext.Table(modelType); string[] fieldNames = table.GetFieldNames(false); Func <Task> flushAsync = async() => { // ReSharper disable once AccessToDisposedClosure await writer.FlushAsync(); if ((object)flushResponseAsync != null) { await flushResponseAsync(); } }; // Write column headers await writer.WriteLineAsync(string.Join(",", fieldNames.Select(fieldName => connection.EscapeIdentifier(fieldName, true)))); await flushAsync(); // See if modeled table has a flag field that represents a deleted row bool hasDeletedField = !string.IsNullOrEmpty(dataContext.GetIsDeletedFlag(modelType)); // Get query operation methods MethodInfo queryRecordCount = hubType.GetMethod(queryRecordCountOperation.Item1); MethodInfo queryRecords = hubType.GetMethod(queryRecordsOperation.Item1); // Setup query parameters List <object> queryRecordCountParameters = new List <object>(); List <object> queryRecordsParameters = new List <object>(); // Add current show deleted state parameter, if model defines a show deleted field if (hasDeletedField) { queryRecordCountParameters.Add(showDeleted); } // Add any parent key restriction parameters if (parentKeys.Length > 0 && parentKeys[0].Length > 0) { queryRecordCountParameters.AddRange(parentKeys); } // Add parameters for query records from query record count parameters - they match up to this point queryRecordsParameters.AddRange(queryRecordCountParameters); // Add sort field parameter queryRecordsParameters.Add(sortField); // Add ascending sort order parameter queryRecordsParameters.Add(sortAscending); // Track parameter index for current page to query int pageParameterIndex = queryRecordsParameters.Count; // Add page index parameter queryRecordsParameters.Add(0); // Add page size parameter queryRecordsParameters.Add(PageSize); // Add filter text parameter queryRecordCountParameters.Add(filterText); queryRecordsParameters.Add(filterText); // Read queried records in page sets so there is not a memory burden and long initial query delay on very large data sets int recordCount = (int)queryRecordCount.Invoke(hub, queryRecordCountParameters.ToArray()); int totalPages = Math.Max((int)Math.Ceiling(recordCount / (double)PageSize), 1); // Write data pages for (int page = 0; page < totalPages && !isCancelled(); page++) { // Update desired page to query queryRecordsParameters[pageParameterIndex] = page + 1; // Query page records IEnumerable records = queryRecords.Invoke(hub, queryRecordsParameters.ToArray()) as IEnumerable ?? Enumerable.Empty <object>(); int exportCount = 0; // Export page records foreach (object record in records) { // Periodically check for client cancellation if (exportCount++ % (PageSize / 4) == 0 && isCancelled()) { break; } await writer.WriteLineAsync(string.Join(",", fieldNames.Select(fieldName => $"\"{table.GetFieldValue(record, fieldName)}\""))); } await flushAsync(); } } }