No data available with Entity Framework when consumed by second project - entity-framework

I have a web app that uses EF5 to map to a SQL database. This is the standard membership database with some additional tables I've added. Works like a champ in that project.
I have a second project, a windows service running TCP a server, which needs to insert items into the same database. So I reference the web app from this second project and can see my DbContext and entity types as needed.
At runtime, however, none of my DbSets gets populated with data. I have tried explicitly opening the connection to execute queries too, like this:
public MyContext()
: base("DefaultConnection")
{
try
{
Database.Connection.Open();
var command = new System.Data.SqlClient.SqlCommand("SELECT * FROM dbo.Trackers", (SqlConnection) Database.Connection);
var reader = command.ExecuteReader();
bool result = reader.Read();
}
catch (Exception exception)
{
//handle exception
}
this.Database.Connection.Close();
}
The result is false, but the connection is created and the reader is aware that I have four fields in my table. Is anyone aware of a reason this should work in my web app but not in a referencing app?

I had forgotten that the connection string from the web.config file is only honored when running as a web app. The TCP service .exe needs its own copy of the connection string in App.config. It just happened that the default (implicit) connection string on my TCP service connected to a valid, but empty, copy of my database.

Related

C# MVC5 classic ADO.NET when to open connection

I'm using MVC5 with classic ADO.NET objects such as sqldatareader and sqldataadapter and sqlconnection and so on....
My controllers are creating a connection while initializing because I need to send the request object to the class holding the sqlconnection for something irrelevant to the question so my controller has an override void
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
db = new db(Request);
db.Connect();
}
Where db is my class and the method (connect) will create the sqlconnection object and open a connection...
and to close the connection I used the controller's dispose method as follows
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (db != null)
{
db.Close();
db = null;
}
}
and everything works fine then at one moment I got a weird server error (can't connect to db) please notice that my host is smarterasp.net
I can connect to database remotely using my home computer and I can connect to the web host as well so the problem is between my webhost and my database host, or between my application and my database host...
or it could be something related to the connection pooling even though the server error doesn't give me any details or stack trace(hens error is not inside my app thread)....
and I've fixed the problem by opening (remote iis) tab of smarterasp.net's control panel and clicked on (fix ACL) which I have no idea what it does but it fixed my problem.... temporarily :( unfortunately the problem reoccurred many times after that
so my question is in short format
is it good practice to open the connection while I'm initializing the controller and close it while the controller disposing???
and what do you think the error reason is??
finally I want to apologize if the question wasn't clear enough because English is not my first language (obviously)....
thanks a lot
so my question is in short format is it good practice to open the
connection while I'm initializing the controller and close it while
the controller disposing???
I do not think that is a good approach. You shouldn't open / close database connections and / or access the database from your controller. The controller should be as "thin" as possible. Additionally - the connection should be kept open for as short a period of time as possible and let ADO.NET connection pooling handle the details for you.
I also recommend wrapping your connection in a using block as it will implicitly call the close method:
using (SqlConnection connection = new SqlConnection(
connectionString))
{
SqlCommand command = new SqlCommand(queryString, connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
You did not say what the exact error is. At first glance, you aren't even checking to see if the connection is open before you try closing it. You should check the connection state before you try to explicitly close it and this should happen outside of the controller. Though I recommend that you wrap your SqlConnection in a using block (mentioned above).
EDIT
I read your comment. You are trying to manage the connection within the context of the controller's lifecycle and I suspect this is your issue.
If you were using Entity Framework (or possibly an another ORM), an IoC with "per-request lifestyle" - then the IoC container would properly dispose your context (connection) at the end of each request, and serve a new instance at each new one.
Perhaps this an option you can explore if you want to manage your database connection this way.

WCF netTCP EntityFramework WindowsAuthenticated SQL

I am using WCF netTCP and passing Windows Identity. But EntityFramework is not allowing WindowsAuthenticated SQL connections. SQL login works fine, but it always has. I have verified that the Thread.CurrentPrincipal does contain the correct identity (domain\networkid). But the EntityFramework attempt is rejecting the machine name (domain\machineid). (this is a safe corporate network)
From the WCF server, this returns the correct domain\networked:
var principal = Thread.CurrentPrincipal;
var identityName = principal.Identity.Name;
From the SAME server, the SAME method, this does not work:
var myEntities = new Declared_EF5_Entities()
The error tells me that domain\machineid$ is not a valid user in that SQL database. Note: the app.config contains the connection string and specifies IntegratedSecurity=true.
All of the code works without any tricks fine when self-hosted.
This did not help:
using (var impcontext = ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
{
var myEntities = new Declared_EF5_Entities()

MVC4 + EntityFramework: metadata only found from within web.config - why is that?

I want to change our EF-driven database-first ASP.NET MVC4 web application in such a way that I can specify the database to connect to at runtime. For the beginning, I simply wanted to substitute the entry in the connectionStrings section of the web.config with a coded version. But first things first. Here's my web.config connection section:
<connectionStrings>
<add name="WEB_Entities" connectionString="metadata=~/bin/Models\WEB_Models.csdl|~/bin/Models\WEB_Models.ssdl|~/bin/Models\WEB_Models.msl;provider=System.Data.SqlClient;provider connection string="data source=testsvr;initial catalog=DEMO;persist security info=True;user id=sa;password=xxxxxxxx;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
When using this setting, everything runs just fine. Now I tried to comment out this entry and hard-code it, thereby moving the setting from the web.config to the global.asax.cs.
I read about the EntityConnectionStringBuilder, but for the beginning I simply want to give the whole connection string as the constructor parameter of an EntityConnection:
string CS =
#"metadata=~/bin/Models\WEB_Models.csdl|
~/bin/Models\WEB_Models.ssdl|
~/bin/Models\WEB_Models.msl;
provider=System.Data.SqlClient;
provider connection string=""Data Source=testsvr\sqlexpress;
Initial Catalog=DEMO;
Integrated Security=True;MultipleActiveResultSets=True""";
conn = new EntityConnection(CS);
conn.Open();
The conn object is a static object that lives in my application class:
public static EntityConnection conn;
In order to use this connection object, I changed my DBContext code to use the aforementioned connection object as constructor parameter, rather than the Name of an entry in the web.config:
public partial class WEB_Entities : DbContext
{
public WEB_Entities()
: base(PAMVCTEST.MvcApplication.conn,true)
//: base("name=WEB_Entities")
{
}
Now when I compile an run the whole thing, the connection to the db server seems to be possible (because I get some network related errors when e.g. changing the datasource to something wrong), but the application does not find the given metadata files. This is the error:
The supplied connection string is not valid, because it contains insufficient mapping or metadata information. Parameter name: connection
I don't understand why the metadata files cannot be found, they are definitely present in the given location. As soon as I change everything back to using the web.config connection entry, everything works as expected.
I also tried changing the metadata files location to this:
res://*/Models.WEB_Models.csdl|res://*/Models.WEB_Models.ssdl|res://*/Models.WEB_Models.msl
I made sure that the resource names are correct with ILMerge. THe result is the same: when I use the web.config way, it works - when I set it by code, I get the same error as mentioned above.
What can I do to resolve this issue? Are there any workarounds? And why in the world do we have to cope with such awful and error-prone connection strings with nested escapings and stuff? It's 2013!!! :-]
Thanks for your help!
Call it from DbContext. Change your DbContext constructor to the following:
public class MyDbContext : DbContext
{
public MyDbContext()
: base("DefaultConnection")
{
}
public MyDbContext(string conStr)
: base(conStr)
{
}
// ...
}
Then add your desired ConStrs to the web config. Finally, when you want another ConStr than the DefaultConnection pass its name to the DbContext() constructor:
Models.MyDbContext db = new Models.MyDbContext("MyConStr");

EntityFramework, AppHarbor and configuration variables

I'm having some trouble with EntityFramework (database first) and AppHarbor.
I'm trying to use the configuration string as inserted into the web.config by AppHarbor (I've added the metadata into the Sequelizer config option on the website), and I'm trying to add some additional values using code provided.
Currently I'm being a very bad person and embedding the string directly into my apps configuration provider - not good if the hosting provider switch DBs on us, so I'm looking to do it the proper way and use the values AppHarbor supply via the web.config.
This is the string as per provided by AppHarbor (passwords and server details removed):
metadata='res://*/MyDataEntities.csdl|res://*/MyDataEntities.ssdl|res://*/MyDataEntities.msl;';provider=System.Data.SqlClient;provider connection string='Server=servername.sequelizer.com;Database=databasename;User ID=username;Password=<snip>;'
If used "as is", that generates the following error:
The specified metadata path is not valid. A valid path must be either an existing directory, an existing file with extension '.csdl', '.ssdl', or '.msl', or a URI that identifies an embedded resource.
I then use the following code (purloined off of one of the AppHarbor support discussions) to append the required extra things EF needs...
if (String.IsNullOrWhiteSpace(ProductionDatabaseConnectionString))
{
// Get it on first read and cache it
var configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
var connectionString = configuration.ConnectionStrings.ConnectionStrings["SQLAppHarbor001"].ConnectionString;
// Add the required extra metadata for EF4.x
if (!connectionString.Contains("MultipleActiveResultSets=True;"))
connectionString += "MultipleActiveResultSets=True;";
if (!connectionString.Contains("App=EntityFramework;"))
connectionString += "App=EntityFramework;";
configuration.ConnectionStrings.ConnectionStrings["SQLAppHarbor001"].ConnectionString = connectionString;
configuration.Save();
ProductionDatabaseConnectionString = connectionString;
}
return ProductionDatabaseConnectionString;
That produces the connection string as follows:
metadata='res://*/MyDataEntities.csdl|res://*/MyDataEntities.ssdl|res://*/MyDataEntities.msl;';provider=System.Data.SqlClient;provider connection string='Server=servername.sequelizer.com;Database=databasename;User ID=username;Password=<snip>;'MultipleActiveResultSets=True;App=EntityFramework;
But that produces the error:
Format of the initialization string does not conform to specification starting at index 165.
Index 165 being the start of "provider connection string".
The working connection string I use embedded, which currently works without issue, is:
metadata='res://*/MyDataEntities.csdl|res://*/MyDataEntities.ssdl|res://*/MyDataEntities.msl;';provider=System.Data.SqlClient;provider connection string='Server=servername.sequelizer.com;Database=databasename;User ID=username;Password=<snip>;multipleactiveresultsets=True;App=EntityFramework'
The only real differences being that the "multipleactiveresultsets=True;App=EntityFramework" entries are inside the "provider connection string" string rather than outside.
Other people seem to be using EntityFramework on AppHarbor using the supplied configuration variables fine, so what an I doing wrong?
Update: Multiple Active Result Sets (MARS) can now be enabled for the injected connection string by using the Sequelizer admin panel. This is the recommended approach since the web.config no longer needs to be modified, which causes an AppDomain reload during startup
I came up against this today! I did the following:
var configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
var connectionString = configuration.ConnectionStrings.ConnectionStrings["ConnStringAlias"].ConnectionString;
if (!connectionString.Contains("multipleactiveresultsets=True;"))
{
connectionString = connectionString.TrimEnd('\'');
connectionString = connectionString += "multipleactiveresultsets=True;\'";
configuration.ConnectionStrings.ConnectionStrings["ConnStringAlias"].ConnectionString = connectionString;
configuration.Save();
}
The MultipleActiveResultSets property must be inside the provider connection string, which is why you received an error regarding the format of your connection string.
I seen a few 'solutions' around but none seemed to work for me, including the solution at the bottom of a support page of how to do exactly this on AppHarbor's site. The solution provided even sends the application into an infinite loop as the application will restart every time the web.config file is saved, which is every time in the example.

Why connectionstring without metadata works?

I had connection strings for entity framework edmx, which is usual EF connection string with metadata.
Now i am implementing mvc-mini-profiler and wrote method below to create context. I am using just sql connection string part now, no longer using EF connection string.
Now it works but i am curious how it is getting metadata(.csdl, .ssdl address), If it can find now then why 'new Context()' need metadata
public static T GetProfiledContext<T>() where T : ObjectContext
{
// create connection
var sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString);
// wrap the connection with a profiling connection that tracks timings
var profiledDbConnection = MvcMiniProfiler.Data.ProfiledDbConnection.Get(sqlConnection, MiniProfiler.Current);
// create context
return profiledDbConnection.CreateObjectContext<T>();
}
The reason why it works without metadata is that CreateObjectContext extension method will add these metadata when creating the context. It uses wildcards: res://*/ to get metadata. You can check the implementation here.