How to simulate ConfigurationManager in LINQPad - c#

I'm trying to test some code in LINQPad. However, the base class calls Configuration Manager. How can I simulate that when testing in LINQPad.
void Main()
{
var tRepo = new TestRepository();
var result = tRepo.GetAsync(1);
result.Dump();
}
public partial class TestRepository : BaseRepository<Customer>, ICustomerRepository
{
// Here base throws the errror
public TestRepository() : base("DbConnString")
{
}
}
Here's the constructor for BaseRepository (from a compiled DLL, so not editable in LINQPad):
protected BaseRepository(string connectionStringName)
{
var connectionString = ConfigurationManager.ConnectionStrings[connectionStringName];
Connection = new SqlConnection(connectionString.ConnectionString);
Connection.Open();
}

The answer can be found on the LinqPad website FAQ
http://www.linqpad.net/faq.aspx
I'm referencing a custom assembly that reads settings from an application configuration file (app.config). Where should I put my application config file so that LINQPad queries will pick it up?
Create a file called linqpad.config in the same folder as LINQPad.exe and put your configuration data there. Don't confuse this with linqpad.exe.config:
•linqpad.exe.config is for the LINQPad GUI
•linqpad.config is for your queries.

Something that might be useful for you, I created it some time ago.
This is an extension method, which you can use to force the reload of configuration from specific file. It uses reflection to change the private fields in the manager, clears the configuration and then conditionally reloads it. It is much easier than manually editing the config file of LINQPad.
public static void ForceNewConfigFile(this Type type, bool initialize = true)
{
var path = type.Assembly.Location + ".config";
if (!File.Exists(path))
throw new Exception("Cannot find file " + path + ".");
AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", path);
var typeOfConfigManager = typeof(ConfigurationManager);
typeOfConfigManager.GetField("s_initState", BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, 0);
typeOfConfigManager.GetField("s_configSystem", BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, null);
var typeOfClientConfigPaths = typeOfConfigManager.Assembly.GetTypes().Where(x => x.FullName == "System.Configuration.ClientConfigPaths").Single();
typeOfClientConfigPaths.GetField("s_current", BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, null);
if (initialize)
{
var dummy = ConfigurationManager.AppSettings;
}
}
Example usage:
typeof(SomeType).ForceNewConfigFile();
System.Configuration.ConfigurationManager.AppSettings.Dump();
SomeType is just a type contained in the assembly, which will be used as a source for location of the config file. Assumption is: configuration file exists beside the DLL file and is named {Assembly.Location}.config.

I went looking for this as well, but didn't want to create a whole new file, point, have other share that file etc. So I added in the ConfigurationBuilder, created a dictionary and added it to a InMemoryCollection.
#nullable enable
private IConfiguration _config;
void Main()
{
var builder = new ConfigurationBuilder();
var dictonary = new Dictionary<string, string>
{
{"Authentication:SecretKey","SuperSecret"}
};
builder.AddInMemoryCollection(dictonary);
_config = builder.Build();
_config.GetValue<string>("Authentication:SecretKey").Dump();
}
Example

Related

How can I add AutoMapper Profiles to my mapper config using a for loop?

