diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..960ed18 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,68 @@ +## Purpose + +This repository generates human-readable HTML documentation for Microsoft SQL Server databases (2005+). +This file gives pragmatic, repo-specific guidance for an AI coding assistant to be productive quickly. + +## Quick Tasks + +- **Build:** run `dotnet build` at the repository root (solution file `SqlServerDatabaseDocumentationGenerator.sln`). VS2019/VS2022 can also be used for .NET Framework builds. +- **Run Console Example:** edit `DocumentationGeneratorConsole/Program.cs` to change the connection string, then run the Console project; it writes `database.html` to the current directory. +- **Run GUI:** `DocumentationGeneratorApplication` is a WinForms app (MainForm.cs). Launch from Visual Studio to use the interactive connection-string dialog. + +## Key Components (big picture) + +- **Entry projects:** + - `DocumentationGeneratorApplication/` — WinForms GUI, interactive connection string and save dialog (MainForm.cs, FrmConnectionString.cs). + - `DocumentationGeneratorConsole/` — small console runner (Program.cs), currently uses a hard-coded `connStr` and writes `database.html`. + - `SqlServerDatabaseDocumentationGenerator/` — core library: Document, Inspection, Model, Utility, and DesignIssue folders. + +- **Core flow:** + 1. `DatabaseInspector` (in `Inspection/`) reads metadata from SQL Server (schemas, tables, views, columns, routines) into Model objects. + 2. `DatabaseHtmlDocumentGenerator` (in `Document/`) converts `Model.Database` to an HTML document using an internal `HtmlTextWriter` fallback. + 3. Output is an HTML file (Bootstrap CSS included inline). + +## Repo-specific patterns & conventions + +- Database object descriptions are pulled from the extended property named `MS_Description` (expect code to refer to this). +- The `Document/DatabaseHtmlDocumentGenerator.cs` contains a self-contained fallback for `System.Web.UI.HtmlTextWriter` — careful when adding System.Web references or testing on environments without it. +- Inspector classes follow the pattern `*Inspector.cs` (e.g., `TableInspector.cs`, `SchemaInspector.cs`) and populate POCOs in `Model/` — prefer working through the inspector methods to change how metadata is collected. + +## Important files to inspect/edit + +- `SqlServerDatabaseDocumentationGenerator/Document/DatabaseHtmlDocumentGenerator.cs` — main HTML generation; contains the app version and base CSS. +- `SqlServerDatabaseDocumentationGenerator/Inspection/DatabaseInspector.cs` — orchestrates other inspectors and exposes `GetDatabaseMetaData()`. +- `DocumentationGeneratorConsole/Program.cs` — minimal runnable example; useful for automation and CI. +- `DocumentationGeneratorApplication/` — UI-specific code (WinForms): `MainForm.cs`, `FrmConnectionString.cs`. +- `SqlServerDatabaseDocumentationGenerator.sln` and `.vscode/tasks.json` (task `build`) — canonical build targets. + +## Building, testing, and debugging notes + +- The solution targets .NET Framework 4.8 (Readme states 4.8, compatible with 4.5+). Use Visual Studio for WinForms debugging. +- To build from terminal (cross-machine): + +``` +dotnet build "SqlServerDatabaseDocumentationGenerator.sln" +``` + +- The console project currently hardcodes a connection string — update `Program.cs` or add CLI arg parsing before running in non-dev environments. +- Output HTML (example) is at `AdventureWorks-example.html` in the repo root — use it as a sample for layout and expected content. + +## Integration & external dependencies + +- Expects a reachable Microsoft SQL Server instance and valid connection string (Integrated or SQL auth). +- Third-party code lives under `third-party/` (e.g., `BeTimvwFramework`); inspect those for license/compat issues. + +## Coding guidance for PRs + +- Preserve public model shapes in `Model/` where possible — many components (inspectors, document generator) rely on these POCOs. +- When modifying HTML output, edit `DatabaseHtmlDocumentGenerator.cs`. There is an inline `baseCss` and bootstrap usage; search for `baseCss` in that file. +- Avoid introducing a hard dependency on `System.Web` — the repo intentionally includes a lightweight fallback. If you add System.Web references, update project files and ensure builds still succeed on CI/targets. + +## Helpful searches/examples + +- To find metadata collection code: search for `GetDatabaseMetaData`, `DatabaseInspector`, or names under `Inspection/`. +- To find where descriptions are read: search for `MS_Description` or `ExtendedProperty` string patterns. + +## If you need more + +If any part of the flow or environment is unclear (e.g., which project is used in a specific CI or how tests are run), tell me which area to expand and I will update this file with concrete commands and examples. diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..ce55aa6 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Launch DocumentationGeneratorConsole (exe)", + "type": "coreclr", + "request": "launch", + "program": "${workspaceFolder}/DocumentationGeneratorConsole/bin/Debug/net40/DocumentationGeneratorConsole.exe", + "args": [], + "cwd": "${workspaceFolder}/DocumentationGeneratorConsole", + "console": "internalConsole" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..013007b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "dotnet.preferCSharpExtension": true +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..369ad88 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}", + "/property:GenerateFullPaths=true", + "/consoleLoggerParameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/001_Source/SqlServerDatabaseDocumentationGenerator-master.zip b/001_Source/SqlServerDatabaseDocumentationGenerator-master.zip new file mode 100644 index 0000000..12fa4c1 Binary files /dev/null and b/001_Source/SqlServerDatabaseDocumentationGenerator-master.zip differ diff --git a/DbDocGenerator/DbDocGenerator.csproj b/DbDocGenerator/DbDocGenerator.csproj index a3f9e65..1680ad8 100644 --- a/DbDocGenerator/DbDocGenerator.csproj +++ b/DbDocGenerator/DbDocGenerator.csproj @@ -1,58 +1,16 @@  - - + + - Debug - AnyCPU - {77C675D0-B954-45F0-AAD8-E3880829EA02} + net45 Exe - Properties DbDocGenerator DbDocGenerator - v4.5 - 512 + false - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - + - - + \ No newline at end of file diff --git a/DocumentationGeneratorApplication/DocumentationGeneratorApplication.csproj b/DocumentationGeneratorApplication/DocumentationGeneratorApplication.csproj index 93845a7..7594656 100644 --- a/DocumentationGeneratorApplication/DocumentationGeneratorApplication.csproj +++ b/DocumentationGeneratorApplication/DocumentationGeneratorApplication.csproj @@ -1,123 +1,21 @@  - - + + - Debug - AnyCPU - {5FF70C2D-FDE3-47F6-A95C-605C98CE1996} + net48 + true WinExe - Properties net.datacowboy.DocumentationGeneratorApplication DocumentationGeneratorApplication - v4.8 - 512 - + false - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - - - - - - - - - - - - - - Form - - - FrmConnectionString.cs - - - Form - - - FrmObjectsWithoutDescription.cs - - - Form - - - MainForm.cs - - - - - - - - - FrmConnectionString.cs - - - FrmObjectsWithoutDescription.cs - - - MainForm.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - + + - - {68bb69bf-a89e-4a81-b2b7-160ace34e0f7} - SqlServerDatabaseDocumentationGenerator - + - - - + \ No newline at end of file diff --git a/DocumentationGeneratorApplication/FrmConnectionString.cs b/DocumentationGeneratorApplication/FrmConnectionString.cs index 419150b..383ccfb 100644 --- a/DocumentationGeneratorApplication/FrmConnectionString.cs +++ b/DocumentationGeneratorApplication/FrmConnectionString.cs @@ -105,6 +105,9 @@ public FrmConnectionString(string connectionString="") catch (Exception ex) { //TODO: tell user something wrong in initial connection string + MessageBox.Show(String.Format("Unable to parse initial connection string:\n{0}", ex.Message), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + builder = new SqlConnectionStringBuilder(); + } if (!String.IsNullOrWhiteSpace(builder.DataSource)) diff --git a/DocumentationGeneratorApplication/MainForm.cs b/DocumentationGeneratorApplication/MainForm.cs index 0ff51b7..bba9afb 100644 --- a/DocumentationGeneratorApplication/MainForm.cs +++ b/DocumentationGeneratorApplication/MainForm.cs @@ -42,10 +42,32 @@ private string getConnectionStringFromAppConfig() string connString = null; - var config = ConfigurationManager.ConnectionStrings["default"]; - if (config != null) + try + { + // Try to access ConfigurationManager via reflection so the code compiles + // even when System.Configuration assembly is not referenced (e.g. .NET Core). + var cmType = Type.GetType("System.Configuration.ConfigurationManager, System.Configuration.ConfigurationManager") + ?? Type.GetType("System.Configuration.ConfigurationManager"); + if (cmType != null) + { + var connectionStringsProp = cmType.GetProperty("ConnectionStrings", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public); + var connectionStrings = connectionStringsProp?.GetValue(null); + if (connectionStrings != null) + { + // indexer "Item" with key + var indexer = connectionStrings.GetType().GetProperty("Item"); + var config = indexer?.GetValue(connectionStrings, new object[] { "default" }); + if (config != null) + { + var connStringProp = config.GetType().GetProperty("ConnectionString"); + connString = connStringProp?.GetValue(config) as string; + } + } + } + } + catch { - connString = config.ConnectionString; + // ignore any reflection failures and return null } diff --git a/DocumentationGeneratorConsole/DocumentationGeneratorConsole.csproj b/DocumentationGeneratorConsole/DocumentationGeneratorConsole.csproj index 7de55c8..a736c1a 100644 --- a/DocumentationGeneratorConsole/DocumentationGeneratorConsole.csproj +++ b/DocumentationGeneratorConsole/DocumentationGeneratorConsole.csproj @@ -1,65 +1,20 @@  - - + + - Debug - AnyCPU - {CBD3F56E-359E-455D-AEF5-91AC205743B1} + net40 Exe - Properties net.datacowboy.DocumentationGeneratorConsole DocumentationGeneratorConsole - v4.0 - 512 - + false - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - + + - - {68bb69bf-a89e-4a81-b2b7-160ace34e0f7} - SqlServerDatabaseDocumentationGenerator - + - - + \ No newline at end of file diff --git a/SqlServerDatabaseDocumentationGenerator/Document/DatabaseHtmlDocumentGenerator.cs b/SqlServerDatabaseDocumentationGenerator/Document/DatabaseHtmlDocumentGenerator.cs index 4d63951..774dfdd 100644 --- a/SqlServerDatabaseDocumentationGenerator/Document/DatabaseHtmlDocumentGenerator.cs +++ b/SqlServerDatabaseDocumentationGenerator/Document/DatabaseHtmlDocumentGenerator.cs @@ -7,6 +7,114 @@ using net.datacowboy.SqlServerDatabaseDocumentationGenerator.Model; using net.datacowboy.SqlServerDatabaseDocumentationGenerator.Utility; +// Provide a lightweight fallback for System.Web.UI.HtmlTextWriter and related types when System.Web is not referenced. +// This allows the project to compile in environments where System.Web (and its assemblies) are unavailable. +// The fallback implements only the methods and enums used by this file. +namespace System.Web.UI +{ + public enum HtmlTextWriterTag + { + Html, Head, Title, Style, Body, H1, P, Hr, H2, Table, Thead, Tr, Th, Tbody, Td, A, Caption, H3, Span + } + + public enum HtmlTextWriterAttribute + { + Class, Type, Href, Style + } + + public class HtmlTextWriter : System.IO.TextWriter + { + private readonly System.IO.TextWriter _writer; + private readonly System.Collections.Generic.Stack _tagStack = new System.Collections.Generic.Stack(); + private readonly System.Text.StringBuilder _attrBuilder = new System.Text.StringBuilder(); + + public HtmlTextWriter(System.IO.TextWriter writer) + { + _writer = writer ?? throw new System.ArgumentNullException(nameof(writer)); + } + + public override System.Text.Encoding Encoding => _writer.Encoding; + + public void AddAttribute(HtmlTextWriterAttribute attr, string value) + { + AddAttribute(attr.ToString().ToLowerInvariant(), value); + } + + public void AddAttribute(string name, string value) + { + if (string.IsNullOrEmpty(value)) return; + // encode attribute values to avoid broken HTML + _attrBuilder.Append(' '); + _attrBuilder.Append(name); + _attrBuilder.Append("=\""); + _attrBuilder.Append(System.Net.WebUtility.HtmlEncode(value)); + _attrBuilder.Append('"'); + } + + public override void WriteLine(string s) + { + _writer.WriteLine(s); + } + + public override void Write(char value) + { + _writer.Write(value); + } + + public override void Write(string s) + { + _writer.Write(s); + } + + public void WriteEncodedText(string s) + { + _writer.Write(System.Net.WebUtility.HtmlEncode(s ?? string.Empty)); + } + + public void RenderBeginTag(HtmlTextWriterTag tag) + { + var tagName = tag.ToString().ToLowerInvariant(); + + // treat hr as self-closing + if (tag == HtmlTextWriterTag.Hr) + { + _writer.Write(" 0) + { + _writer.Write(_attrBuilder.ToString()); + _attrBuilder.Clear(); + } + _writer.Write(" />"); + return; + } + + _writer.Write('<'); + _writer.Write(tagName); + if (_attrBuilder.Length > 0) + { + _writer.Write(_attrBuilder.ToString()); + _attrBuilder.Clear(); + } + _writer.Write('>'); + _tagStack.Push(tagName); + } + + public void RenderEndTag() + { + if (_tagStack.Count == 0) return; + var tagName = _tagStack.Pop(); + _writer.Write("'); + } + + public void WriteBreak() + { + _writer.Write("
"); + } + } +} + namespace net.datacowboy.SqlServerDatabaseDocumentationGenerator.Document { public class DatabaseHtmlDocumentGenerator @@ -162,10 +270,41 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN } hw.RenderEndTag(); //td + hw.RenderEndTag(); //tr + + + #region Total Table Fields Summary + + hw.RenderBeginTag(HtmlTextWriterTag.Tr); + hw.RenderBeginTag(HtmlTextWriterTag.Td); + hw.Write("Fields (all tables)"); + hw.RenderEndTag(); //td + hw.AddAttribute(HtmlTextWriterAttribute.Class, "text-right"); + hw.RenderBeginTag(HtmlTextWriterTag.Td); + if (hasTables) + { + // compute total number of fields (columns) in all tables + int totalTableFields = 0; + if (db.Schemas != null) + { + totalTableFields = db.Schemas.Sum(sch => (sch.Tables != null) ? sch.Tables.Sum(tbl => (tbl.Columns != null) ? tbl.Columns.Count : 0) : 0); + } + hw.WriteEncodedText(totalTableFields.ToString()); + } + else + { + hw.Write("0"); + } + + hw.RenderEndTag(); //td hw.RenderEndTag(); //tr + #endregion + + + hw.RenderBeginTag(HtmlTextWriterTag.Tr); @@ -271,6 +410,101 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN //Render tables if (hasTables) { + + #region Tables Records (Rows) + + + + hw.RenderBeginTag(HtmlTextWriterTag.Hr); + hw.RenderEndTag(); //hr + + + hw.RenderBeginTag(HtmlTextWriterTag.H2); + hw.WriteEncodedText("Tables Records"); + hw.RenderEndTag(); //h2 + + + hw.AddAttribute(HtmlTextWriterAttribute.Class, "table table-bordered table-striped table-condensed schema-objects-list-container"); + hw.RenderBeginTag(HtmlTextWriterTag.Table); + + hw.RenderBeginTag(HtmlTextWriterTag.Thead); + + hw.RenderBeginTag(HtmlTextWriterTag.Tr); + hw.RenderBeginTag(HtmlTextWriterTag.Th); + hw.Write("Table Name"); + hw.RenderEndTag(); //th + + hw.RenderBeginTag(HtmlTextWriterTag.Th); + hw.Write("Records (Rows)"); + hw.RenderEndTag(); //th + + hw.RenderEndTag(); //tr + + hw.RenderEndTag(); //thead + + + hw.RenderBeginTag(HtmlTextWriterTag.Tbody); + + + int totalTableRecords = 0; + + for (int t = 0; t < schema.Tables.Count; t++) + { + var table = schema.Tables[t]; + if (table.RowCount > 0) + { + totalTableRecords += table.RowCount; + + hw.RenderBeginTag(HtmlTextWriterTag.Tr); + hw.RenderBeginTag(HtmlTextWriterTag.Td); + + bool createHyperlink = true; + if (createHyperlink) + { + // create internel hyperlink target + hw.AddAttribute("href", String.Concat("#_", table.ObjectId.ToString())); + hw.RenderBeginTag(HtmlTextWriterTag.A); + hw.WriteEncodedText(table.TableName); + hw.RenderEndTag(); //a + } + else + { + hw.Write(table.TableName); + } + + + hw.RenderEndTag(); //td + + hw.AddAttribute(HtmlTextWriterAttribute.Class, "text-left"); + hw.RenderBeginTag(HtmlTextWriterTag.Td); + hw.WriteEncodedText(table.RowCount.ToString("N0")); + + hw.RenderEndTag(); //td + hw.RenderEndTag(); //tr + } + } + hw.RenderBeginTag(HtmlTextWriterTag.Tr); + + hw.AddAttribute(HtmlTextWriterAttribute.Class, "text-center"); + hw.AddAttribute(HtmlTextWriterAttribute.Style, "font-weight:bold;"); + hw.RenderBeginTag(HtmlTextWriterTag.Td); + hw.Write("Total records"); + hw.RenderEndTag(); //td + + hw.AddAttribute(HtmlTextWriterAttribute.Class, "text-center"); + hw.AddAttribute(HtmlTextWriterAttribute.Style, "font-weight:bold;"); + hw.RenderBeginTag(HtmlTextWriterTag.Td); + hw.WriteEncodedText(totalTableRecords.ToString("N0")); + + hw.RenderEndTag(); //td + hw.RenderEndTag(); //tr + + + hw.RenderEndTag(); //tbody + hw.RenderEndTag(); //table + + + #endregion for (int t = 0; t < schema.Tables.Count; t++) diff --git a/SqlServerDatabaseDocumentationGenerator/Inspection/TableInspector.cs b/SqlServerDatabaseDocumentationGenerator/Inspection/TableInspector.cs index 0c38eb8..c7a9dd1 100644 --- a/SqlServerDatabaseDocumentationGenerator/Inspection/TableInspector.cs +++ b/SqlServerDatabaseDocumentationGenerator/Inspection/TableInspector.cs @@ -40,6 +40,8 @@ public IList GetTables(Schema schema) table.Indexes = indexInspector.GetIndexes(table); table.ForeignKeys = foreignKeyInspector.GetForeignKeys(table); table.Parent = schema; + table.RowCount = this.peta.ExecuteScalar("Select Sum(row_count) FROM sys.dm_db_partition_stats WHERE object_id = @0 AND (index_id = 0 OR index_id = 1)", table.TableId); + // We could store RowCount in Table class if needed in future } } diff --git a/SqlServerDatabaseDocumentationGenerator/Model/Table.cs b/SqlServerDatabaseDocumentationGenerator/Model/Table.cs index c0f9f66..cf4701c 100644 --- a/SqlServerDatabaseDocumentationGenerator/Model/Table.cs +++ b/SqlServerDatabaseDocumentationGenerator/Model/Table.cs @@ -30,6 +30,8 @@ public class Table : IDbObject public string ObjectTypeDisplayText { get { return "Table"; } } + public int RowCount { get; set; } + /// /// Check if the table has any columns which use a user defined data type /// diff --git a/SqlServerDatabaseDocumentationGenerator/SqlServerDatabaseDocumentationGenerator.csproj b/SqlServerDatabaseDocumentationGenerator/SqlServerDatabaseDocumentationGenerator.csproj index 40080bd..3c7ce98 100644 --- a/SqlServerDatabaseDocumentationGenerator/SqlServerDatabaseDocumentationGenerator.csproj +++ b/SqlServerDatabaseDocumentationGenerator/SqlServerDatabaseDocumentationGenerator.csproj @@ -1,103 +1,20 @@  - - + + - Debug - AnyCPU - {68BB69BF-A89E-4A81-B2B7-160ACE34E0F7} + net48 Library - Properties net.datacowboy.SqlServerDatabaseDocumentationGenerator SqlServerDatabaseDocumentationGenerator - v4.8 - 512 - + + false - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - false - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + Always - - - + \ No newline at end of file diff --git a/SqlServerDatabaseDocumentationGenerator/third-party/PetaPoco.cs b/SqlServerDatabaseDocumentationGenerator/third-party/PetaPoco.cs index ac1c44a..06f312f 100644 --- a/SqlServerDatabaseDocumentationGenerator/third-party/PetaPoco.cs +++ b/SqlServerDatabaseDocumentationGenerator/third-party/PetaPoco.cs @@ -159,14 +159,23 @@ public Database(string connectionStringName) { // Use first? if (connectionStringName == "") - connectionStringName = ConfigurationManager.ConnectionStrings[0].Name; + { + var first = GetConnectionStringByIndex(0); + if (first == null) + throw new InvalidOperationException("Can't find any connection strings in configuration."); + var nameProp = first.GetType().GetProperty("Name"); + connectionStringName = nameProp == null ? "" : (string)nameProp.GetValue(first, null); + } // Work out connection string and provider name var providerName = "System.Data.SqlClient"; - if (ConfigurationManager.ConnectionStrings[connectionStringName] != null) + var cs = GetConnectionStringByName(connectionStringName); + if (cs != null) { - if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName)) - providerName = ConfigurationManager.ConnectionStrings[connectionStringName].ProviderName; + var provProp = cs.GetType().GetProperty("ProviderName"); + var provVal = provProp == null ? null : provProp.GetValue(cs, null) as string; + if (!string.IsNullOrEmpty(provVal)) + providerName = provVal; } else { @@ -174,11 +183,49 @@ public Database(string connectionStringName) } // Store factory and connection string - _connectionString = ConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString; + var connProp = cs.GetType().GetProperty("ConnectionString"); + _connectionString = connProp == null ? null : connProp.GetValue(cs, null) as string; _providerName = providerName; CommonConstruct(); } + // Reflection-based helpers to access ConfigurationManager.ConnectionStrings without a compile-time dependency + private static object GetConnectionStringByName(string name) + { + Type cfgType = Type.GetType("System.Configuration.ConfigurationManager, System.Configuration") + ?? Type.GetType("System.Configuration.ConfigurationManager, System.Configuration.ConfigurationManager"); + if (cfgType == null) + return null; + var connStringsProp = cfgType.GetProperty("ConnectionStrings", BindingFlags.Static | BindingFlags.Public); + if (connStringsProp == null) + return null; + var connStrings = connStringsProp.GetValue(null, null); + if (connStrings == null) + return null; + var itemProp = connStrings.GetType().GetProperty("Item", new Type[] { typeof(string) }); + if (itemProp != null) + return itemProp.GetValue(connStrings, new object[] { name }); + return null; + } + + private static object GetConnectionStringByIndex(int index) + { + Type cfgType = Type.GetType("System.Configuration.ConfigurationManager, System.Configuration") + ?? Type.GetType("System.Configuration.ConfigurationManager, System.Configuration.ConfigurationManager"); + if (cfgType == null) + return null; + var connStringsProp = cfgType.GetProperty("ConnectionStrings", BindingFlags.Static | BindingFlags.Public); + if (connStringsProp == null) + return null; + var connStrings = connStringsProp.GetValue(null, null); + if (connStrings == null) + return null; + var itemProp = connStrings.GetType().GetProperty("Item", new Type[] { typeof(int) }); + if (itemProp != null) + return itemProp.GetValue(connStrings, new object[] { index }); + return null; + } + enum DBType { SqlServer, diff --git a/SqlServerDatabaseDocumentationGeneratorTest/SqlServerDatabaseDocumentationGeneratorTest.csproj b/SqlServerDatabaseDocumentationGeneratorTest/SqlServerDatabaseDocumentationGeneratorTest.csproj index ddef9bb..db45f12 100644 --- a/SqlServerDatabaseDocumentationGeneratorTest/SqlServerDatabaseDocumentationGeneratorTest.csproj +++ b/SqlServerDatabaseDocumentationGeneratorTest/SqlServerDatabaseDocumentationGeneratorTest.csproj @@ -1,90 +1,23 @@  - + + - Debug - AnyCPU - {1EF99352-90C4-4AD3-B45A-439BF2E25633} + net48 Library - Properties SqlServerDatabaseDocumentationGeneratorTest SqlServerDatabaseDocumentationGeneratorTest - v4.8 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - + true + false - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - + - - + + + + - - {68bb69bf-a89e-4a81-b2b7-160ace34e0f7} - SqlServerDatabaseDocumentationGenerator - + - - - - - False - - - False - - - False - - - False - - - - - - - + \ No newline at end of file