I'm new to NHibernate and I wanted to create a simple project to start using it. I followed this tutorial http://www.youtube.com/watch?v=FkmFI736wMU to set up the NHibernate files and configuration. Unlike the link, I use Mysql.
I can't run the program because I get a Mapping Exception (Could not compile the mapping document: catsHibernate.Code.Cat.hbm.xml) as soon as I create a configuration object. Here is my code, Cat is a simple class with gets and sets only.
App.config
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler, NHibernate"/>
</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">Server=localhost;Database=catsdb;User ID=root;Password=root</property>
<mapping assembly="catsHibernate"/>
</session-factory>
</hibernate-configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/></startup></configuration>
Cat.hbm.xml
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="catsHibernate.code" namespace="catsHibernate.code">
<class name="Cat" table="cats">
<id name="id" column="id" type="String"></id>
<property name="name" type="String">
<column name="name" length="45" sql-type="varchar" not-null="true"/>
</property>
<property name="sex" column="sex" not-null="true" update="false"/>
<property name="weight" column="weight" not-null="true"/>
</class>
</hibernate-mapping>
Program.cs
class Program
{
static void Main(string[] args)
{
Configuration cfg = new Configuration().Configure();
ISessionFactory sessionFactory = cfg.BuildSessionFactory();
//ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
ISession session = sessionFactory.OpenSession();
ITransaction tx1 = session.BeginTransaction();
Cat c1 = new Cat();
c1.Id = "cat1";
c1.Name = "Fluffy";
c1.Sex = 'f';
c1.Weight = 3.2F;
Cat c2 = new Cat();
c2.Id = "cat2";
c2.Name = "Mittens";
c2.Sex = 'm';
c2.Weight = 4.3F;
try
{
session.Save(c1);
session.Save(c2);
tx1.Commit();
}
catch (Exception ex)
{
tx1.Rollback();
throw ex;
}
ITransaction tx2 = session.BeginTransaction();
var cats = session.CreateQuery("FROM cats").List<Cat>();
foreach (Cat c in cats)
{
Console.WriteLine(c.Name);
}
tx2.Commit();
session.Close();
}
}
Cat.hbm.xml is embedded resource. Like I said, I get a mapping exception as soon as I create a configuration object -> Configuration cfg = new Configuration().Configure(); .
What am I doing wrong here?
Edit - Stack Trace
NHibernate.MappingException was unhandled
HResult=-2146232832
Message=Could not compile the mapping document: catsHibernate.Code.Cat.hbm.xml
Source=NHibernate
StackTrace:
at NHibernate.Cfg.Configuration.LogAndThrow(Exception exception) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 342
at NHibernate.Cfg.Configuration.AddDeserializedMapping(HbmMapping mappingDocument, String documentFileName) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 530
at NHibernate.Cfg.Configuration.AddValidatedDocument(NamedXmlDocument doc) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 500
at NHibernate.Cfg.Configuration.ProcessMappingsQueue() in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 1865
at NHibernate.Cfg.Configuration.AddDocumentThroughQueue(NamedXmlDocument document) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 1857
at NHibernate.Cfg.Configuration.AddXmlReader(XmlReader hbmReader, String name) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 1850
at NHibernate.Cfg.Configuration.AddInputStream(Stream xmlInputStream, String name) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 652
at NHibernate.Cfg.Configuration.AddResource(String path, Assembly assembly) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 690
at NHibernate.Cfg.Configuration.AddAssembly(Assembly assembly) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 769
at NHibernate.Cfg.Configuration.AddAssembly(String assemblyName) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 752
at NHibernate.Cfg.Configuration.DoConfigure(ISessionFactoryConfiguration factoryConfiguration) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 1574
at NHibernate.Cfg.Configuration.Configure() in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 1433
at catsHibernate.Program.Main(String[] args) in c:\Users\Cátia\Documents\Visual Studio 2012\Projects\catsHibernate\catsHibernate\Code\Program.cs:line 15
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: NHibernate.MappingException
HResult=-2146232832
Message=persistent class catsHibernate.Code.Cat, catsHibernate.Code not found
Source=NHibernate
StackTrace:
at NHibernate.Cfg.XmlHbmBinding.Binder.ClassForFullNameChecked(String fullName, String errorMessage) in p:\nhibernate-core\src\NHibernate\Cfg\XmlHbmBinding\Binder.cs:line 105
at NHibernate.Cfg.XmlHbmBinding.Binder.ClassForNameChecked(String name, Mappings mappings, String errorMessage) in p:\nhibernate-core\src\NHibernate\Cfg\XmlHbmBinding\Binder.cs:line 117
at NHibernate.Cfg.XmlHbmBinding.ClassBinder.BindClass(IEntityMapping classMapping, PersistentClass model, IDictionary`2 inheritedMetas) in p:\nhibernate-core\src\NHibernate\Cfg\XmlHbmBinding\ClassBinder.cs:line 32
at NHibernate.Cfg.XmlHbmBinding.RootClassBinder.Bind(HbmClass classSchema, IDictionary`2 inheritedMetas) in p:\nhibernate-core\src\NHibernate\Cfg\XmlHbmBinding\RootClassBinder.cs:line 21
at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.AddRootClasses(HbmClass rootClass, IDictionary`2 inheritedMetas) in p:\nhibernate-core\src\NHibernate\Cfg\XmlHbmBinding\MappingRootBinder.cs:line 84
at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.AddEntitiesMappings(HbmMapping mappingSchema, IDictionary`2 inheritedMetas) in p:\nhibernate-core\src\NHibernate\Cfg\XmlHbmBinding\MappingRootBinder.cs:line 42
at NHibernate.Cfg.XmlHbmBinding.MappingRootBinder.Bind(HbmMapping mappingSchema) in p:\nhibernate-core\src\NHibernate\Cfg\XmlHbmBinding\MappingRootBinder.cs:line 31
at NHibernate.Cfg.Configuration.AddDeserializedMapping(HbmMapping mappingDocument, String documentFileName) in p:\nhibernate-core\src\NHibernate\Cfg\Configuration.cs:line 523
InnerException: System.IO.FileNotFoundException
HResult=-2147024894
Message=Could not load file or assembly 'catsHibernate.Code' or one of its dependencies. O sistema não conseguiu localizar o ficheiro especificado.
Source=mscorlib
FileName=catsHibernate.Code
FusionLog==== Pre-bind state information ===
LOG: DisplayName = catsHibernate.Code
(Partial)
WRN: Partial binding information was supplied for an assembly:
WRN: Assembly Name: catsHibernate.Code | Domain ID: 1
WRN: A partial bind occurs when only part of the assembly display name is provided.
WRN: This might result in the binder loading an incorrect assembly.
WRN: It is recommended to provide a fully specified textual identity for the assembly,
WRN: that consists of the simple name, version, culture, and public key token.
WRN: See whitepaper http://go.microsoft.com/fwlink/?LinkId=109270 for more information and common solutions to this issue.
LOG: Appbase = file:///C:/Users/Cátia/documents/visual studio 2012/Projects/catsHibernate/catsHibernate/bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : NHibernate, Version=3.3.1.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4.
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Users\Cátia\documents\visual studio 2012\Projects\catsHibernate\catsHibernate\bin\Debug\catsHibernate.vshost.exe.Config
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: The same bind was seen before, and was failed with hr = 0x80070002.
StackTrace:
at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection)
at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.Load(String assemblyString)
at NHibernate.Util.ReflectHelper.TypeFromAssembly(AssemblyQualifiedTypeName name, Boolean throwOnError) in p:\nhibernate-core\src\NHibernate\Util\ReflectHelper.cs:line 308
at NHibernate.Util.ReflectHelper.ClassForName(String name) in p:\nhibernate-core\src\NHibernate\Util\ReflectHelper.cs:line 181
at NHibernate.Cfg.XmlHbmBinding.Binder.ClassForFullNameChecked(String fullName, String errorMessage) in p:\nhibernate-core\src\NHibernate\Cfg\XmlHbmBinding\Binder.cs:line 99
InnerException:
You have done few things wrong. Your mapping is wrong as well - with name of the properties and class mismatch. This is the example I tried with sql server - you can just changed the connection settings to mysql.
So write a class Cat ( Property name should be uppercase but following your example above)
public class Cat
{
public string id { get; set; }
public string name { get; set; }
public string sex { get; set; }
public decimal weight { get; set; }
}
This was the table :
CREATE TABLE [dbo].[cats](
[id] [varchar](50) NOT NULL,
[name] [varchar](45) NOT NULL,
[sex] [nchar](10) NOT NULL,
[weight] [decimal](18, 0) NOT NULL
)
Now we create a hbm file( watch the case names of properties mapped), class name and assembly name
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="catsHibernate.code" namespace="catsHibernate.code"> <class name="Cat" table="cats" lazy="false">
<id name="id" column="id" type="String"></id>
<property name="name" type="String">
<column name="name" length="45" sql-type="varchar" not-null="true"/>
</property>
<property name="sex" column="sex" not-null="true" update="false"/>
<property name="weight" column="weight" not-null="true"/>
This was the configuration file for connection ( watch the assembly name):
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="dialect">NHibernate.Dialect.MsSql2012Dialect</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="connection.connection_string">Data Source=.\sqlexpress;Database=StackExchangeExample;Integrated Security=SSPI;</property>
<mapping assembly="catsHibernate.code"/>
</session-factory>
Now your program should run ( watch the name of the class in the query)
private static void Main(string[] args)
{
var cfg = new Configuration();
cfg.Configure();
ISessionFactory sessionFactory = cfg.BuildSessionFactory();
ISession session = sessionFactory.OpenSession();
ITransaction tx1 = session.BeginTransaction();
var c1 = new Cat();
c1.id = "cat1";
c1.name = "Fluffy";
c1.sex = "f";
c1.weight = new Decimal(3.2);
var c2 = new Cat();
c2.id = "cat2";
c2.name = "Mittens";
c2.sex = "m";
c2.weight = new Decimal(4.3);
try
{
session.Save(c1);
session.Save(c2);
tx1.Commit();
}
catch (Exception ex)
{
tx1.Rollback();
throw ex;
}
ITransaction tx2 = session.BeginTransaction();
IList<Cat> cats = session.CreateQuery("FROM Cat").List<Cat>();
foreach (Cat c in cats)
{
Console.WriteLine(c.name);
}
tx2.Commit();
session.Close();
}
If you'd provide complete exception trace, it'll be much more easier to find out what is wrong. But for sure, NHibernate and C# entities naming is case sensitive. Which is not the case in your snippets above
C# code:
Cat c1 = new Cat();
c1.Id = "cat1";
c1.Name = "Fluffy";
c1.Sex = 'f';
c1.Weight = 3.2F;
...
shows, that your C# entity Cat has standard naming, and should look like this (virtual keyword is essential)
public class Cat
{
public virtual string Id { get; set; }
public virtual string Name { get; set; }
...
but your mapping is targeting the lower case properties:
<id name="id" column="id" ...
<property name="name" ..
<property name="sex" ...
<property name="weight" ...
And it must be exactly the same as in C#:
<id name="Id" column="id" type="String" generator="assigned" />
<property name="Name" type="String">
<column name="name" length="45" sql-type="varchar" not-null="true"/>
</property>
<property name="Sex" column="sex" not-null="true" update="false"/>
<property name="Weight" column="weight" not-null="true"/>
Related
I am trying use NHibernate to my MySQL but I have still issue with connection on my localhost database.
Exeptions:
MySql.Data.MySqlClient.MySqlException
HResult=0x80004005
Message=Unable to connect to any of the specified MySQL hosts.
Source=MySql.Data
StackTrace:
at MySql.Data.MySqlClient.NativeDriver.Open()
at MySql.Data.MySqlClient.Driver.Open()
at MySql.Data.MySqlClient.Driver.Create(MySqlConnectionStringBuilder settings)
at MySql.Data.MySqlClient.MySqlPool.CreateNewPooledConnection()
at MySql.Data.MySqlClient.MySqlPool.GetPooledConnection()
at MySql.Data.MySqlClient.MySqlPool.TryToGetDriver()
at MySql.Data.MySqlClient.MySqlPool.GetConnection()
at MySql.Data.MySqlClient.MySqlConnection.Open()
at NHibernate.Connection.DriverConnectionProvider.GetConnection()
at NHibernate.Tool.hbm2ddl.SuppliedConnectionProviderConnectionHelper.Prepare()
at NHibernate.Tool.hbm2ddl.SchemaMetadataUpdater.GetReservedWords(Dialect dialect, IConnectionHelper connectionHelper)
at NHibernate.Tool.hbm2ddl.SchemaMetadataUpdater.Update(ISessionFactoryImplementor sessionFactory)
at NHibernate.Impl.SessionFactoryImpl..ctor(Configuration cfg, IMapping mapping, Settings settings, EventListeners listeners)
at NHibernate.Cfg.Configuration.BuildSessionFactory()
at TestE.Model.NHibernateHelper.get_Session() in C:\Users\hajek\source\repos\TestE\TestE\NHibernateHelper.cs:line 24
at TestE.Dao.DaoBase1..ctor() in C:\Users\hajek\source\repos\TestE\TestE\Dao\DaoBase.cs:line 20
at TestE.Dao.ItemDao..ctor() in C:\Users\hajek\source\repos\TestE\TestE\Dao\ItemDao.cs:line 13
at TestE.Program.Main(String[] args) in C:\Users\hajek\source\repos\TestE\TestE\Program.cs:line 16
Inner Exception 1:
WaitHandleCannotBeOpenedException: No handle of the given name exists.
Code:
namespace TestE.Model
{
public class NHibernateHelper
{
private static ISessionFactory factory;
private static MySqlConnectionStringBuilder conn_string = new MySqlConnectionStringBuilder();
public static ISession Session
{
get
{
if (factory == null)
{
Configuration cfg = new Configuration();
factory = cfg.Configure("hibernate.cfg.xml").BuildSessionFactory();
}
return factory.OpenSession();
}
}
}
}
hibernate.cfg.xml:
<?xml version="1.0" encoding="utf-8"?>
<!--
This template was written to work with NHibernate.Test.
Copy the template to your NHibernate.Test project folder and rename it in hibernate.cfg.xml and change it
for your own use before compile tests in VisualStudio.
-->
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="TestE">
<property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
<property name="connection.connection_string">
Database=todo_list;Data Source=localhost;User Id=root;Password=root;
Protocol=memory;Old Guids=True;
</property>
<property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
</session-factory>
</hibernate-configuration>
Configuration is located in ~/bin/debug and Nhibernate can see it but still can not connect to database.
----- Sorry for my English Language.------
By default, shared memory is not enabled on Windows. This may be why your connection is failing.
Remove Protocol=memory; from your connection string to use a regular TCP/IP connection.
i try to implement a custom generator class like this:
Creating a custom id generator for nHibernate
This example is in fluent Nhibernate and not what I want exactly. I want it for nhibernate with mapping.
I have the following lines of Code:
namespace webportale_ger_webservice.Routinen
{
public class NextKey : TableGenerator
{
private const Int32 SeedValue = 1048576;
public override object Generate(ISessionImplementor sessionimpl, object obj)
{
var session = NHibernateHelper.GetSession();
int counter = Convert.ToInt32(base.Generate(sessionimpl, obj));
return counter + SeedValue + 1;
}
}
}
Now I want to give this generator class the ID-property of the mapping document, like this:
<hibernate-mapping assembly="webportale ger webservice" namespace="webportale_ger_webservice.Model" xmlns="urn:nhibernate-mapping-2.2">
<class name="SPTPL" table="SPTPL" lazy="false" >
<id name="AR" column="AR" generator="webportale_ger_webservice.Routinen.NextKey"/>
But it doesn't work with generator="webportale_ger_webservice.Routinen.NextKey", the error message is the following:
NHibernate.Id.IdentifierGenerationException: Could not interpret id generator strategy: webportale_ger_webservice.Routinen.NextKey
bei NHibernate.Id.IdentifierGeneratorFactory.GetIdentifierGeneratorClass(String strategy, Dialect dialect)
bei NHibernate.Id.IdentifierGeneratorFactory.Create(String strategy, IType type, IDictionary`2 parms, Dialect dialect)
bei NHibernate.Impl.SessionFactoryImpl..ctor(Configuration cfg, IMapping mapping, Settings settings, EventListeners listeners)
bei NHibernate.Cfg.Configuration.BuildSessionFactory()
bei webportale_ger_webservice.DatabaseInterface.NHibernateHelper..cctor() in C:\Quellen\VSWebNeoBackEnd\VSWebNeoBackEnd\VSWebNeoBackEnd\project india webservice\DatabaseInterface\NHibernateHelper.cs:Zeile 34.
--- Ende der internen Ausnahmestapelüberwachung ---
bei webportale_ger_webservice.DatabaseInterface.NHibernateHelper.GetSession()
bei webportale_ger_webservice.india_webservice.InsertSP_Leistungsort(String vornameStr, String nachnameStr, String strasseStr, String hnrzusatzStr, Int32 hausnrStr, String plzStr, String ortStr, String mailStr, String dateStr, String telStr, String argef, String bemerkungStr, String arstrasse, String arplz) in C:\Quellen\VSWebNeoBackEnd\VSWebNeoBackEnd\VSWebNeoBackEnd\project india webservice\webportale_ger_webservice.asmx.cs:Zeile 382.
Does anyone know how to define the class correctly in mapping documents?
thank you.
In case, we provide a type, it is better to use full type name - mostly including the assembly name. So this should work:
<class name="SPTPL" table="SPTPL" lazy="false" >
//<id name="AR" column="AR" generator="webportale_ger_webservice.Routinen.NextKey"/>
<id name="AR" column="AR" generator="webportale_ger_webservice.Routinen.NextKey,webportale_ger_webservice"/>
Expecting that the assembly name is webportale_ger_webservice
I'm trying to load my plugin dll into separate AppDomain, but Load() method fails with FileNotFoundException. Moreover, it seems like setting PrivateBinPath property of AppDomainSetup has no effect, because in log I see "Initial PrivatePath = NULL". All plugin have strong name. Normally each plugin is stored in [Application startp path]\postplugins\[plugindir]. If I put plugins subdirectories under [Application startp path] directory, everything works. I also have tried to change AppBase property manually but it does not change.
Here is the code:
public void LoadPostPlugins(IPluginsHost host, string pluginsDir)
{
_Host = host;
var privatePath = "";
var paths = new List<string>();
//build PrivateBinPath
var dirs = new DirectoryInfo(pluginsDir).GetDirectories();
foreach (var d in dirs)
{
privatePath += d.FullName;
privatePath += ";";
}
if (privatePath.Length > 1) privatePath = privatePath.Substring(0, privatePath.Length - 1);
//create new domain
var appDomainSetup = new AppDomainSetup { PrivateBinPath = privatePath };
Evidence evidence = AppDomain.CurrentDomain.Evidence;
var sandbox = AppDomain.CreateDomain("sandbox_" + Guid.NewGuid(), evidence, appDomainSetup);
try
{
foreach (var d in dirs)
{
var files = d.GetFiles("*.dll");
foreach (var f in files)
{
try
{
//try to load dll - here I get FileNotFoundException
var ass = sandbox.Load(AssemblyName.GetAssemblyName(f.FullName));
var f1 = f;
paths.AddRange(from type in ass.GetTypes()
select type.GetInterface("PluginsCore.IPostPlugin")
into iface
where iface != null
select f1.FullName);
}
catch (FileNotFoundException ex)
{
Debug.WriteLine(ex);
}
}
}
}
finally
{
AppDomain.Unload(sandbox);
}
foreach (var plugin in from p in paths
select Assembly.LoadFrom(p)
into ass
select
ass.GetTypes().FirstOrDefault(t => t.GetInterface("PluginsCore.IPostPlugin") != null)
into type
where type != null
select (IPostPlugin)Activator.CreateInstance(type))
{
plugin.Init(host);
plugin.GotPostsPartial += plugin_GotPostsPartial;
plugin.GotPostsFull += plugin_GotPostsFull;
plugin.PostPerformed += plugin_PostPerformed;
_PostPlugins.Add(plugin);
}
}
And here is the log:
'FBTest.vshost.exe' (Managed (v4.0.30319)): Loaded 'D:\VS2010Projects\PNotes - NET\pnfacebook\FBTest\bin\Debug\postplugins\pnfacebook\pnfacebook.dll', Symbols loaded.
A first chance exception of type 'System.IO.FileNotFoundException' occurred in FBTest.exe
System.IO.FileNotFoundException: Could not load file or assembly 'pnfacebook, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e2a2192d22aadc7' or one of its dependencies. The system cannot find the file specified.
File name: 'pnfacebook, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e2a2192d22aadc7'
at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks)
at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection)
at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.Load(String assemblyString)
at System.UnitySerializationHolder.GetRealObject(StreamingContext context)
at System.AppDomain.Load(AssemblyName assemblyRef)
at PNotes.NET.PNPlugins.LoadPostPlugins(IPluginsHost host, String pluginsDir) in D:\VS2010Projects\PNotes - NET\pnfacebook\FBTest\PNPlugins.cs:line 71
=== Pre-bind state information ===
LOG: User = ANDREYHP\Andrey
LOG: DisplayName = pnfacebook, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e2a2192d22aadc7
(Fully-specified)
LOG: Appbase = file:///D:/VS2010Projects/PNotes - NET/pnfacebook/FBTest/bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config.
LOG: Post-policy reference: pnfacebook, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e2a2192d22aadc7
LOG: Attempting download of new URL file:///D:/VS2010Projects/PNotes - NET/pnfacebook/FBTest/bin/Debug/pnfacebook.DLL.
LOG: Attempting download of new URL file:///D:/VS2010Projects/PNotes - NET/pnfacebook/FBTest/bin/Debug/pnfacebook/pnfacebook.DLL.
LOG: Attempting download of new URL file:///D:/VS2010Projects/PNotes - NET/pnfacebook/FBTest/bin/Debug/pnfacebook.EXE.
LOG: Attempting download of new URL file:///D:/VS2010Projects/PNotes - NET/pnfacebook/FBTest/bin/Debug/pnfacebook/pnfacebook.EXE.
when you load an assembly into the AppDomain in that way, it is the current AppDomain's PrivateBinPath that is used to find the assembly.
For your example, when I added the following to my App.config it ran fine:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="[PATH_TO_PLUGIN]"/>
</assemblyBinding>
</runtime>
This is not very useful to you though.
What I did instead was to create a new assembly that contained the IPostPlugin and IPluginsHost interfaces, and also a class called Loader that looked like this:
public class Loader : MarshalByRefObject
{
public IPostPlugin[] LoadPlugins(string assemblyName)
{
var assemb = Assembly.Load(assemblyName);
var types = from type in assemb.GetTypes()
where typeof(IPostPlugin).IsAssignableFrom(type)
select type;
var instances = types.Select(
v => (IPostPlugin)Activator.CreateInstance(v)).ToArray();
return instances;
}
}
I keep that new assembly in the application root, and it doesn't need to exist in the plugin directories (it can but won't be used as the application root will be searched first).
Then in the main AppDomain I did this instead:
sandbox.Load(typeof(Loader).Assembly.FullName);
Loader loader = (Loader)Activator.CreateInstance(
sandbox,
typeof(Loader).Assembly.FullName,
typeof(Loader).FullName,
false,
BindingFlags.Public | BindingFlags.Instance,
null,
null,
null,
null).Unwrap();
var plugins = loader.LoadPlugins(AssemblyName.GetAssemblyName(f.FullName).FullName);
foreach (var p in plugins)
{
p.Init(this);
}
_PostPlugins.AddRange(plugins);
So I create an instance of the known Loader type, and then get that to create the plugin instances from within the plug-in AppDomain. That way the PrivateBinPaths are used as you want them to be.
One other thing, the private bin paths can be relative so rather than adding d.FullName you could add pluginsDir + Path.DirectorySeparatorChar + d.Name to keep the final path list short. That's just my personal preference though! Hope this helps.
Thanks a lot to DedPicto and James Thurley ; I was able to implement a complete solution, I posted in this post.
I had the same problem as Emil Badh : if you try to return from "Loader" class an interface that represents a concrete class that is unknown in current AppDomain, you get a "Serialization Exception".
It is because the concrete type tries to be deserialized.
The solution: I was able to return from "Loader" class a concrete type of a "custom proxy" and it works. See referenced post for details :
// Our CUSTOM PROXY: the concrete type which will be known from main App
[Serializable]
public class ServerBaseProxy : MarshalByRefObject, IServerBase
{
private IServerBase _hostedServer;
/// <summary>
/// cstor with no parameters for deserialization
/// </summary>
public ServerBaseProxy ()
{
}
/// <summary>
/// Internal constructor to use when you write "new ServerBaseProxy"
/// </summary>
/// <param name="name"></param>
public ServerBaseProxy(IServerBase hostedServer)
{
_hostedServer = hostedServer;
}
public string Execute(Query q)
{
return(_hostedServer.Execute(q));
}
}
This proxy could be returned and use as if it was the real concrete type !
How can I configure NHibernate to connect to both a MySQLserver and a Microsoft SQL server 2008? I do want to copy data from one server to another. I heard of NHibernate shared.
I've struggled quite a bit few months ago.
My problem was with MS Sql Server and Oracle.
What I've done is to create two separate config files for nhibernate:
sql.nhibernate.config
<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<reflection-optimizer use="false" />
<session-factory name="BpSpedizioni.MsSql">
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>
<!-- <property name="connection.connection_string">Data Source=(local); Initial Catalog=NHibernate; Trusted_Connection=true;</property> -->
<property name="current_session_context_class">web</property>
<property name="adonet.batch_size">100</property>
<property name="command_timeout">120</property>
<property name="max_fetch_depth">3</property>
<property name='prepare_sql'>true</property>
<property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
<property name='proxyfactory.factory_class'>NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
<mapping assembly="BpSpedizioni.Services"/>
</session-factory>
</hibernate-configuration>
ora.nhibernate.config
<?xml version="1.0" encoding="utf-8"?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<reflection-optimizer use="false" />
<session-factory name="BpSpedizioni.Oracle">
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.OracleDataClientDriver</property>
<property name="dialect">NHibernate.Dialect.Oracle10gDialect</property>
<!-- <property name="connection.connection_string">Data Source=(local); Initial Catalog=NHibernate; Trusted_Connection=true;</property> -->
<property name="current_session_context_class">web</property>
<property name="adonet.batch_size">100</property>
<property name="command_timeout">120</property>
<property name="max_fetch_depth">3</property>
<property name='prepare_sql'>true</property>
<property name="query.substitutions">true 1, false 0, yes 'Y', no 'N'</property>
<property name='proxyfactory.factory_class'>NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>
<mapping assembly="BpSpedizioni.Services"/>
</session-factory>
</hibernate-configuration>
I use this simple class to build my nhibernate SessionFactory:
public class NHibernateSessionFactory
{
private ISessionFactory sessionFactory;
private readonly string ConnectionString = "";
private readonly string nHibernateConfigFile = "";
public NHibernateSessionFactory(String connectionString, string nHConfigFile)
{
this.ConnectionString = connectionString;
this.nHibernateConfigFile = nHConfigFile;
}
public ISessionFactory SessionFactory
{
get { return sessionFactory ?? (sessionFactory = CreateSessionFactory()); }
}
private ISessionFactory CreateSessionFactory()
{
Configuration cfg;
cfg = new Configuration().Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, this.nHibernateConfigFile));
// With this row below Nhibernate searches for the connection string inside the App.Config.
// cfg.SetProperty(NHibernate.Cfg.Environment.ConnectionStringName, System.Environment.MachineName);
cfg.SetProperty(NHibernate.Cfg.Environment.ConnectionString, this.ConnectionString);
#if DEBUG
cfg.SetProperty(NHibernate.Cfg.Environment.GenerateStatistics, "true");
cfg.SetProperty(NHibernate.Cfg.Environment.ShowSql, "true");
#endif
return (cfg.BuildSessionFactory());
}
}
As you can see I pass to my NHibernateSessionFactory a connection string (I prefer to save it in my app config file) and the name (without the path) of the nhibernate config file.
I personally use a DI container (StructureMap) and you can achieve something very cool defining a registry class:
public class NhibernateRegistry : Registry
{
public NhibernateRegistry()
{
For<ISessionFactory>()
.Singleton()
.Add(new NHibernateSessionFactory(<oracle connection string>, "ora.nhibernate.config").SessionFactory)
.Named("OracleSF");
For<ISession>()
.HybridHttpOrThreadLocalScoped()
.Add(o => o.GetInstance<ISessionFactory>("OracleSF").OpenSession())
.Named("OracleSession");
For<ISessionFactory>()
.Singleton()
.Add(new NHibernateSessionFactory(<ms sql connection string>, "sql.nhibernate.config").SessionFactory)
.Named("MsSqlSF");
For<ISession>()
.HybridHttpOrThreadLocalScoped()
.Add(o => o.GetInstance<ISessionFactory>("MsSqlSF").OpenSession())
.Named("MsSqlSession");
}
}
in which you can use named instances.
My services layer than uses a StructureMap registry class where you can define the constructors:
this.For<IOrdersService>()
.HybridHttpOrThreadLocalScoped()
.Use<OrdersService>()
.Ctor<ISession>("sessionMDII").Is(x => x.TheInstanceNamed("OracleSession"))
.Ctor<ISession>("sessionSpedizioni").Is(x => x.TheInstanceNamed("MsSqlSession"));
For your Service implementation:
public class OrdersService : IOrdersService
{
private readonly ISession SessionMDII;
private readonly ISession SessionSpedizioni;
public OrdersService(ISession sessionMDII, ISession sessionSpedizioni)
{
this.SessionMDII = sessionMDII;
this.SessionSpedizioni = sessionSpedizioni;
}
...
}
It's not clear what your use case is, but you will simply need to create 2 session factories. One will use your mySQL dialect, connection string, etc... and the other will use the SQL Server equivalents.
Just avoid including any custom SQL in your mappings and this should work fine.
Here's the code raising the exception:
public static class NHibernateSessionManager
{
private static ISessionFactory sessionFactory = new Configuration().Configure().BuildSessionFactory();
public static ISession GetSession(string clientId)
{
if (ContextSession == null)
ContextSession = sessionFactory.OpenSession(new OracleIntercerptor(clientId.ToUpper()));
else
((OracleConnection)ContextSession.Connection).ClientId = clientId;
return ContextSession;
}
// - snip -
}
and the call to the code where the exception is raised:
private ISession NHibernateSession
{
get
{
return NHibernateSessionManager.GetSession(SessionWrapper.GetUser());
}
}
I get a TypeInitializationException
{"The type initializer for
'Sigaf.Presupuesto.EntidadesDAL.NHibernate.NHibernateSessionManager'
threw an exception."}
With an inner exception of
{"Could not create the driver from
NHibernate.Driver.OracleDataClientDriver."}
A few more inner exceptions lead me to a NRE:
Object reference not set to an
instance of an object.
at
NHibernate.Driver.OracleDataClientDriver..ctor()
NHibernate v3.0
Target Framework v4.0
This code implementation is working for other, similar, solutions.
Oh, the Hibernate.config file:
<?xml version="1.0"?>
<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="current_session_context_class">web</property>
<property name="proxyfactory.factory_class">NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
<property name="connection.driver_class">NHibernate.Driver.OracleDataClientDriver</property>
<property name="connection.connection_string_name">Sigaf</property>
<property name="default_schema">PRE</property>
<property name="show_sql">true</property>
<mapping assembly="Sigaf.Presupuesto.EntidadesDAL" />
</session-factory>
</hibernate-configuration>
Make sure the actual Oracle driver is in your application bin folder.
In Visual Studio you should add a reference to Oracle.DataAcess.dll in your project for example.
Select the DLL => Right click it => In the Properties grid select Copy Local = True.
This should solve your problem.