I want to load a bunch of automapper profiles of referenced libraries, without having to type each one out by hand.
I'm trying to take the following steps:
Get all profiles from referenced assemblies
Add profiles to mapper config
Register mapper for DI
Step 1 works, but something goes wrong in step 2.
Current code:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var container = new UnityContainer();
var assemblyNames = Assembly.GetExecutingAssembly().GetReferencedAssemblies()
.Where(a => a.Name.StartsWith("OKL_KPS"));
var assemblies = assemblyNames.Select(an => Assembly.Load(an));
var loadedProfiles = new List<Type>();
foreach (var assembly in assemblies)
{
var assemblyProfiles = assembly.ExportedTypes.Where(type => type.IsSubclassOf(typeof(Profile)));
loadedProfiles.AddRange(assemblyProfiles);
}
var mapconfig = new MapperConfiguration(cfg =>
{
// Magic should happen here
foreach (var profile in loadedProfiles)
{
var resolvedProfile = container.Resolve(profile) as Profile;
cfg.AddProfile(resolvedProfile);
}
});
container.RegisterInstance<IMapper>(mapconfig.CreateMapper());
config.DependencyResolver = new UnityResolver(container);
//routes here
}
}
I also tried cfg.AddProfile((Profile)Activator.CreateInstance(profile.AssemblyQualifiedName, profile.Name).Unwrap());, but this returns the assembly name of the service I'm using it in, not the name of the library where the profile is from.
Edit
The assemblies aren't loading during the register step. To hack this there's a Dummy class in each library which are initialised before registering the profiles. Optimal solution is not needing these dummy classes, otherwise it would be cleaner to add each profile explicitly.
I also tried adding the ExportAttribute to the profile, but that didn't work either.
You scan loaded assemblies on available properties using LINQ queries. Something like this should work:
var profiles = AllClasses.FromLoadedAssemblies().
Where(type => typeof(Profile).IsAssignableFrom(type));
//add profiles to config
var mapconfig = new MapperConfiguration(cfg =>
{
// Magic should happen here
foreach (var profile in profiles)
{
var resolvedProfile = container.Resolve(profile) as Profile;
cfg.AddProfile(resolvedProfile);
}
});
//register mapper using config
container.RegisterInstance<IMapper>(mapconfig.CreateMapper());
You can add profiles by listing your assembly instance, assembly name or type.
Using names:
var mapconfig = new MapperConfiguration(cfg =>
{
cfg.AddProfiles("Foo.YourProject.API");
cfg.AddProfiles("Foo.YourProject.Service");
cfg.AddProfiles("Foo.YourProject.Repository");
...
});
Also check official documentation for more information.
Within the documenation is described on how to use AutoMapper with the Microsoft DI framework. And there it simply forwards to the corresponding NuGet package and an article that describes how it searches through the current application domain for all the open types and profiles to load them.
In your classes you then have to simply inject an IMapper imapper into the constructor which then simply does what you expect.
The only next caveat I ran into was, that not all my assemblies where loaded before I called services.AddAutoMapper() in my ConfigureServices() method. But for this case I simply added a simple helper method, which will be called before DI starts to do its work:
public static void LoadAllLocalAssemblies()
{
var entryAssembly = Assembly.GetEntryAssembly();
var location = entryAssembly.Location;
var path = Path.GetDirectoryName(location);
var files = Directory.EnumerateFiles(path, "*.dll");
foreach (var file in files)
{
try
{
Assembly.LoadFrom(file);
}
catch
{
}
}
}
After that all assemblies are loaded into the current app domain and the NuGet package will resolve all classes that are derived from Profile. My handlers get an IMapper mapper injected within the constructor and within my method I can call mapper.Map<MyDestination>(mySource) and it works as expected.
No dummy classes, interfaces or whatsoever is needed.

How to use .settings files in .NET core?

