dynamically updating connection string - MVC - c#

My requirement is, on the first time loading the application i want to fetch information about connection string from a database and next time onward's connect using the new connection string (which is fetched from the db)
is this possible in .net.? The connection string is written in web.config file
do I need to restart IIS whenever the web.config changes?
I tried this:
public ActionResult Index()
{
UpdateSetting("test", "123");
UpdateConnectionString("testcon", "12345");
return View();
}
/// <summary>
/// Updates the setting.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public void UpdateSetting(string key, string value)
{
Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
if (config.AppSettings.Settings[key] == null)
{
config.AppSettings.Settings.Add(key, value);
}
else
{
config.AppSettings.Settings[key].Value = value;
}
config.Save();
ConfigurationManager.RefreshSection("appSettings");
}
/// <summary>
/// Updates the connection string.
/// </summary>
/// <param name="key">The key.</param>
/// <param name="value">The value.</param>
public void UpdateConnectionString(string key, string value)
{
Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
if (config.ConnectionStrings.ConnectionStrings[key] == null)
{
config.ConnectionStrings.ConnectionStrings.Add(new ConnectionStringSettings(key, value));
}
else
{
config.ConnectionStrings.ConnectionStrings[key].ConnectionString = value;
}
config.Save();
ConfigurationManager.RefreshSection("connectionStrings");
}
This function will add a new connection string but is there any other method so that i don't want to restart the application?

The application setting is static and should not be modified in the runtime. I don't know why you have to store the connection in the config file, it doesn't make sense. Try another solution, update the setting by a script before start or store the setting in another or just retrieve every time.

There are multiple options to achieve this.
If you're using DI, you can register the connection string factory as a singleton, and then just try to get connection string wherever you'd like. It'll fetch it only once for the application.
Update your UpdateConnectionString method to cache the retrieved value in some static variable (not a great way to do it, though) and then, and check the cache before retrieving the value. If cache is not null, use its value.

Related

autofac and owned instances

