Configuring NHibernate via Web.config in ASP.NET 4.0 - c#

So my unit tests are green, time to integrate this shiny new NHibernate-driven DAL in to my web app! I don't really want to maintain two configuration files so I've migrated hibernate.cfg.xml in to my Web.config file (i.e. I copypasta'd the contents of hibernate.cfg.xml in to my Web.config). Here is the relevant bits from my Web.config:
<configSections>
<section name="combres" type="Combres.ConfigSectionSetting, Combres, Version=2.0.0.0, Culture=neutral, PublicKeyToken=49212d24adfbe4b4"/>
<section name="nhibernate" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"/>
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler,log4net"/>
</configSections>
<nhibernate xmlns="urn:nhibernate-configuration-2.2">
<session-factory name="">
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Data Source=(local)\SQLExpress;Initial Catalog=MyProject;Integrated Security=True</property>
<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<property name='proxyfactory.factory_class'>NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
<listener class="MyProject.Sql.Listeners.SaveEventListener, MyProject" type="save"/>
<listener class="MyProject.Sql.Listeners.UpdateEventListener, MyProject" type="update"/>
</session-factory>
</nhibernate>
In Global.asax, on Application_Start, I try to initialize my configuration:
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
SessionProvider.Initialize();
}
All this really does is call new Configuration().Configure().AddAssembly("MyProject"); in accordance with the configuration code above.
Interesting result: When I first hit the page, an exception is thrown:
[FileNotFoundException: Could not find file 'D:\Build\MyProject\Source\MyProject.Web\bin\hibernate.cfg.xml'.]
Well, I put the configuration in Web.config, shouldn't it be lookign there? Do I need to indicate "hey, NHibernate, pay attention -- the config data is in Web.config, dummy!" anywhere?
When I then hit F5, the page comes up. Hurray! Now I try to do something with data access and I get this exception:
[ProxyFactoryFactoryNotConfiguredException: The ProxyFactoryFactory was not configured.
Initialize 'proxyfactory.factory_class' property of the session-factory configuration section with one of the available NHibernate.ByteCode providers.
Example:
<property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
Example:
<property name='proxyfactory.factory_class'>NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>]
Huh, that's kinda weird too -- this worked just fine in test with configuration in hibernate.cfg.xml...and I am specifying this property in my Web.config...I wonder what could possibly be up?
So, anyone have any ideas? Any help in solving this mystery would be super!
*Update: I found the issue. It looks like I wasn't using the correct type in my configs section! D'oh. I have a complete write up on my blog.

Try calling the .Configure() method at the end:
new Configuration().AddAssembly("MyProject").Configure();
Or if you prefer put it into the web.config:
<nhibernate xmlns="urn:nhibernate-configuration-2.2">
<session-factory name="">
...
<mapping assembly="MyProject" />
</session-factory>
</nhibernate>
and then:
new Configuration().Configure();
Also make sure that the NHibernate.ByteCode.Castle.dll assembly is referenced in your web project.

It turns out that I was using the wrong type in the configuration section. You need to use NHibernate's section handler, not the generic .NET one. The behavior I was seeing was because it was all loaded in a singleton. On first visit, the configuration would fail. On subsequent visits it would just throw weird errors because the configuration failed originally!
There is one other caveat -- I have a complete writeup on my blog.

Related

Make the web.config dynamic