I'm porting an application to .NET core which relies on a .settings file. Unfortunately, I can't find a way to read it from .NET core. Normally, adding the following lines to the .csproj would generate a TestSettings class that would let me read the settings.
<ItemGroup>
<None Include="TestSettings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
</None>
</ItemGroup>
Unfortunately, this no longer seems to do anything. I can't even verify that the SettingsSingleFileGenerator runs at all. This GitHub issue suggests that this is a bug with the new .csproj format, but no one has offered an alternative.
What is the proper way of reading .settings files in .NET core?
For .NET Core 2.x, use the Microsoft.Extensions.Configuration namespace (see note below), and there are tons of extensions on NuGet you'll want to grab for reading from sources ranging from environment variables to Azure Key Vault (but more realistically, JSON files, XML, etc).
Here's an example from a console program that retrieves settings the same way we use them when Kestrel starts up for our Azure sites:
public static IConfiguration Configuration { get; } = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
// This allows us to set a system environment variable to Development
// when running a compiled Release build on a local workstation, so we don't
// have to alter our real production appsettings file for compiled-local-test.
//.AddJsonFile($"appsettings.{Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") ?? "Production"}.json", optional: true)
.AddEnvironmentVariables()
//.AddAzureKeyVault()
.Build();
Then in your code that needs settings, you just reference Configuration or you register IConfiguration for dependency injection or whatever.
Note: IConfiguration is read-only and will likely never get persistence per this comment. So if reading AND writing are required, you'll need a different option. Probably System.Configuration sans designer.
There's no way this is "proper", as I asked in the question, but I'm using this as a stop-gap until something more reasonable comes along. I cannot guarantee it will work for anyone else.
Include your .settings file as an embedded resource, then use it like this:
private static readonly ConfigurationShim Configuration = new ConfigurationShim("MyApp.Settings.settings");
public static bool MyBoolSetting => (bool) Configuration["MyBoolSetting"];
Code:
internal class ConfigurationShim
{
private static readonly XNamespace ns = "http://schemas.microsoft.com/VisualStudio/2004/01/settings";
private readonly Lazy<IDictionary<string, object>> configuration;
public ConfigurationShim(string settingsResourceName)
{
configuration = new Lazy<IDictionary<string, object>>(
() =>
{
Assembly assembly = Assembly.GetExecutingAssembly();
using (Stream stream = assembly.GetManifestResourceStream(settingsResourceName))
using (var reader = new StreamReader(stream))
{
XDocument document = XDocument.Load(reader);
return document.Element(ns + "SettingsFile")
.Element(ns + "Settings")
.Elements(ns + "Setting")
.Select(ParseSetting)
.ToDictionary(kv => kv.Item1, kv => kv.Item2);
}
});
}
public object this[string property] => configuration.Value[property];
private static (string, object) ParseSetting(XElement setting)
{
string name = setting.Attribute("Name").Value;
string typeName = setting.Attribute("Type").Value;
string value = setting.Element(ns + "Value").Value;
Type type = Type.GetType(typeName);
IEnumerable<ConstructorInfo> ctors = GetSuitableConstructors(type);
IEnumerable<MethodInfo> staticMethods = GetSuitableStaticMethods(type);
object obj = null;
foreach (MethodBase method in ctors.Cast<MethodBase>().Concat(staticMethods))
{
try
{
obj = method.Invoke(null, new object[] {value});
break;
}
catch (TargetInvocationException)
{
// ignore and try next alternative
}
}
return (name, obj);
}
private static IEnumerable<MethodInfo> GetSuitableStaticMethods(Type type)
{
// To use a static method to construct a type, it must provide a method that
// returns a subtype of itself and that method must take a single string as
// an argument. It cannot be generic.
return type.GetMethods().Where(method =>
{
ParameterInfo[] parameters = method.GetParameters();
return !method.ContainsGenericParameters &&
method.IsStatic &&
parameters.Length == 1 &&
parameters[0].ParameterType.IsAssignableFrom(typeof(string)) &&
type.IsAssignableFrom(method.ReturnType);
});
}
private static IEnumerable<ConstructorInfo> GetSuitableConstructors(Type type)
{
// We need a constructor of a single string parameter with no generics.
return type.GetConstructors().Where(ctor =>
{
ParameterInfo[] parameters = ctor.GetParameters();
return !ctor.ContainsGenericParameters &&
parameters.Length == 1 &&
parameters[0].ParameterType.IsAssignableFrom(typeof(string));
});
}
}
When porting existing projects I usually copy the generated Settings.Designer.cs from the old to the new project. But I know, this is bad for changing the Settings-file or adding new Settings-Keys.
I also noticed that the user's settings were deleted after installing a new version, what was not the case with .net-Framework-Settings.

Building programmatically a project

