ASP.Net MVC Constructor Injection with Autofac - Change Runtime ConnectionString [duplicate] - asp.net

I have a specific scenario here where I need to pass the connection string based on the user, because users may be mapped to the different databases based on his/her enterprise.
This is the code I use to resolve the dependency with a static variable:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IUserRepository>()
.ImplementedBy(typeof(IKS.Dare.Optimix.Repository.EntityFramework.UserModule.UserRepository))
.DependsOn(Dependency.OnValue("connectionString", DatabaseSettings.DefaultConnectionString))
);
}
Because this DefaultConnectionString is supposed to be a dynamic one, I don't want to lock this variable to make it thread safe, as this would degrade the performance. I would want a way so that I can deal with such situation.
Possible consideration which can be that we can give a session, which can be applied as follows:
DynamicParameters((k, d) => d["connectionString"] = Session["connectionString"])
But this is in a different project which doesn't utilize any web component, it's just an installer project which is basically designed for resolving the dependencies only.
My Generic repository looks like following
public class GenericRepository<T> : IGenericRepository<T> where T : BaseEntity
{
private const string IsActive = "IsActive", DbContext = "dbContext", EntityPropertyName = "Entity";
private string connectionString = String.Empty, provider = String.Empty;
public GenericRepository(string connectionString, string provider)
{
this.connectionString = connectionString;
this.provider = provider;
}
public int Count()
{
string tableName = typeof(T).Name;
string query = SqlQueryConstants.SelectCount + SqlQueryConstants.Space + tableName;
int count = DbHelper.ExecuteScalar<int>(query: query, commandType: System.Data.CommandType.Text, connectionString: connectionString, provider: provider, parameters: null);
return count;
}
}
DBHelper class looks like follows
public static int ExecuteNonQuery(string query, CommandType commandType = CommandType.StoredProcedure,
IList<DbParameter> parameters = null, int? timeout = null, string connectionString = "", string provider = "")
{
using (var connection = CreateDbConnection(connectionString, provider))
{
connection.Open();
using (DbCommand command = CreateDbCommand(sqlQuery: query, parameters: parameters,
connection: connection, commandType: commandType, timeout: timeout))
{
return command.ExecuteNonQuery();
}
}
}
public static DbParameter CreateParameter<TValue>(string name, TValue value, DbType dbType,
ParameterDirection parameterDirection = ParameterDirection.Input, string provider = "")
{
DbParameter param = CreateDbProviderFactory(provider).CreateParameter();
param.Value = value;
param.ParameterName = name;
param.DbType = dbType;
param.Direction = parameterDirection;
return param;
}
public static DbConnection CreateDbConnection()
{
return CreateDbConnection(String.Empty, String.Empty);
}
public static DbConnection CreateDbConnection(string connectionString = "", string provider = "")
{
DbConnection connection = null;
if (String.IsNullOrEmpty(provider))
{
if (String.IsNullOrEmpty(DatabaseSettings.DefaultProvider))
throw new ArgumentNullException("provider");
else
provider = DatabaseSettings.DefaultProvider;
}
connection = CreateDbProviderFactory(provider).CreateConnection();
connection.ConnectionString = connectionString;
return connection;
}
Any help would be greatly appreciated.
Note : I couldn't edit steven's answer.
[EDIT] To make it more clear it can be implemented as:
Here controller is inherited from BaseController
public class UserController : BaseController
{
//
// GET: /Index/
private IUserRepository userRepository;
public UserController(IUserRepository userRepository)
: base(userRepository)
{
this.userRepository = userRepository;
}
}
and BaseController is inherited from Controller where in the database settings are being set in the constructor of Base controller so that we don't need to set it everywhere
public abstract class BaseController : Controller
{
public BaseController(IUserRepository userRepository)
{
userRepository.connectionStringProvider.Provider = WebUtilities.CurrentUserData.Provider;
userRepository.connectionStringProvider.ConnectionString = WebUtilities.CurrentUserData.ConnectionString;
}
}

