How to apply VS2010 web.config transformation to a

2019-04-21 07:18发布

问题:

I'd like to use the new VS2010 web.config transformation feature to change the connection string within the nhibernate configuration in my web.config file. The relevant snippet is something like this:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
  </configSections>

  <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
      <property name="connection.driver_class">NHibernate.Driver.OracleDataClientDriver</property>
      <property name="connection.connection_string">(test connection string)</property>
      <property name="proxyfactory.factory_class">NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
...

I've tried the following transformation without success:

<?xml version="1.0"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
    <hibernate-configuration  xmlns="urn:nhibernate-configuration-2.2" >
        <session-factory>
            <property name="connection.connection_string" xdt:Transform="Replace">(production connection string)</property>
        </session-factory>
    </hibernate-configuration>
</configuration>

The problem seems to be in the xmlns attribute of the nhibernate-configuration element.

What should be the correct transformation to replace (test connection string) with (production connection string) during deployment?

回答1:

The answer may be a bit late, but since I needed this as well, I figured I would post an answer that worked for me in the event anyone else stumbles upon this question.

You need to use the xdt:Locator in combination with an xpath expression to get the correct node. So something like this should work.

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
   <session-factory>
      <property name="connection.connection_string" xdt:Locator="XPath(//*[local-name()='hibernate-configuration']//*[local-name()='property'][@name='connection.connection_string'])" xdt:Transform="Replace">(production connection string)</property>
   </session-factory>
</hibernate-configuration>

There may be a better xpath expression, but this is what worked for me.

The only issue, which isn't that big a deal, is the replaced node will have a namespace redeclared on the node. So the replaced node will actually look like this in the final output.

<property name="connection.connection_string" xmlns="urn:nhibernate-configuration-2.2">(production connection string)</property>


回答2:

I recently encountered the same issue - it was solved by placing explicit namespace prefixes in the transform file

<configuration
               xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform"
               xmlns:hib="urn:nhibernate-configuration-2.2"
              >
    <hib:hibernate-configuration>
        <hib:session-factory>
            <hib:property name="connection.connection_string" xdt:Transform="Replace">(production connection string)</hib:property>
        </hib:session-factory>
    </hib:hibernate-configuration>
</configuration>

The resulting transformed web.config file was thankfully free of the namespace prefixes (i.e. it left the nhibernate namespace declaration in the same spot as it was in the original web.config file and correctly named all the nodes)



回答3:

If all you are trying to do is transform the connection string, do not use the transformation mechanism. Instead, in your web.config or app.config, reference this property

connection.connection_string_name

instead of this one:

connection.connection_string

This allows you to reference the connection string defined in the ConnectionStrings section, which is transformed in the usual way.

eg in web.config, use this code:

<connectionStrings>
  <add name="DefaultConnection" connectionString="server=MYSERVER; Integrated Security=SSPI; database=MYDATABASE"/>
</connectionStrings>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
  <session-factory>
    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
    <property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
    <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
    <property name="connection.connection_string_name">DefaultConnection</property>
    <property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
    <property name="current_session_context_class">web</property>
    <property name="show_sql">true</property>
  </session-factory>
</hibernate-configuration>


回答4:

Since session-factory contains a collection of child elements, you need to tell it which child to replace using the Match locator.

<?xml version="1.0"?>
    <configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
        <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
            <session-factory>
                <property name="connection.connection_string" xdt:Transform="Replace" xdt:Locator="Match(name)>(production connection string)</property>
            </session-factory>
        </hibernate-configuration>
    </configuration>