I need to build a project programmatically for a .csproj I am creating on the fly.
While searching Google I found the classes and API provided by the MS for the MSBuild Engine. With that information, I create a process which executes msbuild.exe and then reads the output, but now I want to use the namespace Microsoft.Build.Execution to build the project. This is my program:
public class Compiler
{
private static string locationOfMSBuilldEXE = "";
public static void Build(string msbuildFileName)
{
BuildManager manager = BuildManager.DefaultBuildManager;
ProjectInstance projectInstance = new ProjectInstance(msbuildFileName);
var result = manager.Build(new BuildParameters()
{
DetailedSummary = true
},
new BuildRequestData(projectInstance, new string[] { "Build" }));
var buildResult = result.ResultsByTarget["Build"];
var buildResultItems = buildResult.Items;
string s = "";
}
}
The results show that this is building fine, but I need to know the detailed output from the compile and how to view it. It would be really helpful if someone can give me link to a good tutorial or a book on MSBuild.
Thanks #ritchmelton. Though I figured it out myself.
Here is my code : I have used an in built logger ConsoleLogger
public class Compiler
{
private static string locationOfMSBuilldEXE = "";
public static void Build(string msbuildFileName)
{
ConsoleLogger logger = new ConsoleLogger(LoggerVerbosity.Normal);
BuildManager manager = BuildManager.DefaultBuildManager;
ProjectInstance projectInstance = new ProjectInstance(msbuildFileName);
var result = manager.Build(
new BuildParameters()
{
DetailedSummary = true,
Loggers = new List<ILogger>(){logger}
},
new BuildRequestData(projectInstance, new string[] { "Build" }));
var buildResult = result.ResultsByTarget["Build"];
var buildResultItems = buildResult.Items;
string s = "";
}
}
You need to add a instance of a class that implements the ILogger interface to your BuildParameters. You can add a new instance of one of the supplied loggers in the Microsft.Build.Logging namespace, or you can implement ILogger yourself as it is very small and there is a helper class in the Microsoft.Build.Utilities namespace called Logger that is easy to extend.
Build loggers
ILogger interface
Logger helper
If you just want to build a project or solution, without elaborate parameters, you can do it more simply. Pseudocode:
using namespace Microsoft.Build.Evaluation;
var p = Project.Load("path to project");
p.SetGlobalProperty("Configuration", "Release");
p.Build(...);
That's it! BuildParameters and so forth are for quite advanced scenarios. Visual Studio itself uses them.
Dan (msbuild dev)

mefcontrib interceptingCatalog export error