Since, the connection string is runtime data, you should not use it to construct your application components, as is described in this article. So as the article advices, you should hide the connection string behind a provider abstraction. For instance:
public interface IConnectionStringProvider {
string ConnectionString { get; }
}
This way your repositories can depend on IConnectionStringProvider and can call IConnectionStringProvider.ConnectionString at runtime:
public int Count()
{
string tableName = typeof(T).Name;
string query = SqlQueryConstants.SelectCount + SqlQueryConstants.Space + tableName;
return DbHelper.ExecuteScalar<int>(
this.connectionStringProvider.ConnectionString,
provider: provider, parameters: null);
}
It will be trivial to create an IConnectionStringProvider to will get the correct connection string for you:
class DatabaseConnectionStringProvider : IConnectionStringProvider
{
public string ConnectionString => Session["connectionString"];
}
Since this clas depends on application-specifics (the ASP.NET session in this case), the class should not be part of the application's core logic. Instead, this adapter should live in the application's start up path (a.k.a. the composition root, the place where you configure your container).
You might even want to consider not passing along the IConnectionStringProvider into your repositories, but instead create an abstraction that will create a connection itself. This will hide the fact that there is a connection string completely.

What you're looking for is multi tenancy. You can google "castle windsor multi tenancy" and find a number of useful articles.
Here's a similar Stackoverflow question that links to some good articles on Windsor and multi tenancy. In particular, look into Windsor's IHandlerSelector interface.

Related

Execute Dynamic Entity in Database using Dapper