We have an application and it is deployed across different pipeline dedicated for various release.
For ex - pipeline A - dedicated for march release
pipeline B - for June release etc
Within each pipeline we various environment like DEV, SIT etc
Now , with release , while deploying code , we need to make changes in the webcofig file , because the urls that we have in config are pipeline and environment dependent.
For Example we have a web server - box 1 for dev environment .
we have Pipeline A , Pipeline B deployed as websites. The web.config of pipeline A will look like -
<configMap hostnameList="box1" name="DevEnvironment">
<include set="Dev" />
</configMap>
<configSet name="Dev">
<add key="someUrl" value="http://somapp-piplelineA-Dev.app.com"/>
</configSet>
The web.config of pipeline B will look like -
<configMap hostnameList="box1" name="DevEnvironment">
<include set="Dev" />
</configMap>
<configSet name="Dev">
<add key="someUrl" value="http://somapp-piplelineB-Dev.app.com"/>
</configSet>
If you see this config , in the value for key someurl , the pipelineA was changed to pipelineB. These changes are tiresome when there are a lot of keys. So, we want to create a single web.config that can be used by all environment and which would not require any change.
With Octopus Deploy you can deploy your web applications semi- or fully-automatically. But also it can perform Web.config Transformation for each environment separately.
you can use config transforms ability built in inside visual studio
if you create a new asp .net web project you will see a sample inside web.debug.config and web.release.config.
you can also right click on web.config and click Add Config Transform and you will have a config transform file for each of your build configurations.
you can also use SlowCheetah. it is a very handy extension.
This is what I implemented to allow us to have the config dynamically created depending on the build type, utilizing build events.
Which will allow you to have 1 config to rule them all :)
https://xmlpreprocess.codeplex.com/
Project Description
XmlPreprocess is a command-line utility that can modify annotated XML files much like a code preprocessor. It is useful for deploying configuration files to different environments making substitutions such as connection strings. It is easily integrated into almost any script, build tool or deployment package to simplify and centralize your deployment strategy.
My build event
C:\XMLPreprocessor\XmlPreprocess.exe /i "C:\AppConfig\Core.config" /dbkind mssql /db "Server=localhost\SQLEXPRESS;Database=DB1;User Id=dbreader; Password=pass1;" /e $(ConfigurationName)
This is an example of my configuration XML file the {} params are retrieved from a SQL configuration database which contains the release type (1=Debug,2=Test,3=Release) and the values are populated accordingly.
<Nini>
<Section Name="AppSettings">
<!-- ifdef _xml_preprocess -->
<!--
<Key Name="RSAKeyStrength" Value="${RSAKeyStrength}"/>
<Key Name="EventLog_Name" Value="{EventLog_Name}"/>
<Key Name="DomainAddress" Value="${DomainAddress}"/>
<Key Name="AuthIssuer" Value="${AuthIssuer}"/>
-->
<!-- else -->
<Key Name="RSAKeyStrength" Value="2048"/>
<Key Name="EventLog_Name" Value="MyApp"/>
<Key Name="DomainAddress" Value="mydomain.com"/>
<Key Name="AuthIssuer" Value="auth.domain.com"/>
<!-- endif -->
</Section>
<Section Name="ConnectionStrings">
<!-- ifdef _xml_preprocess -->
<!--
<Key Name="IdentityUserModelEntities" Value="data source=${DB1ConnectionString};MultipleActiveResultSets=True"/>
<Key Name="DB1ModelEntities" Value="data source=${DB1ConnectionString};MultipleActiveResultSets=True"/>
<Key Name="LoggingDB1Entities" Value="data source=${LoggingDB1ConnectionString};MultipleActiveResultSets=True"/>
-->
<!-- else -->
<Key Name="IdentityUserModelEntities" Value="data source=localhost\SQLEXPRESS;initial catalog=DB1;user id=admin;password=pass1;MultipleActiveResultSets=True"/>
<Key Name="DB1ModelEntities" Value="data source=localhost\SQLEXPRESS;initial catalog=DB1;user id=admin;password=pass1;MultipleActiveResultSets=True"/>
<Key Name="LoggingDB1Entities" Value="data source=localhost\SQLEXPRESS;Initial Catalog=LoggingDB1;user id=logging_admin;Password=pass1;MultipleActiveResultSets=True"/>
<!-- endif -->
</Section>
</Nini>

NHibernate works when called from one project, but not from the other

