How to use Settings.settings for entity framework connection strings? - entity-framework

I'd like to store the Entity model connection string in the app.config using the same approach used by old Typed DataSet. Both use the same section: <connectionStrings>.
Entity saves the connection as:
<add name="MyDB_Entities" connectionString="metadata=res://*/MyDB.csdl|res:......" providerName="System.Data.EntityClient" />
Typed DataSet saves as:
<add name="MyTest.Properties.Settings.MyDbString" connectionString="Data Source=.\sqlexpress;...." providerName="System.Data.SqlClient" />
The former is only accessibile using a "not-typed" syntax, like:
string s = ConfigurationManager.ConnectionStrings["MyDB_Entities"].ConnectionString;
The latter is "wrapped" by Settings.settings. So you can write:
string s = Settings.Default.MyDbString;
The Entity entry does not contain the namespace so Settings.settings is not able to parse it. Any idea /suggestion?

Related

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");

decrypt connectionstring with entity framework

I've made a class called Crypto to encrypt en decrypt connectionStrings. This class works perfectly.
The idea is to get the encrypted connectionstring in the config file:
<add name="MyConnString" connectionString="KsY+XWC0GnsepTlVu0Z3BU4r0hCAfgrCl/gbqlasndFmCjq0iiTNC7r0JySqm4BtSnSktE20EfDe9F3cDZTaQqwUgmdQTrxBc8cp5HhC9G6PEyzXIVzy2HMyOIH45yTQ9j70uMPV7TUazlnvzRDYnrKJwpgHNQehjMovgkWKCfZji1kQNVN7/61yvdrv+d6KpQKU5Al5W2QKkI7wxYzvJ4vMwH6XoCk1RnulKFKvaMExWtjQTh4XOy2Wo4M9UHKM/FuhjrsxsBg4JgcUcPGfrJZortFmmeDYt7D7QP6/I9HlIrmR4K42/hKSb/ZGiDV9szK6A/V1u9p5qctqFCui7Dx0AKkvUqFIWOWQHtvivV0R/PW8+R1bxsNkr6wUK6A5uPyghJmP4Qv0VI3vW8z0Tw==" providerName="System.Data.EntityClient" />
the problem is where and how do I decrypt the connectionstring (the decrypt method works)
I've tried making these adjustments to the designer class within the edmx file:
public partial class KlantenBITEntities : ObjectContext
{
public static string DecryptedConnectionString
{
get { return Crypto.DecryptFromBase64String(ConfigurationManager.ConnectionStrings["MyConnString"].ToString()); }
}
And in the constructor I tried to pass the decrypted connectionstring :
public KlantenBITEntities(): base(DecryptedConnectionString,"KlantenBITEntities")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
If I to this I get this error:
Keyword not supported:'data source'
I've encrypted the whole entity framework connectionstring (with csdl-,ssdl-,msl-file etc..) Could this be the cause?
Any help with finding a proper way to decrypt the entity framework connectionstring is very much appreciated.
Found the answer here:
KeyWord Not Supported: data source
the problem was &quote . Replacing it by single quotes solves it.

DotNetOpenAuth Provider for REST Service

I've created a REST API in an Area of my ASP.NET MVC 4 web application. The API is working properly, and I'd now like to secure it.
Is there a very simple example of how I can do this? I'm going through the samples that came with the DotNetOpenAuth download and I'm completely lost on it.
I had the same problem a couple of days ago. This answer is ridiculously long, maybe there's an easier way.
Personally, I don't use DNOA anymore because it is designed towards self-validating (i.e. encrypted tokens) so you don't need to hit the DB with every request. A very important side effect of this is that an access revocation will not become effective immediately, but only after the token must be renewed. Also, access tokens will become quite long (around 500 bytes).
As a very first step, make sure you know what you need:
OAuth / OAuth2 look easy at first, but it's important to understand how the authorization workflows are designed. Also, their terminology can be irritating, for instance 'Client' refers to what I would naively call client application. It's not the user (who is called 'resource owner' in OAuth terms). My suggestion: Read RFC 6749. It looks dull, but it's an interesting read (and you can skip half of it...)
A key question is: Do you need 2-legged OAuth or 3-legged OAuth (or both?). Which grant types do you need to support?
If you basically want to replace HTTP Basic Auth, the simple "Resource owner password credentials flow" will do. The facebook/twitter kind type of "have this application access my profile information" is 3-legged OAuth.
There's an IBM Documentation that comes with nice grant type diagrams.
Now to DNOA, take a look at Samples/OAuthAuthorizationServer.
A good entry point is the OAuthController.cs file. Note that the Authorize and AuthorizeResponse actions are required only if you want to enable your users to give access to third party applications (3-legged OAuth).
In a 2-legged scenario, users access the OAuth token endpoint directly and simply request an access token. In any case you will need such a controller in your REST application.
The key to the inner workings is the OAuth2AuthorizationServer class (NOT the AuthorizationServer class). Look at Code/OAuth2AuthorizationServer.cs. It implements IAuthorizationServerHost.
Half of that class deals with data storage (which you might want to modify if you're working with a different datastore), and half of it deals with the encryption of the access tokens. You will need to implement IAuthorizationServerHost for your application, too.
Make sure you have a line #define SAMPLESONLY in your code, so it will accept the hardcoded certificate.
To actually authorize the request, it is helpful to write a custom ActionFilterAttribute. Here's some super condensed code, not production ready:
public sealed class BasicAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute
{
private readonly OAuthResourceServer _authServer;
public override void OnActionExecuting(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization.Scheme == "Bearer"
|| actionContext.Request.Properties.ContainsKey("access_token"))
{
authenticatedUser = _authServer.VerifyOAuth2(request, required_claims);
HttpContext.Current.User = authenticatedUser;
Thread.CurrentPrincipal = authenticatedUser;
}
}
}
// See OAuthResourceServer/Code/OAuthAuthorizationManager.cs in DNOA samples
public sealed class OAuthResourceServer
{
public IPrincipal VerifyOAuth2(HttpRequestMessage httpDetails, params string[] requiredScopes)
{
// for this sample where the auth server and resource server are the same site,
// we use the same public/private key.
using (var signing = CreateAuthorizationServerSigningServiceProvider())
{
using (var encrypting = CreateResourceServerEncryptionServiceProvider())
{
var tokenAnalyzer = new StandardAccessTokenAnalyzer(signing, encrypting);
var resourceServer = new ResourceServer(_myUserService, tokenAnalyzer);
return resourceServer.GetPrincipal(httpDetails, requiredScopes);
}
}
}
}
The resource server is still missing
public sealed class MyResourceServer : ResourceServer
{
public override System.Security.Principal.IPrincipal GetPrincipal([System.Runtime.InteropServices.OptionalAttribute]
[System.Runtime.InteropServices.DefaultParameterValueAttribute(null)]
HttpRequestBase httpRequestInfo, params string[] requiredScopes)
{
AccessToken accessToken = this.GetAccessToken(httpRequestInfo, requiredScopes);
string principalUserName = !string.IsNullOrEmpty(accessToken.User)
? this.ResourceOwnerPrincipalPrefix + accessToken.User
: this.ClientPrincipalPrefix + accessToken.ClientIdentifier;
string[] principalScope = accessToken.Scope != null ? accessToken.Scope.ToArray() : new string[0];
// Now your own code that retrieves the user
// based on principalUserName from the DB:
return myUserService.GetUser(userName);
}
}
Next, modify web.config so DNOA doesn't complain about missing SSL connections in development:
<configSections>
<sectionGroup name="dotNetOpenAuth" type="DotNetOpenAuth.Configuration.DotNetOpenAuthSection, DotNetOpenAuth">
<section name="openid" type="DotNetOpenAuth.Configuration.OpenIdElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
<section name="oauth" type="DotNetOpenAuth.Configuration.OAuthElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
<sectionGroup name="oauth2" type="DotNetOpenAuth.Configuration.OAuth2SectionGroup, DotNetOpenAuth">
<section name="authorizationServer" type="DotNetOpenAuth.Configuration.OAuth2AuthorizationServerSection, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
</sectionGroup>
<section name="messaging" type="DotNetOpenAuth.Configuration.MessagingElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
<section name="reporting" type="DotNetOpenAuth.Configuration.ReportingElement, DotNetOpenAuth" requirePermission="false" allowLocation="true" />
</sectionGroup>
</configSections>
<dotNetOpenAuth>
<!-- Allow DotNetOpenAuth to publish usage statistics to library authors to improve the library. -->
<reporting enabled="true" />
<openid>
<provider>
<security requireSsl="false">
</security>
</provider>
</openid>
<oauth2>
<authorizationServer >
</authorizationServer>
</oauth2>
<!-- Relaxing SSL requirements is useful for simple samples, but NOT a good idea in production. -->
<messaging relaxSslRequirements="true">
<untrustedWebRequest>
<whitelistHosts>
<!-- since this is a sample, and will often be used with localhost -->
<add name="localhost"/>
</whitelistHosts>
</untrustedWebRequest>
</messaging>
</dotNetOpenAuth>

Entity Framework - supply a connection string to constructor

I'm using EF in my C# project. We're about to add clients which will have other databases with other connection strings.
There's no need to sync between DBs.
I tried using the following c'tor (the 2nd out of 3 supplied):
public AppEntities(string connectionString)
and I get the following error: 'Keyword not supported: 'data source'.'
The connection string is as follows:
metadata=res://EntityFramework/App.csdl|res://EntityFramework/App.ssdl|res://EntityFramework/App.msl;provider=System.Data.SqlClient;provider connection string="Data Source=dbname\dbname;Initial Catalog=App;Persist Security Info=True;User ID=User;Password=password;MultipleActiveResultSets=True"
This is the same connection string that is used when taken from App.Config. I don't want to take it from there but rather build it myself (thus leaving the username & password hard-coded in my app's code and not in free text.
Any idea?
Thanks.
The connectionstring parameter is not an Entity Framework Connectionstring (as in the .config file) but it has to be a "normal" .net connectionstring.
The link's example shows how to "convert" the ef connectionstring to a normal connectionstring (using the EntityConnectionStringBuilder.ToString() method). If you pass the app.config's unprepared string you will get the mentioned error.
You can use the EntityConnectionStringBuilder to parse the app.config value and convert it.
Hope that helps.

ADO.NET Entity Connection String for Multiple Projects

I am using multiple layer project where the DataModel hosts the ADo.NET Entity model and DataAccess layer does the validation.
However everytime I get a error like this
The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid.
I have tried connection strings
<add name="SalesEntities" connectionString="metadata=res://*/SalesEntities.csdl|res://*/SalesEntities.ssdl|res://*/SalesEntities.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.;Initial Catalog=Phoenix;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
and
<add name="SalesEntities" connectionString="metadata=.\SalesEntities.csdl|.\SalesEntities.ssdl|.\SalesEntities.msl;provider=System.Data.SqlClient;provider connection string="Data Source=.;Initial Catalog=Phoenix;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
also tried other combinations to refer the Root Directory of the Called project directory but no luck.
Any help is highly appreciated. Many Thanks as always :).
You have to put those connection strings in each applications app.config file. If you have a DAL that you generated the model in, and then try to consume the DAL in an EXE the same thing will happen. The EXE does not know the connection string.
The easiest thing I have found is to put an app.config on each project and just copy the connection string from the DAL I generated the models in originally. Then each will have a copy of that same connection string.
If you copy your App.Config file into the main project and replace all the " with the normal ' character it should run
I suggest a slight variation on the suggestions given above.
It's not a huge improvement, but at least it gives you some separation of concerns.
When the EF wizard creates the .edmx file and its associated .Designer.cs file, the C# code declares a partial class. So you can simply add another.cs file to the project containing the two EDM files.
This new file defines an additional static function for the same namespace and class.
This new static function will return an instance of the desired type (the descendant of ObjectContext).
The new file is a separate file, so it won't be overwritten if you re-create the .edmx and .Designer.cs.
You copy and paste the connection string from the .config of the EDM project, which is kind of a hack, but at least it keeps the connection string hidden in the EDM project.
The new file looks like this:
namespace MyNamespace
{
public partial class MyEntities : ObjectContext
{
public static MyEntities New_MyEntities()
{
string connStr;
MyEntities theContext;
connStr = "metadata=res://*/MyClass.csdl|res://*/MyClass.ssdl|res://*/MyClass.msl;provider=System.Data.SqlClient;provider connection string=\"Data Source=localhost\\SQLSERVER;Initial Catalog=MyDb;Integrated Security=True;MultipleActiveResultSets=True\"";
// set the connection string
theContext = new MyEntities(connStr);
// allocate it
return theContext;
// return it
}
}
}
To get a new entities object, you simply call the static function New_MyEntities() from your calling project.
I passed the entityconnectionstring to all the instances of the objectContext classes and its working now.
But its a too much overhead, creating a property with connectionstring and passing it as a parameter to each instance
I add the same problem, trying to unit-test my DAL. I've found that this works :
<add name="SalesEntities" connectionString="metadata=res://*;provider=System.Data.SqlClient;provider connection string="Data Source=.;Initial Catalog=Phoenix;Integrated Security=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
I had a similar problem with a WinForms project and despite trying everything I could find related to it on the web could not resolve my problem..... until I removed the field that I was using for my ObjectContext (private CubEntities _oc = new CubEntities()) from my BaseForm to the actual form using it.
I got same problem & i tried all the mentioned method. finally i solved it as mentioned. In my case I have separate data layer and presentation layer. in my app.config (data layer) i have connection like this.
<add name="LibraryMgtSysEntities" connectionString="metadata=res://*/DataLibraryMgtSys.csdl|res://*/DataLibraryMgtSys.ssdl|res://*/DataLibraryMgtSys.msl;provider=System.Data.SqlClient;provider connection string="data source=abc;initial catalog=LibraryMgtSys;Persist Security Info=True;user id=sa;password=123;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
in my web.config i manually configured connection as follows:
<add name="DefaultConnection" providerName="System.Data.SqlClient"
connectionString="Data Source=abc;
Initial Catalog=LibraryMgtSys;
Integrated Security=SSPI;
user id=sa;password=123;" />
it gives me same exception as mentioned above. so i solved it by adding app.config value in web config file.
my final web.config file as follows:
<connectionStrings>
<clear />
<add name="LibraryMgtSysEntities" connectionString="metadata=res://*/DataLibraryMgtSys.csdl|res://*/DataLibraryMgtSys.ssdl|res://*/DataLibraryMgtSys.msl;provider=System.Data.SqlClient;provider connection string="data source=TILANITHOTAMUNE\SQLEXPRESS;initial catalog=LibraryMgtSys;Persist Security Info=True;user id=sa;password=testing;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" />
<add name="DefaultConnection" providerName="System.Data.SqlClient"
connectionString="Data Source=abc;
Initial Catalog=LibraryMgtSys;
Integrated Security=SSPI;
user id=sa;password=123;" />
</connectionStrings>
I had the issue in one of my projects, as entity framework connection string was required by a job, a web application and a test project. One way to deal with this was the following:
1) Use UnitOfWork (or a similar) pattern. This allows to control data context creation and manipulate connection string
public partial class MyContext
{
#region Members
private static readonly object objSync = new object();
private static readonly string DATACONTEXT_KEY = "MyContext_UserInstance";
// TODO: read from a place accesible to all deployed projects
// remove hardcoded database
private static readonly string DefaultConnectionString = #"metadata=res://*/MyContext.csdl|res://*/MyContext.ssdl|res://*/MyContext.msl;provider=System.Data.SqlClient;provider connection string='data source=Server;initial catalog=MyDatabase;integrated security=True;multipleactiveresultsets=True;App=EntityFramework'";
private static string connectionString;
#endregion
public MyContext(String connectionString) : base(connectionString)
{
}
/// <summary>
/// Uses a UnitOfWorkStore to return the same instance of MyContext, that is unique
/// per user, per postback (or CallContext, if not in an HttpContext environment, such as unit tests or console apps)
/// </summary>
public static MyContext Instance
{
get
{
// Dirty (non thread-safe) check
if (UnitOfWorkStore.GetData(DATACONTEXT_KEY) == null)
{
lock (objSync)
{
// Thread-safe check
if (UnitOfWorkStore.GetData(DATACONTEXT_KEY) == null)
{
MyContext context = new MyContext(DefaultConnectionString);
connectionString = context.Database.Connection.ConnectionString;
UnitOfWorkStore.SetData(DATACONTEXT_KEY, context);
}
}
}
return (MyContext)UnitOfWorkStore.GetData(DATACONTEXT_KEY);
}
}
}
Data context should allow direct connection string input:
public MyContext(String connectionString) : base(connectionString)
{
}