My user send dynamic entity from client-project so, I have to write methods like this
public Task<TUser> FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
throw new NotImplementedException();
//string sql = "SELECT * FROM \"IdentityUsers\" WHERE \"NormalizedUserName\" = #NormalizedUserName;";
//using (var connection = _databaseConnectionFactory.CreateConnectionAsync())
//{
// connection.QueryFirstOrDefaultAsync<TUser>(sql,
// new { NormalizedUserName = normalizedUserName });
//}
}
My IDatabaseConnectionFactory class bind ConnectionString like below:
public interface IDatabaseConnectionFactory
{
Task<IDbConnection> CreateConnectionAsync();
}
public class ConnectionFactory : IDatabaseConnectionFactory
{
private readonly string _connectionString;
public ConnectionFactory(string connectionString) => _connectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString));
public async Task<IDbConnection> CreateConnectionAsync()
{
try
{
var connString = new NpgsqlConnection(_connectionString);
await connString.OpenAsync();
return connString;
}
catch
{
throw;
}
}
}
Now, how can I execute following query using generic-type entity TUser
string sql = "SELECT * FROM \"IdentityUsers\" WHERE \"NormalizedUserName\" = #NormalizedUserName;";
using (var connection = _databaseConnectionFactory.CreateConnectionAsync())
{
connection.QueryFirstOrDefaultAsync<TUser>(sql,
new { NormalizedUserName = normalizedUserName });
}
Note: QueryFirstOrDefaultAsync not found under connection here
You aren't awaiting the CreateConnectionAsync. Unfortunately it isn't obvious in this case, because Task<T> is disposable (so the using doesn't complain); try instead:
using (var connection = await _databaseConnectionFactory.CreateConnectionAsync())
{
var user = await connection.QueryFirstOrDefaultAsync<TUser>(sql,
new { NormalizedUserName = normalizedUserName });
}
As a tip: the compiler output (against the original code) helps make this clear:
Error CS1929 'Task<IDbConnection>' does not contain a definition for 'QueryFirstOrDefaultAsync' and the best extension method overload 'SqlMapper.QueryFirstOrDefaultAsync<TUser>(IDbConnection, string, object, IDbTransaction, int?, CommandType?)' requires a receiver of type 'IDbConnection'
which tells us that:
it found some QueryFirstOrDefaultAsync method, but it wasn't usable, because
the target expression is a Task<IDbConnection>, not an IDbConnection
As a side note: it is worth knowing that if you're only doing one operation with the connection, Dapper can deal with opening and closing the connection for you - which can help reduce the number of async/await operations. Consider, for example, if you had a CreateClosedConnection() method that did not open the connection, and thus had no need to be async; the following would still work:
using (var connection = _databaseConnectionFactory.CreateClosedConnection())
{
var user = await connection.QueryFirstOrDefaultAsync<TUser>(sql,
new { NormalizedUserName = normalizedUserName });
}
with Dapper dealing with the await OpenAsync() for you as part of the QueryFirstOrDefaultAsync.

Using Entity Framework, ASP.NET MVC Core, and PostgreSQL with Heroku

I am attempting to use a PostgreSQL database managed by Heroku in an ASP.NET MVC app running on .NET core 2.0. I would like to be able to use the Entity Framework to easily read and write to the database. I am extremely new to all of these things except for ASP.NET, which is likely obvious, and having previously used a local SQLite server for this same purpose, I have almost no understanding of how PostgreSQL works with Heroku and the Entity Framework.
I have installed the Npgsql extension to the Entity Framework. I am stuck at the Entity Framework's connection string for this particular setup and how to use it with Heroku. Heroku supplies a DATABASE_URL variable (documented here), which is necessary to use because the database connection credentials are subject to change and Heroku automatically updates the variable when they change.
//This method gets called by the runtime. Use this method to add services to
//the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
string connection = "???";
services.AddDbContext<MyDbContext>(options => options.UseNpgsql(connection));
}
What value do I use for connection such that it will connect to the database through Heroku's URL independently of the current credentials? Additionally, how can I ensure that a table will be created in the database matching MyDbContext's model?
My goal is simply to have a database accessible (read and write) from a deployed Heroku website. It would be nice if I could also access the database locally for development purposes, but my only requirement is that this work on the hosted website and that the database is managed by Heroku (I went with PostgreSQL, Kafka and Redis are also available through Heroku).
The solution here is to "parse" the content of the DATABASE_URLenvironment variable provided by Heroku and use it to build the connection string in the format that the Npgsql expects.
For a quick and dirty solution, you can just follow this solution: .net core - database url parser.
For my project I decided to go a little further and created a class for that, based in the other connection string builders (for MS SQL, Mongo and etc):
public enum SslMode
{
Require,
Disable,
Prefer
}
public class PostgreSqlConnectionStringBuilder : DbConnectionStringBuilder
{
private string _database;
private string _host;
private string _password;
private bool _pooling;
private int _port;
private string _username;
private bool _trustServerCertificate;
private SslMode _sslMode;
public PostgreSqlConnectionStringBuilder(string uriString)
{
ParseUri(uriString);
}
public string Database
{
get => _database;
set
{
base["database"] = value;
_database = value;
}
}
public string Host
{
get => _host;
set
{
base["host"] = value;
_host = value;
}
}
public string Password
{
get => _password;
set
{
base["password"] = value;
_password = value;
}
}
public bool Pooling
{
get => _pooling;
set
{
base["pooling"] = value;
_pooling = value;
}
}
public int Port
{
get => _port;
set
{
base["port"] = value;
_port = value;
}
}
public string Username
{
get => _username;
set
{
base["username"] = value;
_username = value;
}
}
public bool TrustServerCertificate
{
get => _trustServerCertificate;
set
{
base["trust server certificate"] = value;
_trustServerCertificate= value;
}
}
public SslMode SslMode
{
get => _sslMode;
set
{
base["ssl mode"] = value.ToString();
_sslMode = value;
}
}
public override object this[string keyword]
{
get
{
if (keyword == null) throw new ArgumentNullException(nameof(keyword));
return base[keyword.ToLower()];
}
set
{
if (keyword == null) throw new ArgumentNullException(nameof(keyword));
switch (keyword.ToLower())
{
case "host":
Host = (string) value;
break;
case "port":
Port = Convert.ToInt32(value);
break;
case "database":
Database = (string) value;
break;
case "username":
Username = (string) value;
break;
case "password":
Password = (string) value;
break;
case "pooling":
Pooling = Convert.ToBoolean(value);
break;
case "trust server certificate":
TrustServerCertificate = Convert.ToBoolean(value);
break;
case "sslmode":
SslMode = (SslMode) value;
break;
default:
throw new ArgumentException(string.Format("Invalid keyword '{0}'.", keyword));
}
}
}
public override bool ContainsKey(string keyword)
{
return base.ContainsKey(keyword.ToLower());
}
private void ParseUri(string uriString)
{
var isUri = Uri.TryCreate(uriString, UriKind.Absolute, out var uri);
if (!isUri) throw new FormatException(string.Format("'{0}' is not a valid URI.", uriString));
Host = uri.Host;
Port = uri.Port;
Database = uri.LocalPath.Substring(1);
Username = uri.UserInfo.Split(':')[0];
Password = uri.UserInfo.Split(':')[1];
}
}
And then, in my Startup.cs, in the Configuration method, I have:
var builder = new PostgreSqlConnectionStringBuilder(Configuration["DATABASE_URL"])
{
Pooling = true,
TrustServerCertificate = true,
SslMode = SslMode.Require
};
services.AddEntityFrameworkNpgsql()
.AddDbContext<TTRDbContext>(options => options.UseNpgsql(builder.ConnectionString));
If you are accessing your DB from outside Heroku network (e.g. your local environment), you need to add the SSL Mode and Trust Server Certificate.
Hope it helps

