For example, I created a provider service that uses a database. In web.config, how do I set the provider's connection string to the main application connection string, defined in <ConnectionStrings>?
Matt's answer is pretty much there, with a couple of tweaks.
If you're happy to have it outside of the configuration code itself, once you've picked up your provider configuration, you can just talk to the main connection strings section directly from your provider classes:
var provider = ConfigurationManager.GetSection("ProviderConfiguration")
as ProdviderSettingsSection;
ConnectionString connStr =
WebConfigurationManager.ConnectionStrings[provider.ConnectionString];
If you want to wrap it all up in the provider you'll need a backing field for your properties:
public class ProvderSettingsConfigElement : ConfigurationElement {
private m_ConnectionString;
[ConfigurationProperty("connectionString")]
public string ConnectionString{
// Probably want to check m_ConnectionString for IsNullOrEmpty
get{ return WebConfigurationManager.ConnectionStrings[m_ConnectionString]; }
set{ m_ConnectionString = value;}
}
}
You could create a custom config element that reads the configuration for main app config.
Don't take this line for line but something like...
public class ProviderConfiguration : ConfigurationSection
{
#region Constructors
public ProviderConfiguration () { }
#endregion
#region Public Properties
[ConfigurationProperty("ProviderConnection")]
public ProvderSettingsConfigElement ProvderConnection
{
get { return (ProvderSettingsConfigElement)this["ProviderConnection"]; }
}
#endregion
}
public class ProvderSettingsConfigElement : ConfigurationElement
{
#region Constructors
public ProvderSettingsConfigElement () { }
public WebSecuritySettingsDataProviderElement(string name, string type)
{
ConnectionString = ConfigurationManager.Get("mainAppConnString");
}
#region Public Properties
[ConfigurationProperty("connectionString")]
public string ConnectionString{get; set;}
}
Related
I'm trying to build a data layer in my application based on a .NET Core class library using Dapper. The data classes look like this:
//FieldRepository.cs
using Dapper.Contrib.Extensions;
public class FieldRepository : IRepository<TblField>
{
private IDbConnection connection;
public FieldRepository(string connectionString)
{
connection = new SqlConnection(connectionString);
}
public IEnumerable<TblField> GetAll()
{
return connection.GetAll<TblField>();
}
}
//IRepository.cs
public interface IRepository<T>
{
IEnumerable<T> GetAll();
}
//TblField
public class TblField
{
public string FieldText { get; set; }
public int Id { get; set; }
}
Then I tried to run a test against these classes as below:
public void ThereShouldBeFields()
{
var repo = new FieldRepository("valid connection string");
var fields = repo.GetAll();
fields.Should().NotBeNull();
}
When I ran this test, I got a FileNotFound exception at the FieldRepository constructor for System.Data.SqlClient, version 4.2.0.0, which is installed in the data layer project.
I know I'm missing something simple here, but what is it?
Looks like it was because the reference needed to be added to both the Test project and the Data layer project.
The more you know!
I want to change my session proviced to statically typed - I just hate typing strings because of many many errors I do.
What technology am I using? ASP.NET MVC via EXT.NET MVC
I was trying to do that using web.config but the problem is that after add session state to it visual is not going to compile my code because of that session should be using strings as keys.
I want to use session by enums such as :
public enum SessionEnum{Model}
public class Bar{
void foo(){
Session[SessionEnum.Model] = "blah";
}
}
I am aware that I can create wrapper converting enums to strings but it's not very satisfying solution for me.
public class StorageWrapper{
public object this[SessionEnum enum]{ get{return Session[enum.toString()]}; //+set
}
What I did was create static object for base class for all of my controllers and then I was able to use it across them but after closing and opening the page again I wasn't able to get values from it. I guess I should serialize them somehow but I have no idea how.
Is there any way to do that?
EDIT
My session now looks like this :
[Serializable]
public abstract class DataWrapper<T> : HttpSessionStateBase
{
Dictionary<T, object> Dictionary { get; set; } = new Dictionary<T, object>();
public object this[T a]
{
get
{
try
{
return Dictionary[a];
}
catch
{
return null;
}
}
set { Dictionary[a] = value; }
}
}
[Serializable]
public class SessionWrapper : DataWrapper<SessionNames>
{}
public enum SessionNames { Model, Login, LastOpenedFile }
It's very simple.
Create a UserSession object which does everything you want (holds your values as enum etc), instantiate it, then put it in the session.
var US = new UserSession();
US.stuff = somestuff;
Session["UserSess"] = US
Then you can just always use Session["UserSess"].stuff;
Mmmm, wouldn't you use static const string instead of an enum?
using System.Web;
public static class SessionEnum
{
public static const string Model = "_Session_Model";
public static const string Login = "_Session_Login";
public static const string LastOpenedFile = "_Session_LastOpenedFile ";
}
class test
{
void test()
{
Session[SessionEnum.Model] = "blah";
}
}
I can DI app setting in the controller like this
private IOptions<AppSettings> appSettings;
public CompanyInfoController(IOptions<AppSettings> appSettings)
{
this.appSettings = appSettings;
}
But how to DI that in my custom class like this
private IOptions<AppSettings> appSettings;
public PermissionFactory(IOptions<AppSettings> appSetting)
{
this.appSettings = appSettings;
}
my register in Startup.cs is
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
The "proper" way
Register your custom class in the DI, the same way you register other dependencies in ConfigureServices method, for example:
services.AddTransient<PermissionFactory>();
(Instead of AddTransient, you can use AddScoped, or any other lifetime that you need)
Then add this dependency to the constructor of your controller:
public CompanyInfoController(IOptions<AppSettings> appSettings, PermissionFactory permFact)
Now, DI knows about PermissionFactory, can instantiate it and will inject it into your controller.
If you want to use PermissionFactory in Configure method, just add it to it's parameter list:
Configure(IApplicationBuilder app, PermissionFactory prov)
Aspnet will do it's magic and inject the class there.
The "nasty" way
If you want to instantiate PermissionFactory somewhere deep in your code, you can also do it in a little nasty way - store reference to IServiceProvider in Startup class:
internal static IServiceProvider ServiceProvider { get;set; }
Configure(IApplicationBuilder app, IServiceProvider prov) {
ServiceProvider = prov;
...
}
Now you can access it like this:
var factory = Startup.ServiceProvider.GetService<PermissionFactory>();
Again, DI will take care of injecting IOptions<AppSettings> into PermissionFactory.
Asp.Net 5 Docs in Dependency Injection
I recommend not passing AppSettings. A class shouldn't depend on something vague - it should depend on exactly what it needs, or close to it. ASP.NET Core makes it easier to move away from the old pattern of depending on AppSettings. If your class depends on AppSettings then you can't really see from the constructor what it depends on. It could depend on any key. If it depends on a more specific interface then its dependency is clearer, more explicit, and you can mock that interface when unit testing.
You can create an interface with the specific settings that your class needs (or something less specific but not too broad) and a class that implements it - for example,
public interface IFooSettings
{
string Name { get; }
IEnumerable Foos { get; }
}
public interface IFoo
{
string Color { get; }
double BarUnits { get; }
}
public class FooSettings : IFooSettings
{
public string Name { get; set; }
public List<Foo> FooList { get; set; }
public IEnumerable Foos
{
get
{
if (FooList == null) FooList = new List<Foo>();
return FooList.Cast<IFoo>();
}
}
}
public class Foo : IFoo
{
public string Color { get; set; }
public double BarUnits { get; set; }
}
Then add a .json file, fooSettings.json:
{
"FooSettings": {
"Name": "MyFooSettings",
"FooList": [
{
"Color": "Red",
"BarUnits": "1.5"
}, {
"Color": "Blue",
"BarUnits": "3.14159'"
}, {
"Color": "Green",
"BarUnits": "-0.99999"
}
]
}
}
Then, in Startup() (in Startup.cs) where we specify what goes into our Configuration, add fooSettings.json:
var builder = new ConfigurationBuilder(appEnv.ApplicationBasePath)
.AddJsonFile("config.json")
.AddJsonFile($"config.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("fooSettings.json");
Finally, in ConfigureServices() (also in Startup.cs) tell it to load an instance of FooSettings, cast it as IFooSettings (so the properties appear read-only) and supply that single instance for all dependencies on IFooSettings:
var fooSettings = (IFooSettings)ConfigurationBinder.Bind<FooSettings>(
Configuration.GetConfigurationSection("FooSettings"));
services.AddInstance(typeof (IFooSettings), fooSettings);
Now your class - controller, filter, or anything else created by the DI container - can have a dependency on IFooSettings and it will be supplied from the .json file. But you can mock IFooSettings for unit testing.
Original blog post - it's mine so I'm not plagiarizing.
You can do dependency injection in your non-controller classes as well.
In your startup class,
public class Startup
{
public IConfigurationRoot Configuration { get; set; }
public Startup(IHostingEnvironment env)
{
// Set up configuration sources.
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services)
{
// register other dependencies also here
services.AddInstance<IConfiguration>(Configuration);
}
}
Now in your custom class, Have the constructor accept an implementation of IConfiguration
private IConfiguration configuration;
public PermissionFactory(IConfiguration configuration)
{
this.configuration = configuration;
}
public void SomeMethod()
{
var someSection = this.configuration.GetSection("SomeSection");
var someValue= this.configuration.Get<string>("YourItem:SubItem");
}
If you want to DI to action filter reference to Action filters, service filters and type filters in ASP.NET 5 and MVC 6 service filter part.
recently posted about questioning how unsafe static variables are, I've since discovered I need to get rid of them. But I cannot figure out how to? Was thinking a static Get() method for each class, that returns a single instance, but then that instance would have to be declared static.
So the only way to do it, is to have the instance references (for each helper, I.E user helper.cs, imagehelper.cs etc.) is to declare them as instance properties on some sort of globally accessible class? But which class? Is there something I'm missing here?
Code below of a sample class I need to change:
sing System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Mvc.Mailer;
namespace MVCWebsite.Helpers
{
public class AppSettings
{
public static void OnAppInit()
{
//General
AppName = "MyApp";
DesktopBaseURLs = new Dictionary<string, string>();
DesktopBaseURLs.Add("dev", "localhost:50560");
DesktopBaseURLs.Add("test", "www.test.whatever.com");
DesktopBaseURLs.Add("live", "www.whatever.com");
MobileBaseURLs = new Dictionary<string, string>();
MobileBaseURLs.Add("dev", "m.local.whatever.com");
MobileBaseURLs.Add("test", "m.test.whatever.com");
MobileBaseURLs.Add("live", "m.whatever.com");
//Emails
EmailHostName = AppName + ".com"; //For the moment atleast
NoReplyEmailAddress = "no-reply#" + EmailHostName.ToLower();
SupportEmailAddress = "support#" + EmailHostName.ToLower();
ErrorEmailAddress = "errors#" + EmailHostName.ToLower();
//Resources
TempFileURL = "/content/temp/";
UserDataURL = "/content/user-content/";
ProfilePicturesURL = UserDataURL + "profile-pictures/";
var a = GlobalHelper.GetURLAsServerPath(ProfilePicturesURL);
var b = a;
}
//General
public static string AppName { get; set; }
public static Dictionary<string, string> DesktopBaseURLs;
public static Dictionary<string, string> MobileBaseURLs;
//Emails
public static string EmailHostName { get; set; }
public static string NoReplyEmailAddress { get; set; }
public static string SupportEmailAddress { get; set; }
public static string ErrorEmailAddress { get; set; }
//Resources
public static string UserDataURL { get; set; }
public static string TempFileURL { get; set; }
public static string ProfilePicturesURL { get; set; }
//Methods
public static void SetAppURL()
{
}
}
}
I recommend creating an interface for your AppSettings class, so that you can use it in your controllers now, and implement it in different ways as you see fit:
public interface IAppSettings
{
string AppName { get; set; }
...
}
You can then implement it immediately with your static class via a wrapper class:
public class AppSettingsWrapper : IAppSettings
{
public AppName
{
get
{
return AppSettings.AppName;
}
set
{
AppSettings.AppName = value;
}
}
...
}
Later on, you can create an implementation of IAppSettings that uses session, or cookies, or database values, or whatever. The important thing is to abstract the way you store things so that you can implement in a way that meets your needs.
The answer to you previous question clearly stated that the IDictionary was the only unsafe variable in your static method because it's not thread safe. You just need to store these variables differently. You don't need to get rid of all of your static variables. You just need to change IDictionary to something thread safe.
By the way, someone there makes a good coment about web.config
Right I think I've figured it out, they should be stored as instance variables within Global.asax.cs. This file contains your Application class which inherits from System.Web.HttpApplication. This master class is limited to one instance (of itself) per request. So if you store any references to your helpers here, you can reference them by going, MvcApplication.MyHelper.DoSomething(); Someone please correct me if this is wrong, but seems right to me. "At any single point of time, an HTTPApplication instance handles only one request, so we don't need to think about locking and unlocking of any non static members, but for static members we do require. " -from : http://www.codeproject.com/Articles/87316/A-walkthrough-to-Application-State#c
We've been experimenting with StructureMap, and I'm having trouble grasping how to handle situations where a single interface has multiple implementations. The code below shows an example where we have two databases that are both accessible from a single service.
public class SomeController : Controller
{
private ISomeService _service;
private IClientRepository _repository;
protected IContext _masterContext;
protected IContext _clientContext;
public SomeController(ISomeService service, ISomeRepository repository
, IContext masterCon, IContext clientCon)
{
_service = service;
_repository = repository;
_masterContext = masterCon;
_clientContext = clientCon;
}
}
public class SomeService : ISomeService
{
private IContext _masterContext;
private IContext _clientContext;
public SomeService(IContext masterContext, IContext clientContext)
{
masterContext = _masterContext;
clientContext = _clientContext;
}
}
public class ClientRepository : IClientRepository
{
private IContext _clientContext;
public ClientRepository(IContext clientContext)
{
_clientContext = clientContext;
}
}
public class MasterContext : IContext
{
public MasterContext(String connString)
//<snip, snip> implement 3rd party data context
}
public class ClientContext : IContext
{
public ClientContext(String connString)
//<snip, snip> implement 3rd party data context
}
StructureMap worked GREAT when we had a single context (database), but how do I tell it how to resolve the 2nd? Note: in most situations we wouldn't have a service handling 2 databases (but may have a controller handling 2 connections, i.e. 2 repositories accessing 2 different databases), but it still doesn't seem to make it easier.
I'm half ready to just give up on using an IoC framework and go back to poor man's DI.
Is it not possible to have an IClientContext and an IMasterContext, possibly inheriting from IContext. My feeling is that the code would be doing one of two very different things depending on whether you were talking to the 'Master' or 'Client' database.
In Unity you can have named registrations, allowing you to effectively register more than a class for a given interface. So you could do (typing by heart, check the actual Unity documentation if interested):
container.RegisterType<IContext, MasterContext>("Master");
container.RegisterType<IContext, ClientContext>("Client");
and then the constructor for SomeService would be:
public SomeService(
[Dependency("Master")]IContext masterContext,
[Dependency("Client")]IContext clientContext)
{
//...
}
The drawback is that in this way your service class is no longer independent of the DI framework used, but depending on the project that may be ok.
This can be a little difficult if you're relying on StructureMap to resolve the dependencies automatically. The first solution (and what I'd err towards) is to make use of marker interfaces like Richard mentions in his answer then just register them. You can then explicitly specify whether you want your client or master context there.
The second way is to make use of named registrations, then specify the constructor params explicitly.
ForRequestedType<IContext>().AddInstances(
i => {
i.OfConcreteType<ClientContext>().WithName("Client");
i.OfConcreteType<MasterContext>().WithName("Master");
});
ForRequestedType<SomeController>().TheDefault.Is.ConstructedBy(
i => new SomeController(i.GetInstance<ISomeService>(),
i.GetInstance<IClientRepository>(),
i.GetInstance<IContext>("Master"),
i.GetInstance<IContext>("Client")));
Not particularly nice but it does the job and ultimately if it's only in one or two places it might be OK.
If you want to resolve differently on namespace / assembly you could try something like this:-
ForRequestedType<IContext>().AddInstances(
i => {
i.OfConcreteType<ClientContext>().WithName("Client");
i.OfConcreteType<MasterContext>().WithName("Master");
}).TheDefault.Is.Conditional(c => {
c.If(con => con.ParentType.Namespace.EndsWith("Client"))
.ThenIt.Is.TheInstanceNamed("Client");
c.If(con => con.ParentType.Namespace.EndsWith("Master"))
.ThenIt.Is.TheInstanceNamed("Master");
c.TheDefault.Is.OfConcreteType<ClientContext>();
});
Where the predicate on ParentType can refer to Assembly (or whatever you want really)
In case someone stumble in this problem, you can achieve it using factory pattern.
Service extension
public static class ServiceFactoryExtensions
{
public static void RegisterSqlFactory(this IServiceCollection serviceCollection)
{
serviceCollection.Configure<MsSqlOption>(option => option.ConnectionString = "Mssql connection string");
serviceCollection.Configure<MySqlOption>(option => option.ConnectionString = "Mysql connection string");
serviceCollection.Configure<PostgreOption>(option => option.ConnectionString = "Postgrel connection string");
serviceCollection.AddSingleton<ISqlDatabase, MsSql>();
serviceCollection.AddSingleton<ISqlDatabase, Postgre>();
serviceCollection.AddSingleton<ISqlDatabase, MySql>();
serviceCollection.AddSingleton<Func<IEnumerable<ISqlDatabase>>>(serviceProvider => () => serviceProvider.GetService<IEnumerable<ISqlDatabase>>());
serviceCollection.AddSingleton<ISqlDatabaseFactory, SqlDatabaseFactory>();
}
}
Factory class
public class SqlDatabaseFactory : ISqlDatabaseFactory
{
private readonly Func<IEnumerable<ISqlDatabase>> _factory;
public SqlDatabaseFactory(Func<IEnumerable<ISqlDatabase>> factory)
{
_factory = factory;
}
public ISqlDatabase CreateSql(SqlType sqlType)
{
var databases = _factory();
var sqlDatabase = databases.FirstOrDefault(x => x.DatabaseName == sqlType);
if (sqlDatabase == null)
throw new NotImplementedException($"Sql type {nameof(sqlType)} is not implemented");
return sqlDatabase;
}
}
Sql classes
public class MsSql : ISqlDatabase
{
public SqlType DatabaseName => SqlType.MsSql;
public string Connecionstring { get; private set; }
public MsSql(IOptions<MsSqlOption> option)
{
Connecionstring = option.Value.ConnectionString;
}
}
public class Postgre : ISqlDatabase
{
public SqlType DatabaseName => SqlType.Postgre;
public string Connecionstring { get; private set; }
public Postgre(IOptions<PostgreOption> option)
{
Connecionstring = option.Value.ConnectionString;
}
}
public class MySql : ISqlDatabase
{
public SqlType DatabaseName => SqlType.MySql;
public string Connecionstring { get; private set; }
public MySql(IOptions<MySqlOption> option)
{
Connecionstring = option.Value.ConnectionString;
}
}
public interface ISqlDatabase
{
string Connecionstring { get; }
SqlType DatabaseName { get; }
}
public enum SqlType
{
MsSql,
Postgre,
MySql
}
Usage
internal class Program
{
static void Main(string[] args)
{
var serviceCollection = new ServiceCollection();
serviceCollection.RegisterSqlFactory();
var provider = serviceCollection.BuildServiceProvider();
var sqlFactory = provider.GetService<ISqlDatabaseFactory>();
var mySql = sqlFactory.CreateSql(SqlType.MySql);
var msSql = sqlFactory.CreateSql(SqlType.MsSql);
var postgre = sqlFactory.CreateSql(SqlType.Postgre);
Console.WriteLine($"Database Type : {mySql.DatabaseName}, Connectionstring: {mySql.Connecionstring}");
Console.WriteLine($"Database Type : {msSql.DatabaseName}, Connectionstring: {msSql.Connecionstring}");
Console.WriteLine($"Database Type : {postgre.DatabaseName}, Connectionstring: {postgre.Connecionstring}");
Console.ReadKey();
}
}
Output
Dependencies:
.Net Core 3.1
Microsoft.Extensions.DependencyInjection;
Microsoft.Extensions.Options;
System
System.Collections.Generic
System.Linq;