IIS looking at wrong path for MVC configuration file - nhibernate

When I run MVC4 my application using Visual Studio Development Server, my application is able to load all configuration files correctly. But when I try to run it under the Local IIS Web server, it throws this error
{"Could not find a part of the path 'C:\\Windows\\SysWOW64\\inetsrv\\~\\nhibernate.config'."}
It's looking at the wrong folder. The config file is directly in the root of my web project. Why is this happening. How can I fix it. I'm pretty sure that nhibernate looks for this file in order to load it's properties. Unless you know how to move nhibernate configuration files into the web.config file, please don't recommend that, I get a "Unrecognized configuration section hibernate-configuration" when ever I copy it over
Edit:
by the way, I'm pretty sure it's looking at the following key in appSettings my app settings section
<add key="nhibernate.config" value="~/nhibernate.config" />
Edit2:
here is the stack trace that goes into how Nhibernate is getting this value, and trying to find the configuration file
at NHibernate.Cfg.ConfigurationSchema.HibernateConfiguration..ctor(XmlReader hbConfigurationReader, Boolean fromAppSetting)
at NHibernate.Cfg.ConfigurationSchema.HibernateConfiguration..ctor(XmlReader hbConfigurationReader)
at NHibernate.Cfg.Configuration.Configure(XmlReader textReader)
at NHibernate.Cfg.Configuration.Configure(String fileName, Boolean ignoreSessionFactoryConfig)
at NHibernate.Cfg.Configuration.Configure(String fileName)
at AndroMDA.NHibernateSupport.DefaultSessionManager.BuildSessionFactory()

So it wasn't actually NHibernate that was using this file. My boss decided to use something called AndroMDA to generate code, and part of that generation was some NHibernate Support that I couldn't see into.
If anybody is interested, I created a new implementation of ISessionManager, which looks exactly like DefaultSessionManager except for the following member function and variable.
public class ServerMapSessionManager : ISessionManager
{
//other interface implementation...//
public static HttpServerUtility Server { get; set; }
public String TranslateConfigPath(String virtualPath)
{
return Server.MapPath("/"+virtualPath);
}
}
Then in App_start I call the following
SessionManagerFactory.SessionManager = new MVCFramework.Core.Common.ServerMapSessionManager();
MVCFramework.Core.Common.ServerMapSessionManager.Server = Server;

Related

ConnectionString in .NET Core 6

I'm playing around in .NET Core 6 Web API's. But I can't seem to figure out how the connection string works now.
The first part here that is commented out works fine. But I need to be able to throw the program on different systems and change the connection string with appsettings.json.
The second part is what I attempted but that doesn't work.
Config connection string in .net core 6 is where I got it from.
//builder.Services.AddDbContext<TodoContext>(opt =>
// opt.UseSqlServer(#"Data Source=JOHANDRE\\SQL2017; Database=ToDoItems; User=xxx; Password=xxx;"));
builder.Services.AddDbContext<TodoContext>(opt =>
opt.UseSqlServer(builder.Configuration.GetConnectionString("ToDoItemsDatabase")));
My appsettings.json:
"ConnectionStrings": {
"ToDoItemsDatabase": "Server=JOHANDRE\\SQL2017; Database=ToDoItems; User=xxx; Password=xxx;"
},
I want to add that it does not throw errors. it just does not seem to find the connection.
Problem is how you start your Web API from the service. You are using Process without setting ProcessStartInfo.WorkingDirectory to the folder containing exe and configuration and the started process shares the working directory with parent one, so either move appsettings.json to the parent project folder or set the WorkingDirectory to match the directory containing the exe:
toDoTest.StartInfo.UseShellExecute = false;
toDoTest.StartInfo.WorkingDirectory = "C:\\Develop\\ToDoMVCtutorial\\bin\\Release\\net6.0\\publish\\";
Also you can try redirecting your Web API output to capture the logs.

How to read web.config file in .Net Core app