I have been reasing about owned instances and I have a need to set one up.
http://docs.autofac.org/en/latest/advanced/owned-instances.html
I have 2 methods in the same class that use this owned instance. I have set it up like this:
private readonly Func<SessionDetails, Owned<ITroposUnitOfWork>> _paramatizedTroposUnitOfWork;
My unit of work class constructor looks like this:
/// <summary>
/// Used for creating manual sessions
/// </summary>
/// <param name="sessionDetails">The details of the session to be created</param>
public TroposUnitOfWork(SessionDetails sessionDetails)
{
// Throw if we don't supply any details
ThrowIf.ArgumentIsNull(() => sessionDetails);
// Start the session
StartSession(sessionDetails);
}
So, my understanding is that if I use a using block, then the unit of work will be disposed of at the end of the call. But it isn't.
Like I mentioned before, I have 2 methods that use this owned instance. They are:
/// <summary>
/// Creates the Tropos user
/// </summary>
/// <param name="model">The user to be created</param>
/// <param name="password">The password to set</param>
private async Task CreateTroposUserAsync(User model, string password)
{
// If there is no password, throw an error
ThrowIf.ArgumentIsNull(() => password);
// Get our master user
var user = await base.FindByNameAsync(model.Master);
// If we have no master user, throw an error
if (user == null) throw new ObjectNotFoundException();
// Create our session details
var sessionDetails = _troposSession.Value.Create(user);
// User our new user
using (var troposUnitOfWork = _paramatizedTroposUnitOfWork(sessionDetails))
{
try
{
// Create our tropos user service
var userService = new TroposUserService(troposUnitOfWork.Value);
// Create our user
var transaction = userService.Create(model);
// Save our changes (Don't throw an error if the user already exists)
troposUnitOfWork.Value.RunTransaction(transaction);
} catch (Exception ex)
{
// Display human readable messages
throw new Exception(ex.Message);
}
}
// Sets the new users password
SetTroposPassword(model, password);
// Update the flag
model.HasTroposLogin = true;
}
And the other one is:
/// <summary>
/// Sets the tropos password
/// </summary>
/// <param name="model">The user that needs the password setting</param>
/// <param name="password"></param>
private void SetTroposPassword(User model, string password)
{
// Create our session details
var sessionDetails = _troposSession.Value.Create(model.UserName);
// Create our anonymous session
using (var troposUnitOfWork = _paramatizedTroposUnitOfWork(sessionDetails))
{
// Create our tropos user service
var userService = new TroposUserService(troposUnitOfWork.Value);
// Set our password
var transaction = userService.ChangePassword(password);
// Save our changes
troposUnitOfWork.Value.RunTransaction(transaction);
}
}
The first method does invoke the second method, but outside the using block. I put a breakpoint in the TroposUnitOfWork dispose method and it only gets hit once. The constructor is only hit once too.
Does anyone know why?
We need to see the initialization of _paramatizedTroposUnitOfWork.
What class has the CreateTroposUserAsync method? We need to see the constructor of that class. I suppose your overall goal is to get a unit of work implementation.
The reason why you only hit constructor once, might be due to the lifetime you used when registering. If its Owned. Then the two methods probably execute in the same lifetime scope and the dependency is only resolved once. Or put differently the _paramatizedTroposUnitOfWork(sessionDetails) returns the same instance.
I've solved similar problem using decorators and factories
public interface IEventHandlerFactory<in TNotification> where TNotification
: class, IAsyncNotification
{
IAsyncNotificationHandler<TNotification> Create( ILifetimeScope
lifetimeScope );
}
public class EventHandlerFactory<TNotification, TEventHandler> :
IEventHandlerFactory<TNotification>
where TNotification : class, IAsyncNotification
where TEventHandler : class, IAsyncNotificationHandler<TNotification>
{
public IAsyncNotificationHandler<TNotification> Create( ILifetimeScope
lifetimeScope )
{
return lifetimeScope.ResolveNamed<TEventHandler>( "EventHandler" )
as IAsyncNotificationHandler<TNotification>;
}
}
full .net fiddle is here https://dotnetfiddle.net/fw4IBw

Variable does not exist in current context directly after creating it

I have the following class:
/// <summary>
/// Represents an implementation of the <see cref="IAspNetCoreLoggingConfigurationBuilder"/> to configure the ASP.NET Core Logging.
/// </summary>
public class AspNetCoreLoggingConfigurationBuilder : IAspNetCoreLoggingConfigurationBuilder
{
#region Properties
/// <summary>
/// Gets the <see cref="ILogSource"/> that's used to write log entries.
/// </summary>
public ILogSource LogSource{ get; private set; }
#endregion
#region IAspNetCoreLoggingConfigurationBuilder Members
/// <summary>
/// Sets the log source that should be used to save log entries.
/// </summary>
/// <param name="logSource">The source </param>
public void SetLogSource(ILogSource logSource)
{
LogSource = logSource;
}
#endregion
}
I also have a method in which I create an instance of this class:
/// <summary>
/// Adds logging to the <see cref="IApplicationBuilder"/> request execution pipeline.
/// </summary>
/// <param name="app">The <see cref="IApplicationBuilder"/> to configure the application's request pipeline.</param>
/// <param name="configuration">Builder used to configure the ASP.NET Core Logging.</param>
/// <returns>A reference to this instance after the operation has completed.</returns>
public static IApplicationBuilder UseAspNetCoreLogging(this IApplicationBuilder app, Action<IAspNetCoreLoggingConfigurationBuilder> configuration)
{
var aspNetLoggerConfiguration = new AspNetCoreLoggingConfigurationBuilder();
configuration(aspNetLoggerConfiguration);
// Add the registered ILogSource into the registered services.
_services.AddInstance(typeof (ILogSource), aspNetLoggerConfiguration.LogSource);
// The entire configuration for the middleware has been done, so return the middleware.
return app.UseMiddleware<AspNetCoreLoggingMiddleware>();
}
Notice the first line here, I'm creating an instance of the class.
However, when I inspect this variable in a watch, when my cursor is on line configuration(aspNetLoggerConfiguration); I do get that the variable does not exists in the current context.
Creating an instance of the variable does work when doing it directly in the watch window.
Anyone has a clue?
P.S. It's a DNX project which I'm testing in xUnit. The code is running in 'Debug' mode.
Thats no runtime and no compiling-error.
It's a problem of Visual Studio not beeing able to show the object in a debug-window as it is a runtime-object (something like that).
Another occurence of this problem is in a wcf-service client. Create a new serviceclient Client and try to show client.InnerChannel in the watch window. It won't work. You can however create a temp-object (bool, string, etc..) and write the desired value into it to see your value.
#if DEBUG
var tmpLog = aspNetLoggerConfiguration.LogSource;
#endif
You should see the LogSource in the tmpLog when your mouse is over it.

