我编写了一个T4模板,我在其中实例化一个EF上下文来读取一些数据。 问题是上下文无法从Web.config中看到连接字符串。
如何使Web.config的连接字符串可用于模板?
更多信息:
尝试了下面的一些解决方案(谢谢),但我明白了:
Error 2 Compiling transformation: 'Microsoft.VisualStudio.TextTemplating12165CB53B43A726CBA54A29800255D257AAFD4D5F0DACE4DFE5872F2DEC7739EDF358F49C0444A912B851939903A79BC6180FCEB3FD0D1BF8C0093741DDDACA.GeneratedTextTransformation' does not contain a definition for 'Host' and no extension method 'Host' accepting a first argument of type 'Microsoft.VisualStudio.TextTemplating12165CB53B43A726CBA54A29800255D257AAFD4D5F0DACE4DFE5872F2DEC7739EDF358F49C0444A912B851939903A79BC6180FCEB3FD0D1BF8C0093741DDDACA.GeneratedTextTransformation' could be found (are you missing a using directive or an assembly reference?)
我声明了以下内容:
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
如果我包含Microsoft.VisualStudio.TextTemplating的程序集,它会告诉我它已经插入。
另外,有没有什么方法可以让ConfigurationManager对DbContext可用,这样他就可以在没有我传递连接字符串的情况下在幕后阅读?
解决了,再次感谢:
<#@ template hostspecific="true" language="C#" debug="false" #>
<#@ assembly name="System.Core.dll" #>
<#@ assembly name="System.Configuration" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#@ import namespace="System.Configuration" #>
var map = new ExeConfigurationFileMap();
map.ExeConfigFilename = this.Host.ResolvePath(@"..\Web.config");
var config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
var connectionString = config.ConnectionStrings.ConnectionStrings["MyConnectionName"].ConnectionString;
答案 0 :(得分:7)
我从下一个方式从T4模板访问App.config中的连接字符串:
<#@ template debug="false" hostspecific="true" language="C#" #>
ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap(this.Host.ResolvePath(@"..\ProjName\App.config"));
configFileMap.ExeConfigFilename = this.Host.ResolvePath(@"..\ProjName\App.config");
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
string connectionString = config.ConnectionStrings.ConnectionStrings[0].ConnectionString;
答案 1 :(得分:5)
Injecting Your Web.Config Connection String Into Your T4 Template为您提供了一个T4模板,可以从web.config和app.config中读取连接字符串。我基于它创建了自定义版本,这为我节省了很多时间。
<#@ assembly name="System.Configuration" #> <#@ assembly name="EnvDTE" #> <#@ assembly name="System.Core.dll" #> <#@ import namespace="System" #> <#@ import namespace="System.Configuration" #> <#@ import namespace="System.Text.RegularExpressions" #> <#+ /// <summary> /// Provides strongly typed access to the hosting EnvDTE.Project and app.config/web.config /// configuration file, if present. /// /// Typical usage from T4 template: /// <code>ConfigurationAccessor config = new ConfigurationAccessor((IServiceProvider)this.Host);</code> /// /// </summary> /// <author>Sky Sanders [sky.sanders@gmail.com, http://skysanders.net/subtext]</author> /// <date>01-23-10</date> /// <copyright>The contents of this file are a Public Domain Dedication.</copyright> /// /// TODO: determine behaviour of ProjectItem.FileNames when referred to a linked file. /// public class ConfigurationAccessor { /// <summary> /// Typical usage from T4 template: /// <code>ConfigurationAccessor config = new ConfigurationAccessor((IServiceProvider)this.Host);</code> /// </summary> public ConfigurationAccessor(IServiceProvider host) : this(host, null) { } /// <summary> /// Same as default constructor but it looks for a web.config/app.config in the passed config /// project location and not in the first startup project it finds. The configProjectLocation /// passed should be relative to the solution file. /// </summary> public ConfigurationAccessor(IServiceProvider host, string configProjectLocation) { // Get the instance of Visual Studio that is hosting the calling file EnvDTE.DTE env = (EnvDTE.DTE)host.GetService(typeof(EnvDTE.DTE)); // Initialize configuration filename string configurationFilename=null; // Gets an array of currently selected projects. Since you are either in this file saving it or // right-clicking the item in solution explorer to invoke the context menu it stands to reason // that there is 1 ActiveSolutionProject and that it is the parent of this file.... _project = (EnvDTE.Project)((Array)env.ActiveSolutionProjects).GetValue(0); // Try and find the configuration file in the active solution project configurationFilename = FindConfigurationFilename(_project); // If we didn't find the configuration file, check the startup project or passed config // project location in the constructor if (configurationFilename == null) { // We are going to get the first *STARTUP* project in the solution // Our startup projects should also have a valid web.config/app.config, however, // if for some reason we have more than one startup project in the solution, this // will just grab the first one it finds // // We can also supply a config project location to look for in the constructor. This solves // the problem in the case where we have multiple startup projects and this file is not // in the first, or the config file is not in either the startup project or the active solution // project. if (!string.IsNullOrEmpty(configProjectLocation)) { _project = (EnvDTE.Project)env.Solution.Projects.Item(configProjectLocation); } else { foreach (String s in (Array)env.Solution.SolutionBuild.StartupProjects) { _project = (EnvDTE.Project)env.Solution.Projects.Item(s); break; } } // Try and find the configuration file in one of the projects we found configurationFilename = FindConfigurationFilename(_project); } // Return the configuration object if we have a configuration file name // If we do not have a configuration file name, throw an exception if(!string.IsNullOrEmpty(configurationFilename)) { // found it, map it and expose salient members as properties ExeConfigurationFileMap configFile = null; configFile = new ExeConfigurationFileMap(); configFile.ExeConfigFilename=configurationFilename; _configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None); } else { throw new ArgumentException("Unable to find a configuration file (web.config/app.config). If the config file is located in a different project, you must mark that project as either the Startup Project or pass the project location of the config file relative to the solution file."); } } /// <summary> /// Finds a web.config/app.config file in the passed project and returns the file name. /// If none are found, returns null. /// </summary> private string FindConfigurationFilename(EnvDTE.Project project) { // examine each project item's filename looking for app.config or web.config foreach (EnvDTE.ProjectItem item in project.ProjectItems) { if (Regex.IsMatch(item.Name,"(app|web).config",RegexOptions.IgnoreCase)) { // TODO: try this with linked files. is the filename pointing to the source? return item.get_FileNames(0); } } // not found, return null return null; } private EnvDTE.Project _project; private System.Configuration.Configuration _configuration; /// <summary> /// Provides access to the host project. /// </summary> /// <remarks>see http://msdn.microsoft.com/en-us/library/envdte.project.aspx</remarks> public EnvDTE.Project Project { get { return _project; } } /// <summary> /// Convenience getter for Project.Properties. /// Examples: /// <code>string thisAssemblyName = config.Properties.Item("AssemblyName").Value.ToString();</code> /// <code>string thisAssemblyName = config.Properties.Item("AssemblyName").Value.ToString();</code> /// </summary> /// <remarks>see http://msdn.microsoft.com/en-us/library/envdte.project_properties.aspx</remarks> public EnvDTE.Properties Properties { get { return _project.Properties;} } /// <summary> /// Provides access to the application/web configuration file. /// </summary> /// <remarks>see http://msdn.microsoft.com/en-us/library/system.configuration.configuration.aspx</remarks> public System.Configuration.Configuration Configuration { get { return _configuration; } } /// <summary> /// Provides access to the appSettings section of the configuration file. /// Behavior differs from typical AppSettings usage in that the indexed /// item's .Value must be explicitly addressed. /// <code>string setting = config.AppSettings["MyAppSetting"].Value;</code> /// </summary> /// <remarks>see http://msdn.microsoft.com/en-us/library/system.configuration.configuration.appsettings.aspx</remarks> public KeyValueConfigurationCollection AppSettings { get { return _configuration.AppSettings.Settings;} } /// <summary> /// Provides access to the connectionStrings section of the configuration file. /// Behavior is as expected; items are accessed by string key or integer index. /// <code>string northwindProvider = config.ConnectionStrings["northwind"].ProviderName;</code> /// </summary> /// <remarks>see http://msdn.microsoft.com/en-us/library/system.configuration.configuration.connectionstrings.aspx</remarks> public ConnectionStringSettingsCollection ConnectionStrings { get { return _configuration.ConnectionStrings.ConnectionStrings;} } } #>
答案 2 :(得分:0)
如果任何人都需要解析Web.config文件的绝对路径(例如,包含一个.tt文件,并且该文件从不同相对路径中的多个其他.tt文件中使用):
<#@ template debug="true" hostspecific="true" language="C#" #>
<#@ assembly name="EnvDTE" #>
<#@ Assembly Name="System.Configuration" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Configuration" #>
<#+
string GetConnectionString()
{
var map = new ExeConfigurationFileMap();
var configPath = Path.Combine(
Host.ResolveAssemblyReference("$(SolutionDir)"), "WwwFolderInSolution", "Web.config");
map.ExeConfigFilename = configPath;
var config = ConfigurationManager.
OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);
return config.ConnectionStrings.ConnectionStrings["MyConnectionString"].ConnectionString;
}
#>