I have created a .Net Core API and I referenced a .Net framework application to it. The referenced Application connects to a data base and its connection string is stored in web.config file:
string CONNSTR =ConfigurationManager.ConnectionStrings["SHOPPINGCNN"].ConnectionString;
The .Net Core application uses appsettings.json instead of web.config file. When I run the API and try to use the referenced application resources, the above code will be triggered and will return null because there is no web.config file exists in .net Core app. What is the best solution to resolve this issue
Because .Net Core applications are self hosted and can almost run on any platform, they are no longer hosted on IIS. The .Net Core application settings are stored in a Json format (appsettings.json) by default while .Net Framework application configurations are stored in a web.config file in XML format. For more info about .Net Core applications, you may read Configuration in ASP.NET Core. In my case, I was trying to access the data layer of a .Net Framework assembly from a .Net Core 2.0 assembly. To achieve this, there is no need to install System.Configuration.ConfigurationManager package in the .Net Core application but you only need to add app.config to the .Net Core assembly then add the connection string to it:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<connectionStrings>
<add name="SHOPPINGCNN" connectionString="server=your server name;integrated security=true;database=your database name" />
</connectionStrings>
</configuration>
After that, everything will work fine. Make sure that you use the same connection string name (SHOPPINGCNN in my case) that you used in your .Net Framework application otherwise you will not get the desired result. I did this in my project and it works 100%.
in .net core you can use ConfigurationBuilder to read appsettings.json file.
You can implement like following.
appsettings.json sample
{
"option1": "value1_from_json",
"option2": 2,
"ConnectionStrings": {
"YourConnectionString": "............."
}
}
C# code sample
static class YourClass
{
public static IConfigurationRoot Configuration;
public static string GetConnectionString()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json");
Configuration = builder.Build();
var connectionString = Configuration["ConnectionStrings:YourConnectionString"];
}
}
In case you missed it - and because #Zuhair doesn't seem to want to post an answer - here is a copy paste of their solution (I missed this at first as it was only in a comment):
I found the solution. I changed the name of the Web.config to
app.config and I was able to get the connection string using:
System.Configuration.ConfigurationManager.ConnectionStrings["SHOPPINGCNN"].ConnectionString
The app.config file looks like this:
<?xml version="1.0"> encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="SHOPPINGCNN" connectionString="server=.\SQLEXPRESS;integrated security=true;database=xxxxx" />
</connectionStrings>
</configuration>
You also need to install this NuGet package:
System.Configuration.ConfigurationManager
In my case I simply renamed the web.config containing the connectionString 'app.config' and it worked.
I realise this probably isn't a good long term solution but for mixed legacy projects - or to get a foot in the door to begin to learn .net Core it's very useful.
For .NET Core apps, the best way is to use the Configuration API. This is a very flexible way and, thanks to providers pattern, it allows to use a different sources, not only the most common appsettings.json file (that by the way just a JSON file and could be named in a random way):
File formats (INI, JSON, and XML)
Command-line arguments
Environment variables
In-memory .NET objects
An encrypted user store Azure Key Vault
Custom providers, which you install or create
Now about ConfigurationManager . At first, the .NET Core forced to forget about this class - it was not implemented and supported and the idea was to fully replace it by providing new Configuration API.
Moreover, the reality is that ASP.NET Core apps aren't hosted via IIS anymore (IIS works mainly as a reverse proxy now), and so the web.config is not so useful anymore (unless rare cases when you still need to define parameters specific to IIS configuration).
Though, after the .NET Standard 2.0 was provided, this System.Configuration.ConfigurationManager nuget package is available and brings back the ConfigurationManager class. It became possible due to new compatibility shim implemented in new .NET Core 2.0.
Regarding your case, it is difficult to say why you have 'null' as it not enough information:
it may be a wrong section in web.config
web.config may not be copied into your output/publishing folder
The problem here is that the OP has a data access layer project library that targets the full .Net Framework that contains code which depends on the ConfigurationManager. ConfigurationManager knows nothing about configuration in .Net Core and thus cannot access values from the default configuration implementation, i.e. appsettings.json. Some answers note that you can add an app.config file to the .Net Core client, but this smells if we don't hold our nose.
The better solution would be to inject the connection string into the data access library. Especially if that library will be used by multiple clients.
For everyone having problem reading web.config in asp.net core. After spending hours trying and failing.. then i came to a blog which stated
The .Net Core application uses appsettings.json instead of web.config
file.
so i suggest everyone to place files they want to read to appsettings.json and from there you can read. There are plenty of methods available. Just wanted to save time of those trying.
The only way i could use a web.config was reading the file as a XML, and inputing the values into a ConfigurationManager object using the .AddInMemoryCollection(list) method.
//ConfigurationManager.cs
using System;
using System.Collections;
using System.Xml;
using Microsoft.Extensions.Configuration;
namespace sql_util {
public static class ConfigurationManager {
public static IConfiguration AppSettings { get; }
static ConfigurationManager() {
var list = new List<KeyValuePair<string, string>>();
XmlDocument xd = new XmlDocument();
xd.Load(Directory.GetCurrentDirectory() + "\\" + "web.config");
if (xd.GetElementsByTagName("appSettings").Count > 0) {
XmlNodeList confs = xd.GetElementsByTagName("appSettings")[0].ChildNodes;
for (int y = 0; y < confs.Count; y++) {
if (confs[y].Attributes != null) {
if (confs[y].Attributes[0] != null) {
list.Add(new KeyValuePair<string, string>(confs[y].Attributes[0].Value, confs[y].Attributes[1].Value));
}
}
}
}
AppSettings = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddXmlFile(Directory.GetCurrentDirectory() + "\\Web.config", false, true)
.AddInMemoryCollection(list)
.Build();
}
}
}
//Web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appSettings>
<add key="smtp_server" value="127.0.0.1" />
//envia_mail.cs
using ConfigurationManager = sql_util.ConfigurationManager;
namespace anotacoes {
public class envia_email {
private string SmtpServer = ConfigurationManager.AppSettings["smtp_server"];
added Web.config file to root as i used in .net framework project.
ConfigurationManager.AppSettings["MySQL"]; works fine.
I changed my Web.config to App.config and my issues resolved immediately.
You can still use an app.config for connection strings if needed. Include the nuget package System.Configuration.ConfigurationManager.
Then to get a connection string you'd do this:
System.Configuration.ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString
As others have pointed out, connection strings are easily used from the appsettings.json file and this is the preferred method.

Does App.config (or ApplicationName.exe.config) work in mono?

I'm trying to get EntityFramework 6 with dotConnect for Oracle working on Mono.
I have also all app configuration defined in userSettings section.
First thing I noticed is that my app has always default configuration, then I tried to make Devart.Data.Oracle provider working, but I got an error:
System.Configuration.ConfigurationErrorsException: Failed to find or load the registered .Net Framework Data Provider 'Devart.Data.Oracle'.
I checked my app with strace and using MONO_LOG_LEVEL:
MONO_LOG_LEVEL=debug mono Host.exe | grep config
And config file is loaded (successfully) couple of times during app startup.
I found few bug reports about configuration in mono, but they are quite old and I don't know if still actual.
https://bugzilla.xamarin.com/buglist.cgi?quicksearch=ApplicationSettingsBase+
Could you give me a hint how to get rid of provider section in App.config?
I've managed to move almost all configuration to code (except of providers).
First, your exception is not about wrong configuration. It loaded and read your configuration, but then it cannot find provider (Devart.Data.Oracle) specified in that configuration. Most obvious reason for that is missing dll which contains that provider.
Second, this is how I use EF6 + Devart's postgresql provider (you use Oracle, but that should be similar) on mono without any configuration files:
public class PgSqlConfiguration : System.Data.Entity.DbConfiguration
{
public PgSqlConfiguration()
{
SetProviderServices("Devart.Data.PostgreSql", PgSqlEntityProviderServices.Instance);
SetProviderFactory("Devart.Data.PostgreSql", PgSqlProviderFactory.Instance);
}
}
Then mark your context with DbConfigurationType attribute like this:
[DbConfigurationType(typeof(PgSqlConfiguration))]
public partial class YourContext : DbContext {}
Just replace PostgreSql providers with Oracle in code above (and don't forget to add missing dll if that is the case) and you should be fine.

Zero dependency from the client configuration files for WCF services

Our aim is to have Zero dependency from the client configuration files for WCF services.
we are using ConfigurationChannelFactory() to create the channel and specify the ConfigSettings.
ConfigSettings is loaded using the following code
ConfigurationManager.OpenExeConfiguration(ConfigFilePath);
So we have to provide the ConfigFilePath here.
we have both windows and web clients.
we have used below approaches to find out the path
AppDomain.CurrentDomain.BaseDirectory + "bin\\" + executingAssembly.GetName().Name + ".dll"
Web client : AppDomain.CurrentDomain.BaseDirectory gives root folder of the
web applicaton so its works fine
Windows client : AppDomain.CurrentDomain.BaseDirectory gives path upto Debug/Release folder
so, its throws error
Assembly.GetExecutingAssembly().Location
Web client : Assembly.GetExecutingAssembly().Location gives path to the ASP.Net temp.
files , where we dont have the config files. So its throws an error.
Windows client : Assembly.GetExecutingAssembly().Location gives the correct location,
so its works fine.
In order to make it works in web clients, we have to add the following key in client's web.config files.
<hostingenvironment shadowcopybinassemblies="false">
but it adds a dependency to the clients.
Can you guys please help me to find the path without worrying about the clients?
have you tried this? I used GetCallAssembly() instead of GetExecutingAssembly() as this lives in a utility class in our project.
public static string AssemblyDirectory
{
get{
string codeBase = assembly.GetCallingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
Could you just probe both paths? In other words, check the Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin") folder and if you can't find the config file in there, check the Assembly.GetExecutingAssembly().Location folder instead? Since you indicate that the first approach works for web but not Windows clients, while the second approach works for Windows clients but not web, go with both!

VB .NET (.NET 2.0) Class Library configuration

I have created a class library in VB .NET. Some code in the library connects to the database. I want to create a config file that would hold the connection string.
I have created a "Settings.settings" file and stored the connection string in there.
When a class library having a settings file is built, it generates a ".dll.config" file which has the key value pairs defined in the settings file.
Problem with this is when i change the connection string in the ".dll.config" file, the library does not references these changes. I would still need to recompile the class library which would then overwrite my changes in the .dll.config file.
I need to be able to change the connection strings on the fly without having to recompile the library.
Is there a mechanism in VB.NET class library (.NET 2.0) that would let me do this?
Passing the connection string to the class library from the web page that uses its method is not a option.
I have listed a sample below, this is how i would access the string.
Public Function getsettings(ByVal Setting As String) As String
If Setting = "Demo" Then
Return My.Settings.Demo
Else
Return My.Settings.Live
End If
End Function
If you have an application which uses your library called MyApp, then the connection string defined in MyApp.exe.config will be available to your library. Generally speaking the client program should set the configuration environment, not the library.
If GetApplicationSetting("connectionString") Is Nothing Then
Throw New Exception("Could not retrieve connection string from .config file")
Else
Return ConfigurationManager.AppSettings.Item("connectionString")
End If
Make sure you have the System.Configuration framework loaded to access the ConfigurationManager.
EDIT 1: If you are using it in a web-application, then set the connection string in web.config.
EDIT 2: If you set the connection string in the ConnectionStrings section of the .exe.config or web.config you can access it using :
ConfigurationManager.ConnectionStrings("MyConnectionString")
Config files are specific to the application. So if your DLL is used by an application, the app.config or web.config needs to have the entries you are trying to use in the DLL config.
Unfortunately the "Not an option" is probably the correct option.
We have multiple libraries that have the same requirement. We set it up so that our class library directly retrieves the connection string from the web.config file of the application that is using it. When you say:
Passing the connection string to the
class library from the web page that
uses its method is not a option.
In theory, the web page is not passing the con str as a parameter, but the class library is just directly taking it from the web.config file.