2008-10-25 11 views
28

Tengo una aplicación web que comprende lo siguiente:Cadena de conexión demonios en .NET/LINQ-SQL/ASP.NET

  • 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 un app.config - ambos tienen cadenas de conexión)

Cuando construyo e implemento, no hay ningún archivo de configuración o app.con fig en el directorio Bin con el .dll de acceso a datos, 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 el dll de acceso a datos.

Lo que necesito es un archivo de configuración para toda mi implementación - sitio web, acceso a datos dlls, todo - que tiene una cadena de conexión que se usa. Por el momento, parece haber varias cadenas de conexión que se usan o se codifican en todas partes.

¿Cómo puedo resolver este problema?

Gracias por cualquier ayuda.

+0

Parece ser un error en LINQ to SQL, trabajé mucho en LINQ a las entidades y esta es la primera vez que estoy trabajando con LINQ to SQL y frente a este problema por primera vez. –

Respuesta

14

Nunca he tenido un problema con Data Access Layer (DAL) pudiendo utilizar las cadenas de conexión de mi archivo web.config. Usualmente solo copio la sección de cadenas de conexión del DAL y lo pego en el web.config. Estoy usando el diseñador de 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 sus cadenas de conexión, y cuando cree su objeto DAL (o contexto de datos, si lo está creando 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)) 
{ 
    ... 
} 
+0

+1, funciona para mí. –

+3

Ah, me acabo de dar cuenta de que DAL = Data Access Layer. Nosotros, los novatos, somos un poco lentos con la sintaxis. –

+0

Lo siento por ser estúpido, pero ¿dónde pongo esta clase en el proyecto de la aplicación web o en el proyecto de acceso a datos? ¿Y tienes alguna idea sobre cómo reemplazar el constructor predeterminado DALDataContext() por defecto a la cadena en el web.config? Gracias – Kieran

0

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

6

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

1

Aquí hay una manera 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 dev, QA, UAT y prod, la gestión de estas cadenas de conexión es crucial.

Si el sitio web decide, debe pasar la cadena de conexión de su web.config a DAL. Si se supone que el sitio web no debe saber ni importar de dónde provienen los datos, la cadena de conexión debe pertenecer al DAL.

0

También podría hacer que la aplicación web proporcione la cadena de conexión cuando necesite utilizar el proyecto de acceso a datos. Podrías 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.

3

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

En el configSections paret 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 que poner las entradas para cada DLL:

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

En un mundo perfecto, creo que sería refactorizar su capa de datos para recoger configuraciones a través de System.Configuration o constructores/fábricas relevantes. Lo que significa que necesita 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 este tipo de constantes es arrojar una propiedad readonly en una clase de helper estática y hacer que esa clase administre la resolución real de las configuraciones, etc.

Un lugar que puede ver que creo muestra buenos ejemplos de cómo para hacer esto de forma elegante es NHibernate y su gestión de configuración/mapeos. De acuerdo, es un poco de xml hell, y Fluent NHib es más dulce, pero la mayoría de las muestras del mundo real le mostrarán cómo conciliar la configuración de un ensamblaje de soporte con el ensamblaje en ejecución.

0

rodar su propia ConnectionFactory basado en archivos .config:

  • definir una sección de configuración personalizada para asignar pares de claves/connectionString
  • Enseñe a su ConnectionFactory para olfatear en esa sección de configuración utilizando el nombre de host o Machinename según corresponda
  • Complete los valores de clave/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
  • Adición de destino del despliegue adicional es una operación de copiar/pegar en una.archivo de configuración

contra:

  • Hace para grandes secciones XML feos, especialmente si usted tiene una docena de servidores de producción
  • necesita ser duplicada entre los proyectos
  • cambian las necesidades de código & Redesplegar añadir nuevo objetivo
  • El código necesita saber sobre el entorno en el que vivirá
5

rodar su propia ConnectionFactory basa en el Registro:

  • agregar una clave de registro para su aplicación bajo SOFTWARE/[your_company]/[YOUR_APP]
  • añadir un valor de cadena para ConnectionString
  • Enséñele a su ConnectionFactory para abrir la clave de registro adecuada (en un constructor estático, ¡no en todas las páginas cargadas!).
  • exportar la información de 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:

  • fácil de configurar
  • connectionString vive en un solo lugar
  • No
  • en web/app.config, por lo que no hay necesidad de codificar los ajustes específicos del entorno.
  • No
  • en web/app.config, así junior Dev Jimmy no puede decir accidentalmente el servidor de producción para mirar a la base de datos DEV

