Pregunta

Tengo una aplicación web que comprende lo siguiente:

  • Un proyecto web (con un archivo web.config que contiene una cadena de conexión, pero sin código de acceso a datos en el proyecto web)
  • Un proyecto de acceso a datos que utiliza clases LINQ-SQL para proporcionar entidades a la interfaz de usuario del proyecto web (este proyecto tiene un archivo de configuración y una aplicación.config, ambos con cadenas de conexión)

Cuando construyo y despliego, no hay un archivo de configuración o app.config en el directorio Bin con el acceso a datos .dll, pero cambiar la cadena de conexión en el archivo web.config no cambia la base de datos en consecuencia, por lo que la cadena de conexión debe compilarse en la dll de acceso a datos.

Lo que necesito es un archivo de configuración para toda mi implementación (sitio web, dlls de acceso a datos, todo) que tenga una cadena de conexión que se use. En este momento parece haber múltiples cadenas de conexión que se utilizan o codifican en todo el lugar.

¿Cómo resuelvo mejor este desastre?

Gracias por cualquier ayuda.

¿Fue útil?

Solución

Nunca he tenido un problema con la Capa de acceso a datos (DAL) que puede usar las cadenas de conexión de mi archivo web.config . Por lo general, solo copio la sección de cadenas de conexión del DAL y la pego en el web.config . Estoy usando el diseñador DBML para crear el contexto de datos.

Si esto no funciona para usted, puede especificar la cadena de conexión en el constructor de contexto de datos. En su proyecto web, tenga una clase estática que cargue su configuración, incluidas las cadenas de conexión, y cuando cree su objeto DAL (o contexto de datos, si lo crea directamente) simplemente páselo al constructor.

public static class GlobalSettings
{
    private static string dalConnectionString;
    public static string DALConnectionString
    {
       get
       {
           if (dalConnectionString == null)
           {
              dalConnectionString = WebConfigurationManager
                                      .ConnectionStrings["DALConnectionString"]
                                        .ConnectionString;
           }
           return dalConnectionString;
       }
    }
}
...

using (var context = new DALDataContext(GlobalSettings.DALConnectionString))
{
   ...
}

Otros consejos

El archivo de configuración para el proyecto de inicio definirá los ajustes de configuración para todos los proyectos incluidos. Por ejemplo, si su proyecto web es el proyecto de inicio, cualquier referencia a " appSettings " buscará la configuración de web.config, esto incluye cualquier referencia a " appSettings " de su proyecto de acceso a datos. Por lo tanto, copie cualquier configuración de configuración de la aplicación.config del proyecto de acceso a datos en la web.config del proyecto web.

Roll su propia ConnectionFactory basada en el Registro:

  • agregue una clave de registro para su aplicación en SOFTWARE / [YOUR_COMPANY] / [YOUR_APP]
  • agregar un valor de cadena para ConnectionString
  • Enseñe a su ConnectionFactory a abrir la clave de registro adecuada (en un constructor estático, ¡no cada carga de página!).
  • exporte la información del registro como un archivo .reg, agréguelo al control de origen, modifíquelo y aplíquelo según sea necesario para configurar máquinas adicionales.

Pro:

  • Simple de configurar
  • La cadena de conexión vive en un solo lugar
  • No en web / app.config, por lo que no es necesario codificar configuraciones específicas del entorno.
  • No en web / app.config, por lo que Junior Dev Jimmy no puede decirle accidentalmente a su servidor de producción que mire la base de datos DEV

Con:

  • No es obvio de inmediato que haya cosas importantes en el registro, por lo que los nuevos desarrolladores necesitarán instrucciones.
  • Paso adicional al configurar una nueva máquina de implementación
  • El registro es oldskool. Los desarrolladores junior se burlarán de ti.

Gracias por las respuestas.

Aquellos de ustedes que dicen que la aplicación usará la configuración en web.config son correctos para las instancias en las que la referencia en mi propio código:

_connectionString = ConfigurationManager.AppSettings["ConnectionString"];

