0

Scenario: I want to dynamically choose the connection string based on the environment that the application is running in.

Environment: I have a two environments Dev and Production for a WCF Service. I store the connection strings in the web.config. When that app starts up set a variable with the correct connection string to use.

Problem: When the data model is generated it creates 2 files dmMyDataModel.edmx and dmMyDataModel.Designer.cs, in the designer file there are constructors in there that define the connection to the EntityDatabas.

In the code below you can see that I have created a constructor in the service that when the service is called it will set the context to use the right connection string. But only the items that use myContext work correctly (the stored procedures) the querying of the dbMyWebSiteEntities fail in production environment because the still depend on the connection string set in the designer.

I tired setting the logic in the designer but that get wiped out when its re-generated.

dmMyDataModel.Designer.cs

using System;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Data.EntityClient;
using System.ComponentModel;
using System.Xml.Serialization;
using System.Runtime.Serialization;

[assembly: EdmSchemaAttribute()]

namespace MyWebSite.Services
{
    #region Contexts

    /// <summary>
    /// No Metadata Documentation available.
    /// </summary>
    public partial class dbMyWebSiteEntities : ObjectContext
    {
        #region Constructors

        /// <summary>
        /// Initializes a new dbMyWebSiteEntities object using the connection string found in the 'dbMyWebSiteEntities' section of the application configuration file.
        /// </summary>
        public dbMyWebSiteEntities() : base("name=dbMyWebSiteEntities", "dbMyWebSiteEntities")
        {
            this.ContextOptions.LazyLoadingEnabled = true;
            OnContextCreated();
        }

        /// <summary>
        /// Initialize a new dbMyWebSiteEntities object.
        /// </summary>
        public dbMyWebSiteEntities(string connectionString) : base(connectionString, "dbMyWebSiteEntities")
        {
            this.ContextOptions.LazyLoadingEnabled = true;
            OnContextCreated();
        }
        /// <summary>
        /// Initialize a new dbMyWebSiteEntities object.
        /// </summary>
        public dbMyWebSiteEntities(EntityConnection connection) : base(connection, "dbMyWebSiteEntities")
        {
            this.ContextOptions.LazyLoadingEnabled = true;
            OnContextCreated();
        }

        #endregion
        ...
    }

MyWebSiteData.svc.cs

using System;
using System.Collections.Generic;
using System.Data.Services;
using System.Data.Services.Common;
using System.Linq;
using System.ServiceModel.Web;
using System.Web;
using System.ServiceModel.Activation;
using System.ServiceModel;
using System.Data.EntityClient;
using System.Configuration;
using System.Data.Objects;

namespace MyWebSite.Services
{
    public class MyWebSiteData : DataService<dbMyWebSiteEntities>
    {
        private dbMyWebSiteEntities myContext;

        public static void InitializeService(DataServiceConfiguration config)
        {
            config.UseVerboseErrors = true; 
            config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V2;
            config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
            config.SetEntitySetPageSize("*", 25);

            config.SetServiceOperationAccessRule("mar_getAllByKey", ServiceOperationRights.AllRead);
        }

        //Constructor to override the connection string used in the dmMyDataModel.Designer.cs
        public MyWebSiteData()
        {
            //sets the connetion string and appends the environment so it will pull the correct one from the web.config
            EntityConnection conn = new EntityConnection("name=dbMyWebSiteEntities" + HttpContext.Current.Application["Environment"]);
            myContext = new dbMyWebSiteEntities(conn);
        }

        //This returns the data from the stored procedures
        [WebGet]
        public ObjectResult<myTable> mar_getAllByKey(string key)
        {
            return myContext.mar_getAllByKey(key);
        }
    }
}

Thanks for taking the time to look at this. I have tried to be specific and detailed but if I left something out let me know.

Thanks, Gerald

Gerald
  • 1
  • 1

3 Answers3

4

The generated class is partial. If you want to add new constructors define another partial class (the same class name and namespace) is a different file and add your constructors there. Your file won't be regenerated. That's what partial keyword is for.

Your new constructor has to be unique - different parameters.

You can also define a static factory method in your partial class which will encapsulate the logic of instantiation.

I set different connection strings in .config files using Xml Transformations for each environment I have (Dev / Test / Beta / Prod).

Jakub Konecki
  • 45,581
  • 7
  • 87
  • 126
  • Is Brain's example bellow what your talking about "static factory method"? Sorry I still wrapping my head around OOP. – Gerald Mar 16 '11 at 22:47
0

Best way is to create a wrapper:

public static class DBContextCreator
{
   public static MyDBContext Create()
   {
        return new MyDBContext(/* pass in connection of choice here */);
   }
}

In this wrapper you can handle the varying logic through a variety of ways.

HTH.

Brian Mains
  • 50,520
  • 35
  • 148
  • 257
  • Hi Brian. This creates a new context. When the service is started up it creates a context out of the generated designer, this is the one that I would like to be able to change the connection string of. When I do like you have suggested above it creates a new instance and will only use the right connection string when that new context is used. – Gerald Mar 16 '11 at 22:40
  • You cannot change a connection string; the connection has to be established when you create the object context, and it cannot be changed after that. TO change it means reinstantiating the context. If you have any LINQ objects, you must detach them from the existing context and re-attach them to the new context too. – Brian Mains Mar 17 '11 at 16:20
0

You can find the similar query in the over here

It gives example of using EntityConnectionStringBuilder class in namespace System.Data.Common.DbConnectionStringBuilder

Community
  • 1
  • 1
Milan Raval
  • 1,880
  • 1
  • 16
  • 33