3

ソース コードに接続情報を保存せずに、データベース モデルとデータベース コンテキストを生成するアイテム テンプレートを作成しようとしています。

アイテム テンプレート ウィザードをサーバー エクスプローラーとうまく連携させ、settings.ttinclude で接続キーを設定できます。

問題は、DTE から IVsDataExplorerConnectionManager へのインターフェイスを解決できないことです。

これは、VSIX プロジェクトでサーバー エクスプローラーを取得する方法であるため、間違ったツリーを鳴らしたと思います。T4 ビジュアル スタジオ テンプレート エンジンでも同様のコードが機能することを期待していました。

他の誰かがすでに同様のことを行っているかどうかを確認するために数時間を費やしましたが、何も見つかりませんでした. T4 テンプレートでサーバー エクスプローラーからの接続を使用する方法についてのアイデアをいただければ幸いです。

2020 年 7 月 23 日更新

その後、デフォルトのカスタム ツールに付属している T4 ITextTemplatingEngineHost が、接続マネージャーを取得するための依存性注入の使用をサポートしていないことを知りました。解決策は、探している情報にアクセスするテンプレート ファイル ジェネレーターを実装することです。また、EngineHost サービスを実装するほど単純ではありません。Visual Studio の内部にある TextTemplatingService は、テキスト テンプレート ジェネレーターをサポートするために必要なインターフェイスを実装している可能性があります。ただし、内部的にサービスはインターフェイスを使用しません。これにより、テンプレート サービスは非常に厳格になり、私が望むほど堅牢ではなくなります。進行中のソリューションは、ビジュアル スタジオ サービスをラップし、TemplatedCodeGenerator をオーバーライドして ProcessTemplate をオーバーライドし、ラップされたサービスを置き換える新しいテンプレート サービスを構築するように見えます。

<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ assembly name="EnvDTE" #>
<#@ assembly name="$(DevEnvDir)PublicAssemblies\Microsoft.VisualStudio.Data.Services.dll" #>
<#@ assembly name="$(DevEnvDir)PublicAssemblies\Microsoft.VisualStudio.OLE.Interop.dll" #>
<#@ assembly name="$(DevEnvDir)PublicAssemblies\Microsoft.VisualStudio.Shell.15.0.dll" #>
<#@ assembly name="$(DevEnvDir)PublicAssemblies\Microsoft.VisualStudio.Shell.Interop.dll" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Data" #>
<#@ assembly name="System.Xml" #>
<#@ assembly name="System.Configuration" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Data" #>
<#@ import namespace="System.Data.SqlClient" #>
<#@ import namespace="System.Data.Common" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Configuration" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="Microsoft.VisualStudio.Shell" #>
<#@ import namespace="Interop = Microsoft.VisualStudio.OLE.Interop" #>
<#@ import namespace="Microsoft.VisualStudio.Data.Services" #>
<#+
public class Settings
{
    const string connectionKey = @"$connectionKey$";
    readonly Guid connectionExplorerGuid = Guid.Parse("8B6159D9-A634-4549-9EAC-8642744F1042");

    public static ITextTemplatingEngineHost Host { get; set; }

    public string[] ExcludeTables
    {
        get
        { 
            return new string[]{
                "sysdiagrams",
                "BuildVersion",
                "aspnet_Applications",
                "aspnet_Membership",
                "aspnet_Paths",
                "aspnet_PersonalizationAllUsers",
                "aspnet_PersonalizationPerUser",
                "aspnet_Profile",
                "aspnet_Roles",
                "aspnet_SchemaVersions",
                "aspnet_Users",
                "aspnet_UsersInRoles",
                "aspnet_WebEvent_Events"
                };
        }
    }

    public static IVsDataConnection Connection
    {
        get
        {
            if (Host is IServiceProvider service)
            {
                if (service.GetService(typeof(EnvDTE.DTE)) is Interop.IServiceProvider provider)
                {
                    if (PackageUtilities.QueryService<IVsDataExplorerConnectionManager>(provider) is IVsDataExplorerConnectionManager manager)
                    {
                        return manager.Connections[connectionKey].Connection;
                    }
                    throw new InvalidOperationException("Unable to resolve IVsDataExplorerConnectionManager!");
                }
                throw new InvalidOperationException("Unable to resolve DTE as Interop.IServiceProvider!");
            }
            throw new Exception("Host property returned unexpected value (null)");
        }
    }
}
#>

上記を含むテストコード

<#@ template hostspecific="true" language="C#" #>
<#@ include file="Settings.ttinclude" #>
<#
    Settings.Host = Host;
#>

using Microsoft.Extensions.DependencyInjection;
using SubSonic;
using System;

namespace $rootnamespace$
{
    public partial class $safeitemrootname$
        : SubSonicContext
    {
        private readonly IServiceCollection services = null;

        public $safeitemrootname$(IServiceCollection services)
        {
            this.services = services ?? throw new ArgumentNullException(nameof(services));
        }

        public string ConnectionString => "<#= Settings.Connection.DisplayConnectionString #>";

        #region ISubSonicSetCollection{TEntity} Collection Properties
        #endregion
    }
}
4

1 に答える 1