... pero hay un problema diferente con los contextos de datos LINQ-SQL: creo que incluyen cadenas de conexiones en el dll compilado para usar en el constructor sin parámetros. Como dice tvanofosson, necesito crear contextos de datos pasando una referencia a la cadena de conexión en web.config. Que es donde me estaba metiendo en una maraña :)

También tuve problemas con este problema. Encontré una solución usando la definición de clase parcial de c # y extendiendo el contexto de datos creado por el diseñador dbml. Esta solución es bastante similar a la respuesta de tvanfosson. Lo que debe hacer es crear una clase de contexto de datos parcial con el constructor predeterminado obteniendo ConnectionString de la configuración y en las propiedades de DC del diseñador de dbml establezca la conexión en Ninguno. De esa forma, la cadena de conexión no se compilará en dll. Datacontext obtendrá automáticamente la cadena de conexión de la configuración de la cadena de conexiones web.config. No he probado si esto también funciona con app.config, pero creo que debería funcionar bien.

Aquí hay una muestra de la clase DC parcial:

namespace MyApplication {
    /// <summary>
    /// Summary description for MyDataContext
    /// </summary>
    /// 
    public partial class MyDataContext
    {
        public MyDataContext() :
            base(global::System.Configuration.ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString, mappingSource)
        {
            OnCreated();
        }
    }
}

Su aplicación solo usará las entradas de configuración en el archivo web.config. Puede poner la configuración dll config en el archivo web.config siempre que estén estructurados correctamente. Mi ejemplo es específico de VB usando My Namespace, pero le da una idea general.

En el par de configSections del archivo de configuración, necesitará una entrada:

<configSections>
    <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
        <section name="YourAssembly.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    </sectionGroup></configSections>

Luego, en la parte ApplicationSettings del archivo de configuración, coloca las entradas para cada dll:

    <applicationSettings>
      <YourAssembly.My.MySettings>
        <setting name="DebugMode" serializeAs="String">
            <value>False</value>
        </setting>
      </YourAssembly.My.MySettings>
    </applicationSettings>  

Para mantenerlo a salvo de cualquier cosa en el código generado automáticamente, anule la información de conexión en el método OnCreated () del contexto de datos:

using System.Configuration;
namespace MyApplication 
{
    partial void OnCreated()
    {
        // attempt to use named connection string from the calling config file
        var conn = ConfigurationManager.ConnectionStrings["MyConnectionString"];
        if (conn != null) Connection.ConnectionString = conn.ConnectionString;
    }
}

De esta manera, el diseñador de dbml puede hacer cosas de conexión a su manera (lo que no es bueno fuera de un proyecto web), pero usted toma el control final de la conexión cuando se ejecuta la aplicación.

Aquí hay una forma de verlo. ¿Qué componente debe tomar la decisión sobre qué base de datos usar? Es posible que la base de datos (o al menos la cadena de conexión) pueda cambiar en el futuro. ¿El sitio web decide qué base de datos usar? O, ¿decide el DAL?

Si tiene bases de datos de desarrollo, control de calidad, UAT y producción, la gestión de estas cadenas de conexión es crucial.

Si el sitio web decide, debe pasar la cadena de conexión desde su web.config al DAL. Si se supone que el sitio web no sabe ni le importa de dónde provienen los datos, entonces la cadena de conexión pertenece al DAL.

¿Qué hay de definir un objeto ConnectionFactory, que toma una enumeración como parámetro y devuelve un objeto de conexión completamente formado?

También puede hacer que la aplicación web proporcione la cadena de conexión cuando necesite usar el proyecto de acceso a datos. Podría hacerlo parte del constructor.

Además, podría escribir su propia lógica para cargar una cadena de conexión desde un archivo externo cuando el proyecto de acceso a datos realiza sus llamadas.

En un mundo perfecto, creo que refactorizaría su capa de datos para recoger los ajustes de configuración a través de System.Configuration o constructores / fábricas relevantes. Es decir, debe volver a cablear su fuente de configuración implícita o establecer conexiones explícitamente desde su host / consumidor. Otro patrón relacionado para centralizar estos tipos de constantes es lanzar una propiedad de solo lectura en una clase auxiliar estática y hacer que esa clase administre la resolución real desde las configuraciones, etc.