How to retrieve Membership's PasswordAnswer

It is encypted in the table. I don't want to reset the password.
I got a solution at here
But I am not sure the namespace of
base.DecryptPassword
Because I got an error, can not find it.
Updated again:
updated my code:
public class FalseMembershipProvider: MembershipProvider
{
public string GetPasswordAnswer(Guid providerUserKey)
{
Microsoft.Practices.EnterpriseLibrary.Data.Database db = Microsoft.Practices.EnterpriseLibrary.Data.DatabaseFactory.CreateDatabase();
using (System.Data.Common.DbCommand cmd = db.GetSqlStringCommand("SELECT PasswordAnswer FROM aspnet_Membership WHERE UserID=#UserID"))
{
db.AddInParameter(cmd, "#UserId", DbType.Guid, providerUserKey);
object answer = db.ExecuteScalar(cmd); if (answer != null)
return ProviderDecryptor(answer.ToString());
else
return null;
}
db = null;
}
internal string ProviderDecryptor(string encryptedText)
{
string decrypted = null;
if (!string.IsNullOrEmpty(encryptedText))
{
byte[] encodedbytes = Convert.FromBase64String(encryptedText);
byte[] decryptedbytes = base.DecryptPassword(encodedbytes);
if (decryptedbytes != null)
decrypted = System.Text.Encoding.Unicode.GetString(decryptedbytes, 16, decryptedbytes.Length - 16);
}
return decrypted;
}
}
The class is inheriting from the MembershipProvider class. The method being called is MembershipProvider.DecryptPassword. However, as you can see on the MSDN page, it's a protected method. By inherting from MembershipProvider, this new class can use base.DecryptPassword which is essentially saying "call the DecryptPassword method of the MembershipProvider. Even though the method is protected, I can call it because I have permission since I'm inheriting from the MembershipProvider class".
The class you're writing needs to inherit from MembershipProvider as the author did in their example:
public class FalseMembershipProvider : MembershipProvider

Storing connection in a static class (ASP.NET)