I'm creating my first application using NHibernate. Unfortunately, I encountered a problem I cannot solve:
I'm accessing the database from "DAL" project that contains CRUD methods and NHibernateHelper class.
I wrote a test project and I tried to add an object to DB - it works perfectly. But when I try to call the same method from my application's ViewModel (it's in the other project as well) it throws an error at configuration.BuildSessionFactory() in the code below:
private static ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(Address).Assembly);
_sessionFactory = configuration.BuildSessionFactory();
}
return _sessionFactory;
}
}
The exception:
NHibernate.HibernateException: Could not create the driver from NHibernate.Driver.OracleDataClientDriver.
System.Reflection.TargetInvocationException: {"Exception has been thrown by the target of an invocation."}
System.NullReferenceException: {"Object reference not set to an instance of an object."}
In my test project I added reference to Oracle.DataAccess.dll and created App.config as it throws the same error without it:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<qualifyAssembly partialName="Oracle.DataAccess"
fullName="Oracle.DataAccess,
Version=4.112.2.0,
Culture=neutral,
PublicKeyToken=89b483f429c47342" />
</assemblyBinding>
</runtime>
</configuration>
I made the same thing in my project containing ViewModel in which I need to get data from DB, but it didn't help. I also set Copy Local to True for that reference, but to no avail.
It's my App.config:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="dialect">
NHibernate.Dialect.Oracle10gDialect
</property>
<property name="connection.driver_class">
NHibernate.Driver.OracleDataClientDriver
</property>
<property name="connection.connection_string">
User Id=****;
Password=****;
Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=
(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))
(CONNECT_DATA=(SERVICE_NAME=xe)));
Pooling=true;
Enlist=false;
Statement Cache Size=50;
Min Pool Size=10;
Incr Pool Size=5;
Decr Pool Size=2;
</property>
<property name="show_sql">
true
</property>
</session-factory>
</hibernate-configuration>
I'm using NHibernate v 3.3.1.4000, Oracle 11g xe and 64-bit Windows 7 (I cannot choose to debug on 32 or 64-bit, there is only one possibility to select: "Active (Any CPU)" )
What can be the reason that I can use it from test project, but I cannot do it from the other?
Thank you in advance
Do you have a reference to driver's dll in your web project or in your DAL? it should be on your web project with Copy Local set to true, see this similar question
The problem is solved. I had to put app.config in main project, not in dll library from which I use the database. I didn't know that app.config placed in class library will be ignored.

How to override settings.settings variable by app.config variable

How can I change (or override) a settings.settings variable by adding a variable to the app.config on production?
Is this possible anyway?
You have to directly reference the applicationSettings you're trying to override and explicitly specify the property that has a replaced value.
<configuration>
<!-- section definitions for all elements in <configuration> tag -->
<configSections>
<!-- section group, meaning: there will be a <applicationSettings> tag in you configuration-->
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<!-- defines that there will be a <appname.Properties.Settings> tag inside your <applicationSettings> tag -->
<section name="appname.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</sectionGroup>
</configSections>
<applicationSettings>
<appname.Properties.Settings>
<!-- name of the property you want to override -->
<setting name="setting1" serializeAs="String">
<!-- new value -->
<value>new string value</value>
</setting>
</appname.Properties.Settings>
</applicationSettings>
</configuration>
It depends on the scope of the settings. If its an application scope setting changing its value in app.config is sufficient.
However, if its a user scope setting then the value present in app.config is just the default used to new users and every user that already used the application will have the currently used value stored in a separate file, the user.config, so changing the value in app.config will have no effect to users that already run the application once.
Due to this changing the value of an user scope setting can be a troublesome task. You can check the following answer for more information on changing a user scope setting:
Changing User Scope Application Setting
Use different config files for production and for you. Basically on production you would compile in RELEASE, so if you use Visual Studio for it, use post build events to copy RELEASE config file in case you prepare a build for production.
I would prefer this instead of changing it from the code, as for someone else is much easier to see the differenc in config file, then going deep into the code to find all the if/else stuff.
For an application scope connection string value:
<connectionStrings>
<add name="appname.Properties.Settings.setting1" connectionString="test string" providerName="dbProvider"/>
</connectionStrings>
Only through code:
e.g.
if (bool.Parse(ConfigurationManager.AppSettings["overridethis"].ToString()))
{
//use overridden value
}
If however, your issue is maintaining different configuration values in different environments, then I would use AppSettings instead.
You can then use a developer override file.
<appSettings file="..\user.config">
See http://www.compiledthoughts.com/2005/03/overriding-webconfig-app-settings-with.html