Hide a QueryString parameters, how?

I have a url: like this one: http://www.example/about/49.
I want it to be seen as http://www.example/about/, but I must have this parameters passed as QueryString parameters.
Is it possible ?
Be careful with session variables; it's easy to have multiple pages opened which are all using the same session and end up mixing the values.
It would be better to use TempData, which only allows the value to be used once (removed on first access). However, this implies the value will be used almost immediately.
You can also write a cookie with the desired value, intercept the request (ASP.Net provides a variety of ways of doing this, such as the BeginRequest event), and internally process the URL as though it contained the value.
Of course, you then must cleanup the cookie (which will have the same problem as a Session-based solution). Remember that a cookie is more vulnerable to tampering on the client.
Personally, I think any of these approaches are far more trouble than they are worth. "Hackable URLs" (such as those which contain a potentially meaningful ID) are usually a good thing.
My workaround for this (Which works REALLY well, thanks to the help of the SO Community)
Create a class called SiteSession.cs
Input the following code:
using System;
using System.Collections.Generic;
using System.Web;
/// <summary>
/// Summary description for SiteSession
/// </summary>
public class SiteSession
{
/// <summary>
/// The _site session
/// </summary>
private const string _siteSession = "__SiteSession__";
/// <summary>
/// Prevents a default instance of the <see cref="SiteSession" /> class from being created.
/// </summary>
private SiteSession()
{
}
/// <summary>
/// Gets the current Session
/// </summary>
/// <value>The current.</value>
public static SiteSession Current
{
get
{
SiteSession session = new SiteSession();
try
{
session = HttpContext.Current.Session[_siteSession] as SiteSession;
}
catch(NullReferenceException asp)
{
}
if (session == null)
{
session = new SiteSession();
HttpContext.Current.Session[_siteSession] = session;
}
return session;
}
}
//Session properties
public int PageNumber {get;set;}
}
You can put anything in the Session Properties, just make sure its public.
Then, set it by:
SiteSession.Current.PageNumber = 42
And call it with
int whatever = SiteSession.Current.PageNumber

With MVC 2, how do I stop one app logout from logging out the user in a second app?