I am trying to test mef and mefcontrib in asp.net mvc2 app but i got an error:
Cannot cast the underlying exported value of type LoggerExtSys.Domain.WebLogger
(ContractName="LoggerExtSys.Domain.IWebLogger") to type LoggerExtSys.Domain.IWebLogger.
My test project here
code in Global.asax:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
var catalog = new CatalogBuilder()
.ForAssembliesInDirectory(HttpRuntime.BinDirectory, "*ExtSys.dll")
.Build();
// Create interception configuration
var cfg = new InterceptionConfiguration()
.AddInterceptor(new StartableStrategy());
// Create the InterceptingCatalog with above configuration
var interceptingCatalog = new InterceptingCatalog(catalog, cfg);
// Create the container
var container = new CompositionContainer(interceptingCatalog);
// exception here
var barPart = container.GetExportedValue<IWebLogger>();
barPart.Debug("Test");
}
Exception when i try to get GetExportedValue
code in WebLogger:
[Export(typeof(IWebLogger))]
public class WebLogger : IWebLogger
{
#region IWebLogger Members
public void Debug(string str)
{
}
#endregion
#region ICoreExtension Members
public void Initialize()
{
}
#endregion
}
But in desktop app all working good.
How to fix it? Thanks for all
Ok, the problem was in code block which load assemblies:
public AggregateCatalog ForAssembliesInDirectory(string directory, string pattern)
{
IList<ComposablePartCatalog> _catalogs = new List<ComposablePartCatalog>();
var dir = new DirectoryInfo(directory);
Assembly assembly;
foreach (var file in dir.GetFiles(pattern))
{
assembly = Assembly.LoadFile(file.FullName);
_catalogs.Add(new AssemblyCatalog(assembly));
}
return new AggregateCatalog(_catalogs);
}
After all test i remove it and use DirectoryCatalog. I dont know why but its work in desktop and web app.
Who will tell me why my old code not working in web app will get accepted answer and 50 bounty. Thanks for all
I think the problem is either here:
[Export(typeof(IWebLogger))]
public class WebLogger : IWebLogger
{
or in the way you handle type referencing and resolution.
I would try to change the line:
var barPart = container.GetExportedValue<IWebLogger>();
into:
var barPart = container.GetExportedValue<WebLogger>();
or you can also try to always use fully qualified names so not only IWebLogger but put its full namespace before.
you say this works well in windows based application, what assemblies did you reference in that project or how do you write in there the content of your Application_Start event handler? Are you sure it's absolutely the same?

How To Read UnitTest Project's App.Config From Test With HostType("Moles")

I have the folowing tests:
[TestClass]
public class GeneralTest
{
[TestMethod]
public void VerifyAppDomainHasConfigurationSettings()
{
string value = ConfigurationManager.AppSettings["TestValue"];
Assert.IsFalse(String.IsNullOrEmpty(value), "No App.Config found.");
}
[TestMethod]
[HostType("Moles")]
public void VerifyAppDomainHasConfigurationSettingsMoles()
{
string value = ConfigurationManager.AppSettings["TestValue"];
Assert.IsFalse(String.IsNullOrEmpty(value), "No App.Config found.");
}
}
The only difference between them is [HostType("Moles")]. But the first passes and the second fails. How can I read App.config from the second test?
Or may be I can add some another config file in other place?
Assuming you are trying to access values in appSettings, how about just adding the configuration at the beginning of your test. Something like:
ConfigurationManager.AppSettings["Key"] = "Value";
Then when your test tries to read the AppSettings "Key", "Value" will be returned.
You just add your "App.Config" file to the unit test project . It will read automatically.
See http://social.msdn.microsoft.com/Forums/en/pex/thread/9b4b9ec5-582c-41e8-8b9c-1bb9457ba3f6
In the mean time, as a work around, you could try adding the configuration settings to Microsoft.Moles.VsHost.x86.exe.config
[ClassInitialize]
public static void MyClassInitialize(TestContext testContext)
{
System.Configuration.Moles.MConfigurationManager.GetSectionString =
(string configurationName) =>
{
ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
Assembly assembly = Assembly.GetExecutingAssembly();
fileMap.ExeConfigFilename = assembly.Location + ".config";
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
object section = config.GetSection(configurationName);
if (section is DefaultSection)
{
ConfigurationSection configurationSection = (ConfigurationSection) section;
Type sectionType = Type.GetType(configurationSection.SectionInformation.Type);
if (sectionType != null)
{
IConfigurationSectionHandler sectionHandler =
(IConfigurationSectionHandler)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(sectionType.Assembly.FullName, sectionType.FullName);
section =
sectionHandler.Create(
configurationSection.SectionInformation.GetParentSection(),
null,
XElement.Parse(configurationSection.SectionInformation.GetRawXml()).ToXmlNode());
}
}
return section;
};
}
I ran across this issue at work and didn't like any of these answers. I also have the problem that the configuration file is being read in a static constructor which means I can't Mole ConfigurationManager before the static constructor is executed.
I tried this on my home computer and found that the configuration file was being read correctly. It turns out I was using Pex 0.94.51006.1 at home. This is slightly older than the current one. I was able to find a download for the older academic version:
http://research.microsoft.com/en-us/downloads/d2279651-851f-4d7a-bf05-16fd7eb26559/default.aspx
I installed this on my work computer and everything is working perfectly. At this point, I'm downgrading to the older version until a newer working version is released.
This is what I am using to get the correct AppConfig and ConnectionString sections:
var config = System.Configuration.ConfigurationManager.OpenExeConfiguration(Reflection.Assembly.GetExecutingAssembly().Location);
typeof(Configuration.ConfigurationElementCollection).GetField("bReadOnly", Reflection.BindingFlags.Instance | Reflection.BindingFlags.NonPublic).SetValue(System.Configuration.ConfigurationManager.ConnectionStrings, false);
foreach (Configuration.ConnectionStringSettings conn in config.ConnectionStrings.ConnectionStrings)
System.Configuration.ConfigurationManager.ConnectionStrings.Add(conn);
foreach (Configuration.KeyValueConfigurationElement conf in config.AppSettings.Settings)
System.Configuration.ConfigurationManager.AppSettings(conf.Key) = conf.Value;
Saw the ConnectionString part here

Categories