contra:

  • No es inmediatamente obvio que las cosas son importantes viviendo en el registro, por lo que los nuevos desarrolladores necesitarán instrucciones.
  • Paso adicional al configurar una nueva máquina de despliegue
  • El registro es oldskool. Los desarrolladores Junior se burlarán de ti.
+0

@Jason: felicitaciones por enviar 2 respuestas. Bien pensado pros y contras. Un desafortunado Con sería 'no web hosting' amigable. –

+0

hasta vote por la palabra old school -desde Junior Dev Jimmy – Kieran

4

Gracias por las respuestas.

Aquellos de ustedes que dicen que la aplicación va a utilizar la configuración en el web.config son correctos para casos en los que hacen referencia a él en mi propio código:

_connectionString = ConfigurationManager.AppSettings["ConnectionString"]; 

..pero hay un problema diferente con LINQ -SQL datacontexts: 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 un enredo :)

+0

Sí, el datacontext incluirá ConnectionString como un retroceso si todas las otras formas de encontrar un ConnectionString con el nombre correcto fallan - siempre puede instatar el contexto usando el constructor eso toma una cadena de conexión como un parámetro. –

3

Tuve un poco de lucha con este problema también. Encontré una solución usando la definición de clase parcial C# y ampliando el contexto de datos creado por dbml designer. Esta solución es bastante similar a la respuesta de tvanfosson.Lo que tiene que hacer es crear una clase de contexto de datos parcial con el constructor predeterminado que obtiene ConnectionString de la configuración y en las propiedades de DC del diseñador de dbml establecer la conexión a Ninguno. De esa manera, 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 conexión web.config connectionstring. No he probado si esto funciona con app.config también, pero creo que debería funcionar bien.

Aquí es muestra de clase parcial DC:

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

¿No agrega ese constructor que causa un problema de compilación, ya que la clase parcial generada por el diseñador ya tiene el mismo constructor? –

+0

Eso es correcto, dependiendo de las propiedades de diseñador que elija (sección Conexión), el código generado podría crear un constructor sin parámetros. –

+0

Esta es mi solución preferida. Establecer la conexión a "Ninguno" en el diseñador como lo menciona Hihu evitará que el constructor sin parámetros se genere automáticamente, por lo que no hay problema de compilación. Una solución similar, con detalles más elaborados, se describe [aquí] (http://stackoverflow.com/questions/5139043/point-connectionstring-in-dbml-to-app-config). – Mac

2

para mantenerlo a salvo de cualquier cosa en el auto código generado, anulan 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 forma, el diseñador de dbml puede hacer las cosas de la conexión (lo que no es agradable fuera de un proyecto web), pero usted toma el control final de la conexión cuando se ejecuta la aplicación.

0

Sé que esto es viejo, pero así es como lo hago (me gusta bastante @ manera de Seba, pero no he probado eso)

Esto asume su archivo DBML reside en su propia biblioteca de clases, que he Lo encontré más conveniente cuando compartimos entidades y acceso a datos a través de múltiples sitios web y otras bibliotecas de clases. También asume que ha nombrado la cadena de conexión igual en cada proyecto. Uso NAnt para configurar esto cuando implemento en diferentes entornos.

Basé esto en la respuesta superior anterior de @tvanfosson - kudos 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. abrir su archivo DBML, y en las Propiedades, agregue la clase anterior nombre a la propiedad de la Clase Base.

Nota: si colocó la clase de contexto de datos personalizada en el mismo ensamblado, simplemente incluya el nombre de clase, p. Ej. CustomDataContext.

Si se encuentran en diferentes conjuntos, utilice el nombre completo, p. MyCo.MyApp.Data.CustomDataContext

  1. Para garantizar la materia del diseñador funciona correctamente, copiar la cadena de conexión en el archivo app.config para la biblioteca de clases. Esto no se usará aparte en el IDE.

Eso es todo.

Tendrá que nombrar la cadena de conexión del mismo

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

HTH

Cuestiones relacionadas