NHibernate 2.1.2 - how to disable reflection optimizer

I want to disable reflection optimization (testing purposes), but i don't know where to do it. NH 2.1.2 uses hibernate-configuration in XML, and docs clearly state that this setting can not be set here. :/ I tried doing it the old App.config way with key/value pairs, no luck ...
Also, did NH 2+ version change something about reflection optimization?
Did you try
<add key="hibernate.use_reflection_optimizer" value="false" />
?
From the Hibernate Community:
I was able to set the
hibernate.use_reflection_optimizer
property in the web.config file as
follows. Note that the setting did not
work within the
hibernate-configuration section, so I
had to place it in a new nhibernate
section. The code now appears to be
working in a medium trust environment
( godaddy )
<configSections>
<section name="hibernate-configuration"
type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"
requirePermission="false"/>
<section name="nhibernate"
type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089"
requirePermission="false"/>
</configSections>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MySQLDialect</property>
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
<property name="connection.connection_string">blahblah</property>
</session-factory>
</hibernate-configuration>
<nhibernate>
<add key="hibernate.use_reflection_optimizer" value="false" />
</nhibernate>

An exception occurred during configuration of persistence layer

I'm doing a project in Nhibernate with MySql in asp.net. In that while executing the code I got the error like
An exception occurred during configuration of persistence layer
in the below line
ISessionFactory factory = new NHibernate.Cfg.Configuration().Configure).BuildSessionFactory();
So let me help to trouble shoot the error.
Here s my Configuration file
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<!-- an ISessionFactory instance -->
<session-factory>
<!-- properties -->
<property name="connection.provider">
NHibernate.Connection.DriverConnectionProvider
</property>
<property name="connection.driver_class">
NHibernate.Driver.MySqlDataDriver
</property>
<property name="connection.connection_string">
Server=localhost;Database=hrms;User ID=test;Password=test;
</property>
<property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
<property name="show_mysql">true</property>
<!-- mapping files -->
<mapping resource="WebApp1.Job.hbm.xml" assembly="WebApp1" />
</session-factory>
</hibernate-configuration>
Incomplete configuration perhaps? Try manual configuration initialization like the following:
NHibernate.Cfg.Configuration cfg = new NHibernate.Cfg.Configuration();
cfg.SetProperty("dialect", "NHibernate.Dialect.MySQLDialect");
cfg.SetProperty("connection.driver_class", "NHibernate.Driver.MySqlDataDriver");
cfg.SetProperty("connection.connection_string", "Server=YourServer;Database=YourDatabase;User ID=YourId;Password=YourPass;CharSet=utf8");
cfg.SetProperty("proxyfactory.factory_class", "NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu");
cfg.AddAssembly("Your.Assembly.Name");
ISessionFactory sessionFactory = cfg.BuildSessionFactory();
If everything works, move it to XML if you like.
Please read the inner exception that is being thrown and it's very likely you would know the cause. In my experience it can be as simple as the code is looking for the hibernate.cfg.xml file in bin/debug and could not find it.
I had a similar problem. Problem was that I used in Web.config:
<section name="nhibernate" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
<nhibernate xmlns="urn:nhibernate-configuration-2.2">
.
.
.
</nhibernate>
instead of:
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate" />
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
.
.
.
</hibernate-configuration>

Categories

Resources