Since I'm using Postgresql and can't use LINQ to SQL, I wrote my own wrapper classes.
This is a part of the Student class:
public class Student : User
{
private static NpgsqlConnection connection = null;
private const string TABLE_NAME = "students";
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
/// <summary>
/// Reads data from the data reader and moves it to the Student class.
/// </summary>
private static void ReadFields(Student student, NpgsqlDataReader dr)
{
student.Id = Int32.Parse(dr["id"].ToString());
student.FirstName = dr["first_name"].ToString();
student.LastName = dr["last_name"].ToString();
student.Password = dr["password"].ToString();
}
/// <summary>
/// Updates the student
/// </summary>
public void Update()
{
Connect();
Run(String.Format("UPDATE " + TABLE_NAME + " SET first_name='{0}', last_name='{1}', password='{2}' WHERE id={3}", FirstName, LastName, Password, Id));
connection.Dispose();
}
/// <summary>
/// Inserts a new student
/// </summary>
public void Insert()
{
Connect();
Run(String.Format("INSERT INTO " + TABLE_NAME + " (first_name, last_name, password) VALUES ('{0}', '{1}', '{2}')",FirstName, LastName, Password));
connection.Dispose();
}
private static void Run(string queryString)
{
NpgsqlCommand cmd = new NpgsqlCommand(queryString, connection);
cmd.ExecuteScalar();
cmd.Dispose();
}
private static void Connect()
{
connection = new NpgsqlConnection(String.Format("Server=localhost;Database=db;Uid=uid;Password=pass;pooling=false"));
connection.Open();
}
//....
So as you see with every INSERT, DELETE, UPDATE request I'm using Connect() method which connects to the database. I didn't realize how stupid it was before I had to wait for 10 minutes to have 500 rows inserted, as there were 500 connections to the database.
So I decided to move Connection property to a static DB class.
public static class DB
{
private static NpgsqlConnection connection = null;
public static NpgsqlConnection Connection
{
get
{
if (connection == null)
{
connection = new NpgsqlConnection(String.Format("Server=localhost;Database=db;Uid=uid;Password=pass;pooling=false"));
connection.Open();
}
return connection;
}
}
public static void Run(string queryString)
{
NpgsqlCommand cmd = new NpgsqlCommand(queryString, connection);
cmd.ExecuteScalar();
cmd.Dispose();
}
}
It works now! I replaces all Run methods in the Student class with DB.Run
But I want to know if it will work fine with a lot of people online, not me only. I'm not sure how static things work with ASP.NET, maybe it'll eat a lot of memory?..
It is better not to store the connection in a static field. Create the connection object on demand and let the connection pooling manage your connections.
You can enable connection pooling for PostgreSQL and let the pooler manage connections for you. Then you can use either piece of code without worry. Even when you issue multiple open/close commands the pooler will optimize them.
This provides you more flexibility and less worry about a custom management solution, also less code and edge cases. It will depend on the database provider you're using. Something in the connection string like:
Pooling: True or False. Controls
whether connection pooling is used.
Default = True
If you need a database provider that uses connection pooling for Postgres one option is npgsql: Npgsql is a .Net data provider for Postgresql.
It supports connection pooling as described in the docs.
Static classes are singletons. The danger here is what they reference. Because they always stay alive, everything they keep a reference to will not be garbage collected.
To see if this is the case, profile your web servers memory. If it always grows and never shrinks, you may be constantly adding references in a static class which never get collected.
In all honesty though, I'd create it only as needed, and completely avoid all of this.
EDIT:
I mean don't worry about sharing one single connection object across your data access layer. If the provider you're using supports connection pooling, then it will handle the actual connections made to the database. Just use and dispose of your connection objects as needed at any point in your data access layer.
using (var connection = new NpgsqlConnection("your connection string"))
{
//your data access stuff.
}
I know code like this is rather big, bulky, and repetitive, but that's ADO.NET. As long as you isolate these calls in their own classes by creating a data access library/layer, it's very manageable. Hiding the ADO.NET objects in a static class is dangerous, because you'll inevitably forget to close a connection or call Dispose() somewhere. Plus you run the risk of building a large object graph that will never get garbage collected.
public class Dataconnect
{
public static string connstring = ConfigurationSettings.AppSettings["SQLConnection"].ToString();
SqlConnection objcon = new SqlConnection(connstring);
SqlCommand objcmd = new SqlCommand();
public bool Opencon()
{
try {
if (objcon.State == ConnectionState.Closed)
{
objcon.Open();
}
objcmd.Connection = objcon;
return true;
}
catch (Exception ex) { throw new Exception("Error: In Open connesction"); return false; }
}
public bool Closecon()
{
try
{
if (objcon.State == ConnectionState.Open)
{
objcon.Close();
}
objcmd.Dispose();
return true;
}
catch (Exception ex) { throw new Exception("Error: In Close connesction"); return false; }
}
public static int ExecuteQuery(SqlCommand sqlcmd)
{
try
{
Dataconnect objdc = new Dataconnect();
int affectedrecord = 0;
if (objdc.Opencon() == true)
{
sqlcmd.Connection = objdc.objcon;
affectedrecord = sqlcmd.ExecuteNonQuery();
objdc.Closecon();
objdc = null;
return affectedrecord;
}
else { return affectedrecord; }
}
catch (Exception ex) { throw ex;/* new Exception("Error: In ExecuteNonquery");*/ }
}
public static DataTable Generatedatatable(SqlCommand sqlcmd)
{
try { Dataconnect objdc = new Dataconnect();
if (objdc.Opencon() == true)
{
sqlcmd.Connection = objdc.objcon;
SqlDataReader dr;
DataTable objdt = new DataTable();
dr = sqlcmd.ExecuteReader();
objdt.Load(dr);
objdc.Closecon();
objdc = null;
return objdt;
}
else { return null; }
}
catch (Exception Exception) { throw Exception /*new Exception("Error: In Generatedatatable")*/; }
}

AuthorizationManager based on service invocation parameters

I'm currently developing my own AuthorizationManager, it looks something like that:
public class MyAuthorizationManager : ServiceAuthorizationManager
{
static bool initialize = false;
public override bool CheckAccess(OperationContext operationContext)
{
ServiceSecurityContext context = ServiceSecurityContext.Current;
string[] roles = Roles.GetRolesForUser(operationContext.ServiceSecurityContext.PrimaryIdentity.Name);
return roles.Count() > 0;
}
public override bool CheckAccess(OperationContext operationContext, ref System.ServiceModel.Channels.Message message)
{
MessageBuffer buffer = operationContext.RequestContext.RequestMessage.CreateBufferedCopy(int.MaxValue);
message = buffer.CreateMessage();
Console.WriteLine(message);
return base.CheckAccess(operationContext, ref message);
}
}
I would like to perform authorization check based on a service contract parameter, in example, if contract looks like:
[ServiceContract]
public interface IServerContract
{
[OperationContract]
[ServiceKnownType(typeof(ChildTypeOne))]
[ServiceKnownType(typeof(ChildTypeTwo))]
string SecuredMessage(ParentType incoming);
}
My goal is authorizing depending on type, in example, authorizing if incoming date is ChildTypeOne and deniying in case it was ChildTypeTwo.
I've checked "Message" and it looks like:
It must be decrypted
Seems to be highly dependent on binding
Is there any easy way to simply get parameter type?
Ok, i've figured out how to perform that. Anyway, if you know any better way to do so, let me know:
Here is the AuthorizationManager i'm using:
public class MyAuthorizationManager : ServiceAuthorizationManager
{
static bool initialize = false;
public override bool CheckAccess(OperationContext operationContext, ref System.ServiceModel.Channels.Message message)
{
bool returnedValue = base.CheckAccess(operationContext, ref message);
// messags in WCF are always read-once
// we create one copy to work with, and one copy to return back to the plumbing
MessageBuffer buffer = operationContext.RequestContext.RequestMessage.CreateBufferedCopy(int.MaxValue);
message = buffer.CreateMessage();
// get the username vale using XPath
XPathNavigator nav = buffer.CreateNavigator();
StandardNamespaceManager nsm = new StandardNamespaceManager(nav.NameTable);
nav = nav.SelectSingleNode("//#i:type",nsm);
returnedValue &= (nav.ToString() == "a:"+typeof(ChildTypeOne).Name);
return returnedValue;
}
public class StandardNamespaceManager : XmlNamespaceManager
{
public StandardNamespaceManager(XmlNameTable nameTable)
: base(nameTable)
{
this.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");
this.AddNamespace("s11", "http://schemas.xmlsoap.org/soap/envelope/");
this.AddNamespace("s12", "http://www.w3.org/2003/05/soap-envelope");
this.AddNamespace("wsaAugust2004", "http://schemas.xmlsoap.org/ws/2004/08/addressing");
this.AddNamespace("wsa10", "http://www.w3.org/2005/08/addressing");
this.AddNamespace("i", "http://www.w3.org/2001/XMLSchema-instance");
}
}
}
Previous AuthorizationManager will work rejecting "ChildTypeTwo". You can use a RoleProvider in order to get role based on type.

Resources