Un lugar donde puedes mirar que creo que muestra buenos ejemplos de cómo hacer esto con elegancia es NHibernate y su configuración / gestión de mapeos. De acuerdo, es un poco un infierno xml, y NHib Fluent es más azucarado, pero la mayoría de las muestras del mundo real le mostrarán cómo conciliar la configuración de un conjunto de soporte frente al conjunto de ejecución.

Roll su propia ConnectionFactory basada en archivos .config:

  • Defina una sección de configuración personalizada para asignar pares de clave / cadena de conexiones
  • Enseñe a su ConnectionFactory a rastrear esa sección de configuración utilizando el nombre de host o el nombre de máquina según corresponda
  • Rellene valores de clave / cadena de conexión para sus diversos servidores dev / qa / prod, y colóquelos en sus diversos archivos app.config, web.config, etc.

Pro:

  • Todas las vidas dentro del proyecto, por lo que no hay sorpresas
  • Agregar un destino de implementación adicional es una operación de copiar / pegar en un archivo .config

Con:

  • Crea grandes secciones XML feas, especialmente si tiene una docena de servidores de producción
  • Debe duplicarse entre proyectos
  • Necesita cambio de código & amp; volver a implementar para agregar un nuevo objetivo
  • Code necesita saber sobre el entorno en el que vivirá

Sé que esto es viejo, pero así es como lo hago (me gusta bastante la forma de @ Seba pero no lo he intentado)

Esto supone que su archivo DBML reside en su propia biblioteca de clases, lo que me parece más conveniente cuando comparte entidades y acceso a datos a través de múltiples sitios web y otras bibliotecas de clases. También supone que ha nombrado su cadena de conexión de la misma manera en cada proyecto. Uso NAnt para configurar esto cuando lo implemento en diferentes entornos.

Basé esto en la respuesta superior de @tvanfosson: felicitaciones a ese tipo.

  1. Cree su propia clase base, que se deriva de LinqDataContext

Aquí está el código VB:

    Imports System.Configuration

Public Class CustomDataContextBase
    Inherits System.Data.Linq.DataContext
    Implements IDisposable

    Private Shared overrideConnectionString As String

    Public Shared ReadOnly Property CustomConnectionString As String
        Get
            If String.IsNullOrEmpty(overrideConnectionString) Then
                overrideConnectionString = ConfigurationManager.ConnectionStrings("MyAppConnectionString").ConnectionString
            End If

            Return overrideConnectionString
        End Get
    End Property

    Public Sub New()
        MyBase.New(CustomConnectionString)
    End Sub

    Public Sub New(ByVal connectionString As String)
        MyBase.New(CustomConnectionString)
    End Sub

    Public Sub New(ByVal connectionString As String, ByVal mappingSource As System.Data.Linq.Mapping.MappingSource)
        MyBase.New(CustomConnectionString, mappingSource)
    End Sub

    Public Sub New(ByVal connection As IDbConnection, ByVal mappingSource As System.Data.Linq.Mapping.MappingSource)
        MyBase.New(CustomConnectionString, mappingSource)
    End Sub

End Class
  1. Abra su archivo DBML y, en las Propiedades, agregue el nombre de la clase anterior a la propiedad Clase base.

Tenga en cuenta que si colocó la clase de contexto de datos personalizados en el mismo ensamblaje, simplemente incluya el nombre de la clase, p. CustomDataContext.

Si están en ensamblajes diferentes, use el nombre completo, p. MyCo.MyApp.Data.CustomDataContext

  1. Para asegurarse de que las cosas de Designer funcionan correctamente, copie su cadena de conexión en el archivo app.config para la biblioteca de clases. Esto no se utilizará aparte de en el IDE.

Eso es todo.

Tendrá que nombrar su cadena de conexión de la misma manera

Lo que esencialmente está haciendo es forzar el contexto de datos a ignorar la información de conexión establecida en el archivo DBML. El uso de los métodos de ConfigurationManager significará que recogerá la cadena de conexión del conjunto de llamada.

HTH

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top