Add dotnet-sql-cache
This commit is contained in:
parent
8f2eccbd36
commit
fb54566ff5
|
|
@ -33,6 +33,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.Secret
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.SecretManager.Tools.Tests", "test\Microsoft.Extensions.SecretManager.Tools.Tests\Microsoft.Extensions.SecretManager.Tools.Tests.xproj", "{7B331122-83B1-4F08-A119-DC846959844C}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.Caching.SqlConfig.Tools", "src\Microsoft.Extensions.Caching.SqlConfig.Tools\Microsoft.Extensions.Caching.SqlConfig.Tools.xproj", "{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -75,6 +77,10 @@ Global
|
|||
{7B331122-83B1-4F08-A119-DC846959844C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7B331122-83B1-4F08-A119-DC846959844C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7B331122-83B1-4F08-A119-DC846959844C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -90,5 +96,6 @@ Global
|
|||
{2F48041A-F7D1-478F-9C38-D41F0F05E8CA} = {2876B12E-5841-4792-85A8-2929AEE11885}
|
||||
{8730E848-CA0F-4E0A-9A2F-BC22AD0B2C4E} = {66517987-2A5A-4330-B130-207039378FD4}
|
||||
{7B331122-83B1-4F08-A119-DC846959844C} = {F5B382BC-258F-46E1-AC3D-10E5CCD55134}
|
||||
{53F3B53D-303A-4DAA-9C38-4F55195FA5B9} = {66517987-2A5A-4330-B130-207039378FD4}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
"packages": {
|
||||
"Microsoft.DotNet.Watcher.Tools": { },
|
||||
"Microsoft.DotNet.Watcher.Core": { },
|
||||
"Microsoft.Extensions.Caching.SqlConfig.Tools": { },
|
||||
"Microsoft.Extensions.SecretManager.Tools": { }
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,5 +8,6 @@ The project contains command-line tools for the .NET Core SDK.
|
|||
|
||||
- [dotnet-watch](src/Microsoft.DotNet.Watcher.Tools/)
|
||||
- [dotnet-user-secrets](src/Microsoft.Extensions.SecretManager.Tools/)
|
||||
- [dotnet-sql-cache](src/Microsoft.Extensions.Caching.SqlConfig.Tools/)
|
||||
|
||||
This project is part of ASP.NET Core. You can find samples, documentation and getting started instructions for ASP.NET Core at the [Home](https://github.com/aspnet/home) repo.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>53f3b53d-303a-4daa-9c38-4f55195fa5b9</ProjectGuid>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.SqlClient;
|
||||
using Microsoft.Extensions.CommandLineUtils;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.Extensions.Caching.SqlConfig.Tools
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
private string _connectionString = null;
|
||||
private string _schemaName = null;
|
||||
private string _tableName = null;
|
||||
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public Program()
|
||||
{
|
||||
var loggerFactory = new LoggerFactory();
|
||||
loggerFactory.AddConsole();
|
||||
_logger = loggerFactory.CreateLogger<Program>();
|
||||
}
|
||||
|
||||
public static int Main(string[] args)
|
||||
{
|
||||
return new Program().Run(args);
|
||||
}
|
||||
|
||||
public int Run(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
var description = "Creates table and indexes in Microsoft SQL Server database " +
|
||||
"to be used for distributed caching";
|
||||
|
||||
var app = new CommandLineApplication();
|
||||
app.Name = "dotnet-sql-cache";
|
||||
app.Description = description;
|
||||
|
||||
app.HelpOption("-?|-h|--help");
|
||||
|
||||
app.Command("create", command =>
|
||||
{
|
||||
command.Description = description;
|
||||
var connectionStringArg = command.Argument(
|
||||
"[connectionString]",
|
||||
"The connection string to connect to the database.");
|
||||
var schemaNameArg = command.Argument("[schemaName]", "Name of the table schema.");
|
||||
var tableNameArg = command.Argument("[tableName]", "Name of the table to be created.");
|
||||
command.HelpOption("-?|-h|--help");
|
||||
|
||||
command.OnExecute(() =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(connectionStringArg.Value)
|
||||
|| string.IsNullOrEmpty(schemaNameArg.Value)
|
||||
|| string.IsNullOrEmpty(tableNameArg.Value))
|
||||
{
|
||||
_logger.LogWarning("Invalid input");
|
||||
app.ShowHelp();
|
||||
return 2;
|
||||
}
|
||||
|
||||
_connectionString = connectionStringArg.Value;
|
||||
_schemaName = schemaNameArg.Value;
|
||||
_tableName = tableNameArg.Value;
|
||||
|
||||
return CreateTableAndIndexes();
|
||||
});
|
||||
});
|
||||
|
||||
// Show help information if no subcommand/option was specified.
|
||||
app.OnExecute(() =>
|
||||
{
|
||||
app.ShowHelp();
|
||||
return 2;
|
||||
});
|
||||
|
||||
return app.Execute(args);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
_logger.LogCritical("An error occurred. {ErrorMessage}", exception.Message);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private int CreateTableAndIndexes()
|
||||
{
|
||||
ValidateConnectionString();
|
||||
|
||||
using (var connection = new SqlConnection(_connectionString))
|
||||
{
|
||||
connection.Open();
|
||||
|
||||
var sqlQueries = new SqlQueries(_schemaName, _tableName);
|
||||
var command = new SqlCommand(sqlQueries.TableInfo, connection);
|
||||
|
||||
using (var reader = command.ExecuteReader(CommandBehavior.SingleRow))
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
_logger.LogWarning(
|
||||
$"Table with schema '{_schemaName}' and name '{_tableName}' already exists. " +
|
||||
"Provide a different table name and try again.");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
using (var transaction = connection.BeginTransaction())
|
||||
{
|
||||
try
|
||||
{
|
||||
command = new SqlCommand(sqlQueries.CreateTable, connection, transaction);
|
||||
command.ExecuteNonQuery();
|
||||
|
||||
command = new SqlCommand(
|
||||
sqlQueries.CreateNonClusteredIndexOnExpirationTime,
|
||||
connection,
|
||||
transaction);
|
||||
command.ExecuteNonQuery();
|
||||
|
||||
transaction.Commit();
|
||||
|
||||
_logger.LogInformation("Table and index were created successfully.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(
|
||||
"An error occurred while trying to create the table and index. {ErrorMessage}",
|
||||
ex.Message);
|
||||
transaction.Rollback();
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void ValidateConnectionString()
|
||||
{
|
||||
try
|
||||
{
|
||||
new SqlConnectionStringBuilder(_connectionString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
$"Invalid Sql server connection string '{_connectionString}'. {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
[assembly: AssemblyMetadata("Serviceable", "True")]
|
||||
[assembly: NeutralResourcesLanguage("en-us")]
|
||||
[assembly: AssemblyCompany("Microsoft Corporation.")]
|
||||
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
|
||||
[assembly: AssemblyProduct("Microsoft .NET Extensions")]
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Extensions.Caching.SqlConfig.Tools
|
||||
{
|
||||
internal class SqlQueries
|
||||
{
|
||||
private const string CreateTableFormat = "CREATE TABLE {0}(" +
|
||||
// Maximum size of primary key column is 900 bytes (898 bytes from key + 2 additional bytes used by the
|
||||
// Sql Server). In the case where the key is greater than 898 bytes, then it gets truncated.
|
||||
// - Add collation to the key column to make it case-sensitive
|
||||
"Id nvarchar(449) COLLATE SQL_Latin1_General_CP1_CS_AS NOT NULL, " +
|
||||
"Value varbinary(MAX) NOT NULL, " +
|
||||
"ExpiresAtTime datetimeoffset NOT NULL, " +
|
||||
"SlidingExpirationInSeconds bigint NULL," +
|
||||
"AbsoluteExpiration datetimeoffset NULL, " +
|
||||
"CONSTRAINT pk_Id PRIMARY KEY (Id))";
|
||||
|
||||
private const string CreateNonClusteredIndexOnExpirationTimeFormat
|
||||
= "CREATE NONCLUSTERED INDEX Index_ExpiresAtTime ON {0}(ExpiresAtTime)";
|
||||
|
||||
private const string TableInfoFormat =
|
||||
"SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, TABLE_TYPE " +
|
||||
"FROM INFORMATION_SCHEMA.TABLES " +
|
||||
"WHERE TABLE_SCHEMA = '{0}' " +
|
||||
"AND TABLE_NAME = '{1}'";
|
||||
|
||||
public SqlQueries(string schemaName, string tableName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(schemaName))
|
||||
{
|
||||
throw new ArgumentException("Schema name cannot be empty or null");
|
||||
}
|
||||
if (string.IsNullOrEmpty(tableName))
|
||||
{
|
||||
throw new ArgumentException("Table name cannot be empty or null");
|
||||
}
|
||||
|
||||
var tableNameWithSchema = string.Format(
|
||||
"{0}.{1}", DelimitIdentifier(schemaName), DelimitIdentifier(tableName));
|
||||
CreateTable = string.Format(CreateTableFormat, tableNameWithSchema);
|
||||
CreateNonClusteredIndexOnExpirationTime = string.Format(
|
||||
CreateNonClusteredIndexOnExpirationTimeFormat,
|
||||
tableNameWithSchema);
|
||||
TableInfo = string.Format(TableInfoFormat, EscapeLiteral(schemaName), EscapeLiteral(tableName));
|
||||
}
|
||||
|
||||
public string CreateTable { get; }
|
||||
|
||||
public string CreateNonClusteredIndexOnExpirationTime { get; }
|
||||
|
||||
public string TableInfo { get; }
|
||||
|
||||
// From EF's SqlServerQuerySqlGenerator
|
||||
private string DelimitIdentifier(string identifier)
|
||||
{
|
||||
return "[" + identifier.Replace("]", "]]") + "]";
|
||||
}
|
||||
|
||||
private string EscapeLiteral(string literal)
|
||||
{
|
||||
return literal.Replace("'", "''");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"version": "1.0.0-*",
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.CommandLineUtils": "1.1.0-*",
|
||||
"Microsoft.Extensions.Logging": "1.1.0-*",
|
||||
"Microsoft.Extensions.Logging.Console": "1.1.0-*",
|
||||
"System.Data.SqlClient": "4.1.0-*"
|
||||
},
|
||||
"description": "Command line tool to create tables and indexes in a Microsoft SQL Server database for distributed caching.",
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"version": "1.0.0-*",
|
||||
"type": "platform"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"buildOptions": {
|
||||
"outputName": "dotnet-sql-cache",
|
||||
"emitEntryPoint": true,
|
||||
"warningsAsErrors": true,
|
||||
"keyFile": "../../tools/Key.snk",
|
||||
"nowarn": [
|
||||
"CS1591"
|
||||
],
|
||||
"xmlDoc": true
|
||||
},
|
||||
"packOptions": {
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aspnet/DotNetTools"
|
||||
},
|
||||
"tags": [
|
||||
"cache",
|
||||
"distributedcache",
|
||||
"sqlserver"
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue