I had first created a web application in VB.Net. Now i am creating its mobile application using Ionic framework. Language is c#.
In web application i use to get the connection string from Registry add save it in a session. I used to do it in global.asax.
global.asax:
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
Dim mDBConnector As String = String.Empty
With Application
.Add("ProductRegistryKey", "Accord 2.0")
.Add("ProductGUID", "ea3asue4n43-mbk3-3nmn-n34n4h3j4n4n3")
.Add("ProductId", "1")
mDBConnector = WebHelper.GetDBConnector(Application.Item("ProductRegistryKey")
End With
End Sub
I am not using any session in my API, Since i have read that API is stateless and it is not a good practice. So how can i achieve this in my API?
The fifth DBName does not exist in the connection strings configuration, so when ConfigurationManager.ConnectionStrings[DBName] is called it returns null, which will cause the null reference error when you try to call member on null object.
Check to make sure the name being called exists in the web.config.
<connectionStrings>
<!-- ... -->
<add name="FifthDbName" ...... />
</connectionStrings>
You should also do some defensive coding and check for null before trying to access the property.
var setting = ConfigurationManager.ConnectionStrings[DBName];
if(setting != null) {
string DbConnector = setting.ConnectionString;
bool Connection1 = DbConnector.ToLower().StartWith("metadata");
if (Connection1 == true)
{
System.Data.Entity.Core.EntityClient.EntityConnectionStringBuilder
efBuilder = new
System.Data.Entity.Core.EntityClient.EntityConnectionStringBuilder(DbConnector);
DbConnector = efBuilder.ProviderConnectionString;
}
}
//...
Related
I have a problem, so I thought I would come to the brightest minds on the web.
I have written an ASP.NET MVC application that interfaces with a web service provided by another application. My app basically just adds some features to the other web application.
Both applications have a database. I am trying to limit the configuration for my application by using the other applications SQL Server credentials. This is so that if they decide to change the password for the other application, mine will just start working.
These credentials are saved in a .DSN file that my application can reach. How can I get my application, which uses Entity Framework, to use a connection string that is created from the details read in the .DSN file?
I can figure out the code to read the .DSN file, so if you wish to provide some code examples you can base them around setting the connection string for EF.
I am also open to other solutions, or even reasons why I shouldn't do this.
Thanks in advance.
PS. As I was writing this, I came up with a little concept. I am going to test it out now to see how it goes. But here is the basics:
On start up, read the needed details into static properties.
public MyContext() : base(getConnectionString()) { }
3.
private SomeObjectTypeHere getConnectionString()
{
//read static properties
//return .....something..... not sure yet....
}
Thoughts on that maybe?
EDIT
I have created a method that reads the .DSN file and gets the server, the user id and the password. I now have these stored in static properties. In my context, how can I set my connection string now that i have the required details.
So, the biggest issue that I was really having was how to set my connection string in Entity Framework. But I was also hoping that maybe someone else had worked with .DSN files.
Anyway, here was my solution. Still looking for problems that might arise from this, so if you can see any issues, let me know!
First, I created a method that was run on startup. This method ran through the .DSN file and picked out the gems.
Keep in mind that I have never worked with .DSN files, and the section that gets the password is unique to my situation.
var DSNFileContents = File.ReadAllLines(WebConfigurationManager.AppSettings["AppPath"] + #"\App.DSN");//reads DSN into a string array
//get UID
string uid = DSNFileContents.Where(line => line.StartsWith("UID")).First().Substring(4);//get UID from array
//test if uid has quotes around it
if (uid[0] == '"' && uid[uid.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
uid = uid.Substring(1, uid.Length - 2);
}
//get server
string server = DSNFileContents.Where(line => line.StartsWith("SERVER")).First().Substring(7);//get the server from the array
//test if server has quotes around it
if (server[0] == '"' && server[server.Length - 1] == '"')
{
//if to starts with a quote AND ends with a quote, remove the quotes at both ends
server = server.Substring(1, server.Length - 2);
}
//THIS WON'T WORK 100% FOR ANYONE ELSE. WILL NEED TO BE ADAPTED
//test if PWD is encoded
string password = "";
if (DSNFileContents.Where(line => line.StartsWith("PWD")).First().StartsWith("PWD=/Crypto:"))
{
string secretkey = "<secret>";
string IV = "<alsoSecret>";
byte[] encoded = Convert.FromBase64String(DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(12));
//THIS LINE IN PARTICULAR WILL NOT WORK AS DecodeSQLPassword is a private method I wrote to break the other applications encryption
password = DecodeSQLPassword(encoded, secretkey, IV);
}
else
{
//password was not encrypted
password = DSNFileContents.Where(line => line.StartsWith("PWD")).First().Substring(4);
}
//build connection string
SqlConnectionStringBuilder cString = new SqlConnectionStringBuilder();
cString.UserID = uid;
cString.Password = password;
cString.InitialCatalog = "mydatabase";
cString.DataSource = server;
cString.ConnectTimeout = 30;
//statProps is a static class that I have created to hold some variables that are used globally so that I don't have to I/O too much.
statProps.ConnectionString = cString.ConnectionString;
Now that I have the connection string saved, I just have my database Context use it as below,
public class myContext : DbContext
{
public myContext() : base(statProps.ConnectionString) { }
//all my DbSets e.g.
public DbSet<Person> Persons{ get; set; }
}
This is simple, yes, but I hoping that it can provide some information to anyone that was looking to do something similar but was not sure about how it should be handled.
Again, let me know if you like or dislike this solution and if you dislike it, what is your solution and why.
Thanks again!
Just calling my WCF to populate my datagridView
private void button1_Click(object sender, EventArgs e)
{
ServiceReferenceReservations.ReservationsServiceClient srr =
new ServiceReferenceReservations.ReservationsServiceClient();
gridData.DataSource = srr.getAllReservations();
}
and this what mycf does transforming return type of the businesslayer to have the right one
public List<clsReservation> getAllReservations()
{
List<clsReservation> oDataList = new List<clsReservation>().ToList();
List<Reservation> mesReservations = BusinessLayer.Reservations.LoadAllReservationsEF();
foreach (var item in mesReservations)
{
clsReservation cls = new clsReservation()
{
id = item.id,
lecteurID = item.lecteurID,
livreID=item.livreID
};
oDataList.Add(cls);
}
return oDataList;
}
and the business layer is going to call the data access layer and returning back with data
return DataAccessLayer.Reservations.LoadAllReservationEF();
Then my data access layer is using Entity Framework
public static List<Reservation> LoadAllReservationEF()
{
List<Reservation> malisteReservation = new List<Reservation>();
using (bibliothequeEntities dbcontext = new bibliothequeEntities())
{
List<Reservation_SelectAll_Result> maliste = dbcontext.Reservation_SelectAll().ToList();
var x = from p in maliste
select new Reservation
{
id = p.id,
lecteurID = p.lecteurID,
livreID = p.livreID,
};
foreach (var item in x)
{
malisteReservation.Add(item);
}
}
return malisteReservation;
}
My data access layer is throwing an error in Model1.Context.cs:
No connection string named 'bibliothequeEntities' could be found in the application config file of the DAL
<connectionStrings>
<add name="bibliothequeEntities"
connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlClient;provider connection string="data source=arpa;initial catalog=bibliotheque;integrated security=True;MultipleActiveResultSets=True;App=EntityFramework""
providerName="System.Data.EntityClient" />
</connectionStrings>
But I have that connectionstring in my DAL and also in the startup project calling the WCF. I've already tried to comment the method "onModelCreating" to avoid the throw error but still can't find a solution
What am I missing?
If hosting in IIS, you need to copy the contents of your app.config file into the web.config file of the virtual directory where you're hosting it in IIS. I don't believe this is done automatically for you.
If you use something else to host, you similarly need to locate the folder where the host is executing, and copy the contents into that app/web.config.
In short, you the connection-strings need to be in the .config of the host, not any other assembly.
See here for more details.
the connection string should be in wcf that's all there is no need to even put it in dataccesslayer
I've an application which insert/save data in different databases hosted on different server. UI may be different but at the end data which is getting saved is almost same.
So i want to use the same DataAccessLayer but want to change the connectionString based on the loggedin user.
Dependency can be configured in startup.cs but at that time i may not know the DataBase user would like to work with.
on login page i'm asking user to select the database to work with, so only way to change the connection string is after login page.
Any suggestion?
public class ConnectionRepository : IConnectionRepository
{
private IDbConnection _cnn = null;
public IDbConnection GetOpenConnection(string databaseName)
{
if (_cnn != null && _cnn.ConnectionString.ToLower().Contains(databaseName.ToLower()))
{
_cnn.Open();
return _cnn;
}
var cnn = ConfigurationManager.ConnectionStrings["DefaultConnection"].ToString();
//Now replace database name in connection string with whichever one supplied
var cb = new SqlConnectionStringBuilder(cnn) { InitialCatalog = databaseName };
// wrap the connection with a profiling connection that tracks timings
return new ProfiledDbConnection(new SqlConnection(cb.ConnectionString), MiniProfiler.Current);
}
}
This code replaces the InitialCatalog (database name) part of the connection string dynamically base on the supplied name. The current name is stored in session when the user logs in.
Hope this helps.
I'm utilizing Hangfire in my ASP .Net MVC Web App, it had installed successfully. I'd like to use the same LocalDb to store queued jobs for Hangfire to dequeue and process as I've used to stored data. However I'm running into the below error when I provided its connectionString or name defined in Web.config in Startp.cs. I've had no trouble adding, deleting updating data in the same localDb before hangfire.
Cannot attach the file 'c:\users\jerry_dev\documents\visual studio 2013\Projects\Hangfire.Highlighter\Hangfire.Highlighter\App_Data\aspnet-Hangfire.Highlighter-20150113085546.mdf' as database 'aspnet-Hangfire.Highlighter-20150113085546'.
Startup.cs:
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.UseHangfire(config =>
{
string hangfireConnectionString = #"Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-Hangfire.Highlighter-20150113085546.mdf;Initial Catalog=aspnet-Hangfire.Highlighter-20150113085546;Integrated Security=True";
config.UseSqlServerStorage(hangfireConnectionString);
config.UseServer();
});
}
My project Solution is named "Hangfire.Highlighter"
Web.config:
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=(LocalDb)\v11.0;AttachDbFilename=|DataDirectory|\aspnet-Hangfire.Highlighter-20150113085546.mdf;Initial Catalog=aspnet-Hangfire.Highlighter-20150113085546;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
I know this is old - but its been 9 months and I pulled my hair out over this as well - and decided to do a write-up on it here.
My solution was to just create a quick and dirty DbContext, point it to the proper connection string, and call Database.CreateIfNotExists in the constructor:
public class HangfireContext : DbContext
{
public HangfireContext() : base("name=HangfireContext")
{
Database.SetInitializer<HangfireContext>(null);
Database.CreateIfNotExists();
}
}
In the HangfireBootstrapper.Start() method I do something like this:
public void Start()
{
lock (_lockObject)
{
if (_started) return;
_started = true;
HostingEnvironment.RegisterObject(this);
//This will create the DB if it doesn't exist
var db = new HangfireContext();
GlobalConfiguration.Configuration.UseSqlServerStorage("HangfireContext");
// See the next section on why we set the ServerName
var options = new BackgroundJobServerOptions()
{
ServerName = ConfigurationManager.AppSettings["HangfireServerName"]
};
_backgroundJobServer = new BackgroundJobServer(options);
var jobStarter = DependencyResolver.Current.GetService<JobBootstrapper>();
//See the Recurring Jobs + SimpleInjector section
jobStarter.Bootstrap();
}
}
Not sure why Hangfire has such a hard time with LocalDb - maybe it can only handle full-blown SQL instances? Either way this works for me, new team members, and new dev/staging/prod instances that get stood up.
I too know this is old, but ran into this recently. Here is my fix:
In Visual Studio, go to 'View -> SQL Server Object Explorer'
Connect to the Data Source if it isn't already connected. In the example above it was '(LocalDb)\v11.0'
Right click on 'Databases' -> 'Add New Database'
Fill Database name = Ex: 'aspnet-Hangfire.Highlighter-20150113085546' or whatever you've named the database in the connection string.
Fill Database location = This should be the Data Directory in your application, 'App_Data' for the MVC project.
This fixed the issue in my case.
Jack's answer didn't work for me, because I ran into this problem: No connection string named could be found in the application config file
I got it to work with the following modifications:
Remove "name=" from the string in the base initializer. Thanks to: https://stackoverflow.com/a/37697318/2279059
This moves the error to the call of UseSqlServerStorage. So instead of passing "HangfireContext" to it, I just copy the connection string from the dummy database context.
Complete setup code:
public class HangfireContext : DbContext
{
public HangfireContext() : base("HangfireContext") // Remove "name="
{
Database.SetInitializer<HangfireContext>(null);
Database.CreateIfNotExists();
}
}
public partial class Startup
{
public static void ConfigureHangfire(IAppBuilder app)
{
var db = new HangfireContext();
GlobalConfiguration.Configuration.UseSqlServerStorage(db.Database.Connection.ConnectionString); // Copy connection string
app.UseHangfireDashboard();
app.UseHangfireServer();
}
}
Is the DB already created? Can you try using a different conneciton string format?something like this,
"Server=.;Database=HangFire.Highlighter;Trusted_Connection=True;"
Answer as per AspNetCore 3.1 and Hangfire 1.7.17
Hangfire should create all the tables provided there is an existing database with the specified database name.
If you want to use LocalDb, you can use the following registrations (see below).
services
.AddHangfire(
(serviceProvider, config) =>
{
//read settings or hardcode connection string, but this is cleaner
var configuration = serviceProvider.GetService<IConfiguration>();
var connectionString = configuration.GetValue<string>("Hangfire:ConnectionString");
var sqlServerStorageOptions =
new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true
};
config
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings();
.UseSqlServerStorage(connectionString, sqlServerStorageOptions);
});
The connection string is read, in my example, from the appsettings, so it'd look like this
"Hangfire": {
"ConnectionString": "Data Source=(localdb)\\MsSqlLocalDb; Database=Hangfire;"
}
Again, notice how the connection string has the name of the database (e.g: Hangfire) that MUST exist in localdb. If you remove the Database=xxx parameter altogether, it'll pick the master database by default and create all the tables there.
I have an EF5 ASP.NET MVC 3 (Razor) web site, running under IIS7. Now I want to be able to change the connection string to the MSSQL database depending on the subdomain of the URL, e.g. foo.mydomain.com should connect to my "Foo" database, and bar.mydomain.com should connect to the "Bar" database.
Obviously the DNS records are set up so that they all point to the same web site.
What's the most efficient way of achieving this?
why don't you start passing your own SqlConnection to your YourDbContext?
var partialConString = ConfigurationManager.ConnectionStrings["DBConnectionStringName"].ConnectionString;
var connection = new SqlConnection("Initial Catalog=" + Request.Url.Host + ";" + partialConString);
var context = new MyDbContext(connection, true);
You can also change database in the DBContext:
context.Database.Connection.ChangeDatabase("newDbname");
It's not very easy...
You should change the constructor of object context to dynamically change the connection string.
Take the subdomain name using System.Web.HttpContext.Current.Request.Url.Host. Then use it to compute the proper connection string.
You should do this in the designer generated code. Of course this is not a good place.. to make it work use the T4 templating. Open your model and right click on the blank designer surface, then select "Add code generation item" -> Ado.net entity object generation. This will create a .tt file. Open it and look for the constructor syntax. Add your logic there.
Good luck!
I've come up with what I feel is a better solution than all those proposed to date. I'm using the default EntityModelCodeGenerator, so perhaps there are other, better, solutions for other templates - but this works for me:
Create the other half of the partial class MyEntities.
Override OnContextCreated(), which is called from within the class constructor.
Change the store connection string using a regex.
This comes out as follows:
partial void OnContextCreated()
{
// change connection string, depending on subdomain
if (HttpContext.Current == null) return;
var host = HttpContext.Current.Request.Url.Host;
var subdomain = host.Split('.')[0];
switch (subdomain)
{
case "foo":
ChangeDB("Foo");
break;
case "bar":
ChangeDB("Bar");
break;
}
}
private void ChangeDB(string dbName)
{
var ec = Connection as EntityConnection;
if (ec == null) return;
var match = Regex.Match(ec.StoreConnection.ConnectionString, #"Initial Catalog\s*=.*?;", RegexOptions.IgnoreCase);
if (!match.Success) return;
var newDbString = "initial catalog={0};".Fmt(dbName);
ec.StoreConnection.ConnectionString = ec.StoreConnection.ConnectionString.Replace(match.Value, newDbString);
}
Either use different connection strings in the web.config. Maybe research a bit if you can have conditional XSL transformations, that way, when you publish on a specific configuration the web.Release.config will change your Web.Config to be what you need it to be.
Or, use |DataDirectory| string substitution - http://msdn.microsoft.com/en-us/library/cc716756.aspx
more on DataDirectory string substitution here:
http://forums.asp.net/t/1835930.aspx/1?Problem+With+Database+Connection
I guess, if you want to be by the book, create build configurations for each of your separate releases and put the connection string in the respective web..config and when you publish, that XSL transformation will put the connection string in the resulting web.config and voila.
I've done something like that recently by adding some custom configuration, which uses the host header to determine the connectionStringName, which has to be used.
EF5 has a constructor, which can handle this name
var context = new MyDbContex("name=<DBConnectionStringName>");
I just did for a project
public partial class admpDBcontext : DbContext
{
public static string name
{
get
{
if (System.Web.HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority).ToString() == "http://fcoutl.vogmtl.com")
{
return "name=admpDBcontext";
}
else { return "name=admpNyDBcontext"; }
}
}
public admpDBcontext()
: base(name)
{
}
}
And in the web.config I add the connectionString.