In VS2010 I have two MVC 2 based web apps within the same solution that also share a common Setup project. One app is a configuration utility for setting up users and variables in the opposing app. Upon installation, the two IIS directories look like this on the user's browser:
App1: http://localhost/App1/Auth/Login
App2: http://localhost/App1/App2/Auth/Login
The problem I'm having is when the user has both apps open at the same time, and logs out of one of them they are also logged out of the opposing app. This is a minor issue, but I've been tasked with correcting it.
From what I can tell, the two apps must be sharing the same Session object, because the logout command method in each controller invokes Session.Abandon() .
Only two controllers have the ability to log out a user; here's the constructor's from those controller's:
App1: namespace App1.Controllers
/// <summary>
/// Functionality related to Assets
/// </summary>
public class AssetsController : Controller
{
private IConfig _config = null;
private IProfileRepository _profiles = null;
private IInspectionRepository _inspections = null;
private ICustomLabelsFactory _labels = null;
private IValidateRepository _validator = null;
/// <summary>
/// Create an instance of the AssetsController which uses the db.
/// </summary>
public AssetsController() : this(Config.Current, new ProfileRepository(Config.Current), new InspectionRepository(), new CustomLabelFactory(), new ValidateRepository()) { }
/// <summary>
/// Create an instance of the AssetsController with the given
/// IInspectionRepository implementation.
/// </summary>
/// <param name="inspections">IInspectionRepository implementation.</param>
public AssetsController(IConfig config, IProfileRepository profiles, IInspectionRepository inspections, ICustomLabelsFactory labels, IValidateRepository validator)
: base()
{
ViewData["_Module"] = "Assets";
_config = config;
_profiles = profiles;
_profiles.ModelState = ModelState;
_inspections = inspections;
_inspections.ModelState = ModelState;
_labels = labels;
_labels.ModelState = ModelState;
_validator = validator;
_validator.CustomLabels = _labels.Assets;
_validator.ModelState = ModelState;
}
App2: namespace App1.App2.Controllers
/// <summary>
/// Handles login/logout functionality
/// </summary>
public class AuthController : Controller
{
private ILoginService _login;
private IUtilityRepository _utility;
/// <summary>
/// Creates the Auth controller using the default User Repository which
/// uses the database.
/// </summary>
public AuthController() : this(new LoginService(), new UtilityRepository()) { }
/// <summary>
/// Creates the Auth controller with the given User Repository.
/// </summary>
/// <param name="userRepository">IUserRepository implementation.</param>
public AuthController(ILoginService loginService, IUtilityRepository utility)
: base()
{
ViewData["_Module"] = "Login";
_login = loginService;
_login.ModelState = ModelState;
_utility = utility;
_utility.ModelState = ModelState;
}
I might be barking up the wrong tree on where to start looking at the code, but I'm hoping someone can see something obvious here that I can't. Or, maybe someone can tell me how to do this differently so there is not a shared Session object involved. I've been working on this on and off for the better part of this week, so any help offered will be greatly appreciated.
You could configure each application to use a different session database in your web.config
EDIT: something like
<sessionState mode="SQLServer" sqlConnectionString="Data Source=.\SQLEXPRESS;User Id=test;Password=test;Application Name=AppName" />
<machineKey
validationKey="SOMEKEY"
validation="SHA1" decryption="AES"
/>
Where somekey is different for each application
A simple, lazy, IIS settings avoiding solution is to open each in a different browser.

Entity Framework 4.1 - EFTracingProvider

Is there a way to make the EFTracing provider work with EF 4.1?
EFTracing seems to need an objectcontext and I use dbcontext.
Thanks in advance!
Yes, you can. I'm using the community version with both database-first DbContexts and code-first DbContexts. This answer is based on a discussion thread on the project site.
For database-first/designer DbContexts (via ADO.NET DbContext Generator templates), you can simply add the following constructor:
public abstract class MyDbContext : DbContext
{
protected MyDbContext(string nameOrConnectionString)
: base(EFTracingProviderUtils.CreateTracedEntityConnection(nameOrConnectionString), true)
{
// enable sql tracing
((IObjectContextAdapter) this).ObjectContext.EnableTracing();
}
}
For code first DbContexts its a bit more complicated since the EFTracingProvider wants a full entity connection string. You have to create an instance of EFTracingConnection manually. The following example will work for both database first and code first contexts.
public abstract class MyDbContext : DbContext
{
protected MyDbContext(string nameOrConnectionString)
: base(CreateTracingConnection(nameOrConnectionString), true)
{
// enable sql tracing
((IObjectContextAdapter) this).ObjectContext.EnableTracing();
}
private static DbConnection CreateTracingConnection(string nameOrConnectionString)
{
try
{
// this only supports entity connection strings http://msdn.microsoft.com/en-us/library/cc716756.aspx
return EFTracingProviderUtils.CreateTracedEntityConnection(nameOrConnectionString);
}
catch (ArgumentException)
{
// an invalid entity connection string is assumed to be a normal connection string name or connection string (Code First)
ConnectionStringSettings connectionStringSetting =
ConfigurationManager.ConnectionStrings[nameOrConnectionString];
string connectionString;
string providerName;
if (connectionStringSetting != null)
{
connectionString = connectionStringSetting.ConnectionString;
providerName = connectionStringSetting.ProviderName;
}
else
{
providerName = "System.Data.SqlClient";
connectionString = nameOrConnectionString;
}
return CreateTracingConnection(connectionString, providerName);
}
}
private static EFTracingConnection CreateTracingConnection(string connectionString, string providerInvariantName)
{
// based on the example at http://jkowalski.com/2010/04/23/logging-sql-statements-in-entity-frameworkcode-first/
string wrapperConnectionString =
String.Format(#"wrappedProvider={0};{1}", providerInvariantName, connectionString);
EFTracingConnection connection =
new EFTracingConnection
{
ConnectionString = wrapperConnectionString
};
return connection;
}
}
Whilst the previous answers work, I've found them problematic, a much simpler solution is to use the Clutch.Diagnostics.EntityFramework package from NuGet that uses MiniProfiler behind the scenes. It is significantly simpler to get working than EFTracingProvider, and a much more flexible solution.
The project is on GitHub at https://github.com/Kukkimonsuta/Clutch
For EFTracingProvider like functionality install the NuGet package and then implement IDbTracingListener like this:
using System;
using System.Data.Common;
using System.Diagnostics;
using Clutch.Diagnostics.EntityFramework;
/// <summary>
///
/// </summary>
public class DbTracingListener : IDbTracingListener
{
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="command"></param>
/// <param name="result"></param>
/// <param name="duration"></param>
public void CommandExecuted(DbConnection connection, DbCommand command, object result, TimeSpan duration)
{
Debug.WriteLine(command.CommandText);
Debug.WriteLine(string.Format("Executed in: {0}", duration));
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="command"></param>
public void CommandExecuting(DbConnection connection, DbCommand command)
{
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="command"></param>
/// <param name="exception"></param>
/// <param name="duration"></param>
public void CommandFailed(DbConnection connection, DbCommand command, Exception exception, TimeSpan duration)
{
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="command"></param>
/// <param name="result"></param>
/// <param name="duration"></param>
public void CommandFinished(DbConnection connection, DbCommand command, object result, TimeSpan duration)
{
}
}
If you are using DBContext and MVC Model First, meaning using EntityConnections then the following sample code should be all you need:
public partial class BrickHouseFitnessContext : DbContext
{
public BrickHouseFitnessContext(): base(EntityConnectionWrapperUtils.CreateEntityConnectionWithWrappers(ConfigurationManager.ConnectionStrings["BrickHouseFitnessContext"].ConnectionString, "EFTracingProvider"), true)
{
}
Also:
In the Web.Config file add the following sections:
<system.data>
<DbProviderFactories>
<add name="EF Tracing Data Provider" invariant="EFTracingProvider" description="Tracing Provider Wrapper" type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
<add name="EF Generic Provider Wrapper" invariant="EFProviderWrapper" description="Generic Provider Wrapper" type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit, Version=1.0.0.0, Culture=neutral, PublicKeyToken=def642f226e0e59b" />
</DbProviderFactories>
and:
<add key="EFTracingProvider.logToConsole" value="true" />
<add key="EFTracingProvider.logToFile" value="C:\BrickHouseFitnessSqlLog.txt" />
There is no need to include the ExtendedEntities or the other ObjectContext derived class mentioned in the original article. Run that code and you should see your log file as specified, with all the SQL commands in it. I am bypassing database intialization when tracing is enabled,

Categories

Resources