What is the best way to get Connection String from Web.config files. I know it can be used in Global.asax in App_start
public class Global : System.Web.HttpApplication
{
public static
readonly string ConnectionString = "connection information";
. . .
}
But, how to you get the static variable in Multiple Assemblies.
Let say i have 4 assemblies for my web application ( UI, Service Layer, Business Layer, Data Layer ) and i want access to DataLayer (which is a separate assembly),
I don't want to put the config reading in Datalayer Constructor.
I wanted to use the HttpApplictionvariable / static variable to read the connection string value in Datalayer.
Any suggestions ?
You could create a contract for your settings:
public IApplicationSettings
{
string ConnectionString { get; }
// any other setting variable
}
And than use this abstraction in your code
public class MyRepository
{
private string conncetionString;
public MyRepository(IApplicationSettings settings)
{
this.conncetionString = settings.ConnectionString;
}
}
In this way you will hide any dependency to stuff like ConfigurationManager and the way how you storing settings in app. If your are using IoC, you will have control on instance life time.
Related
I'm working on multitenant application (ASP.NET 5 + EF7). Each tenant will have separate database. I will have one separate database for tenant account data. I have registered service for EF in startup class for this separate database. I have problem with migrations. I cant create EF migration, until tenantDbContext is registered as service with specific connection string. But this conection string must be dynamic for each tenant... Any idea please? What is the best option to manage DbContexts for tenants?
Future edit - protected override void OnConfiguring was the key how to do: Is this good solution please?
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<TenantDbContext>();
public class TenantDbContext : IdentityDbContext<ApplicationUser>
{
public TenantDbContext() //development database with no connectionString in constructor
{
this._connectionString = "Connection String";
}
public TenantDbContext(string ConnectionString)
{
this._connectionString = ConnectionString;
}
private string _connectionString { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
...etc
As I mentioned in comments I have not tried multi-tenant/multi-db myself but try the following:
You can use DbContext CreateIfNotExists() method. https://msdn.microsoft.com/en-us/library/system.data.entity.database.createifnotexists(v=vs.113).aspx
If you have a Migrations/Configuration.cs you can set AutomaticMigrationsEnabled property to false
Setting the initializer off is probably needed as well: Database.SetInitializer<DatabaseContext>(null);
Sorry without knowing more details like workflow of creating a new tenant (automatic from DB or is a screen filled out with the connection string and name etc.) I can't make more detailed suggestions. I would suggest that your data layer be quite abstracted from the context. It seems like a bad idea for developers to have to select the correct context. Hence the use of a factory.
An option is always requiring a tenant id to be passed into all service or repository methods. I'm guessing this would be in some kind of user claim available in the controller.
We are using classes inheriting from Registry to configure our StructureMap container in our ASP.NET MVC 4 application startup.
Some excerpt from one of the registry-classes:
For<ISomeInterface>().HybridHttpOrThreadLocalScoped().Use<SomeImplementation>();
We would like use different instances of our interfaces depending on the context. (For example switching from database "online" mode to "maintenance" mode where everything is saved on filesystem; therefore using other interfaces (i.e. repositories) all over the place in our application)
For example by default it should use SomeImplementation but when passing some kind of querystring in the url (to name a simple "context" scenario) it should use SomeOtherImplementation.
How can this be achieved for multiple interfaces/types?
Should we use named instances for this? Like:
For<ISomeInterface>().HybridHttpOrThreadLocalScoped().Use<SomeOtherImplementation>().Named("other");
I read about StructureMap Profiles but i'm not sure if this is the right way to go.
Should we use profiles for this? Like i.e.:
Profile("other", profileExpression =>
{
For<ISomeInterface>().HybridHttpOrThreadLocalScoped().Use<SomeOtherImplementation>();
});
How can we switch different configurations on the fly?
ObjectFactory.Container.SetDefaultsToProfile("other");
This way? (At what stage in mvc "life-cycle" this can happen at the earliest?)
Can this be a temporary switch for just the current request or current users session?
Thanks in advance!
From my experience, runtime configuration like this is best achieved using an abstract factory that is responsible for creating your dependency during runtime.
This dependency can then be registered with StructureMap like so:
Your registry:
public class StorageRegistry : Registry
{
public StorageRegistry()
{
...
this.For<IDataStoreInstance>().Use(ctx => ctx.GetInstance<DataStoreAbstractFactory>().ConfigureStorage());
...
}
}
Now your DataStoreAbstractFactory is responsible for creating and configure the necessary storage instance based on your configuration. As DataStoreAbstractFactory is now registered with StructureMap you're able to inject the necessary dependencies into it for determining which storage method to use.
Implementation example:
public class DataStoreAbstractFactory
{
public DataStoreAbstractFactory()
{
// Dependencies to figure out data storage method can be injected here.
}
public IDataStoreInstance ConfigureStorage()
{
// This method can be used to return type of storage based on your configuration (ie: online or maintenance)
}
}
public interface IDataStoreInstance
{
void Save();
}
public class DatabaseStorage : IDataStoreInstance
{
public void Save()
{
// Implementation details of persisting data in a database
}
}
public class FileStorage : IDataStoreInstance
{
public void Save()
{
// Implementation details of persisting data in a file system
}
}
Usage:
Your controller/services or whatever are now completely unaware of what storage method they're using when accessing and persisting data.
public class UpdateController : Controller
{
public IDataStoreInstance StorageInstance { get; set; }
public UpdateController(IDataStoreInstance storageInstance)
{
StorageInstance = storageInstance;
}
[HttpPost]
public ActionResult Index()
{
...
this.StorageInstance.Save();
...
}
...
}
To avoid web service's problem of not being able to pass complex objects like dictionaries and trees, I created a small struct inside the class with a few values fields. However, the web service is in a seperate project in the solution and I'm unsure how the behind code that calls the webService function would know what the struct is. Should I copy the struct to the behind code file? Can I import it?
Here's a small example:
namespace mYWebService{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class Service1 : System.Web.Services.WebService
{
struct TreeData
{
private readonly string text;
private readonly string parent;
private string val;
public TreeData (string Text, string Parent)
{
this.text = Text;
this.parent = Parent;
this.val = "";
}
public TreeData (string Text, string Parent, string Value)
{
this.text = Text;
this.parent = Parent;
this.val = Value;
}
public string Text { get { return text; } }
public string Parent { get { return parent; } }
public string Value { get { return val; } }
}
[WebMethod]`
public TreeData getTree(){
TreeData myTree = new TreeData("1","2","3");
return myTree;
}}
When you generate the binding in the client code, all necessary complex data types will get created automatically, because they are described in the service's metadata. However, you should rather use WCF these days providing there's no hard requirement to use the old-fashioned .NET 2.0 web services (i.e. the WebService class).
You will have a hard time compiling this because you are exposing a private struct in a public method. In the very least, the struct must be made public. I also recommend that you put your struct outside of the class, since inner classes / structs /etc is bad practice (this is my personal opinion, however you do not see them used much in e.g. the .net framework, indicating that Microsoft doesn't like them much either).
Keep in mind that web services are distributed by nature, thus you should not have to rely on references to the class directly. This is a SOAP service (I think), and the framework will expose the metadata of the service. This metadata can be used by Visual Studio to auto generate a proxy client which can be used to call the service.
Here's a simple way to set up a proxy:
Start the web service project executable (not in debug mode, you will still need to be able to use Visual Studio for the next steps)
Select the project where your web service client (the code that calls the service) is located and add a service reference
This will open a dialog where you can enter the service endpoint (url). Enter the endpoint where the service is running, and you should be able to select in this dialog
Once the reference is added, some autogenerated proxy code should be generated for you. This will give you access to your Method.
Finally I do agree with Ondrej Tucny that you should look into WCF instead
I need to store 2 sections of settings in app.config and based on the value passed when initialising the class I will load one of the sections of settings.
This is what I need to achieve ideally:
Class
Public Class SiteSettings
Sub New(ByVal Id As Integer)
If Id = 1 Then
'Load in group1 settings.
'Ideally the settings will be available as properties
Else
'Load in group2 settings
End If
End Sub
...
End Class
Code
Dim objSettings = New SiteSettings(Id)
'just to demo what I'm trying to achieve
response.Write(objSettings.setting1)
App.config
<siteSettings>
<section name="group1">
<setting1 value="abc" />
</section>
<section name="group2">
<setting1 value="xyz" />
</section>
</siteSettings>
It shouldn't be hard to read in your own settings. There is a lot of code out there for reading custom config settings - just look at the links under "Related" on this page. If your settings object is serializable, you can retrieve an instance from app.config, using custom settings support.
If you want to instantiate an object and encapsulate all the settings-reading logic in the constructor, you'll probably have to write a wrapper for your actual custom config setting, sort of like this:
public interface ISettings
{
int Setting1 { get; set; }
}
[Serializable]
public class ActualSettings : ISettings
{
public int Setting1 { get;set;}
}
public class SettingsAdapter : ISettings
{
private ISettings settings;
public SettingsAdapter(int id)
{
if(id == 1)
settings = // code to retrieve instance #1 from app.config
else
settings = // code to retrieve instance #2 from app.config
}
public int Setting1 {
get { return settings.Setting1; }
set { settings.Setting1 = value; }
}
}
This may be beyond what is supported in the app.config file. However, you could certainly include your own xml file in the application directory and parse it with XPath to load your settings as you describe.
I have the following in my MVC Application:
namespace WebUx.Areas.User.Controllers
{
[Authorize]
[InitializeSimpleMembership]
public class AccountController : Controller
{
Plus:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
{
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Ensure ASP.NET Simple Membership is initialized only once per app start
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
System.Diagnostics.Debug.Write("Set Initializer\n");
Database.SetInitializer<UsersContext>(null);
try
{
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
// Create the SimpleMembership database without Entity Framework migration schema
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
I understand that when there's a call to the account controller then this will set the DB context but once this is set will it stay set for my application. What about later on for other users who connect. Will the DB context always be available?
The reason I am asking this is that I have other information that I want to store in a table and access with Web API. Should I code in something similar for these controllers so that each time I check that there's a DB context available or could I just use this?
The connection is tightly coupled to the DbContext. As a result, the connection will only be open when your class which inherits DbContext, UsersContext in your case, retains its scope.
In your example, UsersContext is scoped to the using block.
using (var context = new UsersContext())
{
//some actions
}
Therefore, once "some actions" are finished, the connection will close and any attempt to access lazy loading will throw an exception stating the connection is no longer available. Every time you need to access your database, you should start a new connection in my opinion. What you want to make sure is that you only make one actual trip to the database. Make sure that your query is optimized so that you do not make multiple trips to the database instead of just doing it all at once as that will affect your performance.
Edit
As a side note, the using block breaks down into this:
try{
var context = new UsersContext();
//some actions
}finally{
context.Dispose();
}