Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"An invalid or incomplete configuration was used while creating a SessionFactory" NHibernate in Web Services

As the title says, Iam getting an error that says: "An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail."

I'll start with the code.

Database:

User Table:

CREATE TABLE [dbo].[User] (
    [Id]           UNIQUEIDENTIFIER NOT NULL,
    [Username]     NVARCHAR (50)    NULL,
    [PasswordHash] CHAR (64)        NOT NULL,
    [Salt]         CHAR (64)        NOT NULL,
    [Role]         UNIQUEIDENTIFIER NOT NULL,
    [Token]        NVARCHAR (50)    NOT NULL,
    [TokenStamp]   DATETIME         NULL,
    CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC),
    CONSTRAINT [FK_User_Role] FOREIGN KEY ([Role]) REFERENCES [dbo].[Role] ([Id])
);

Role Table:

CREATE TABLE [dbo].[Role] (
    [Id]   UNIQUEIDENTIFIER NOT NULL,
    [Name] NVARCHAR (50)    NULL,
    CONSTRAINT [PK_Role] PRIMARY KEY CLUSTERED ([Id] ASC)
);

User Class:

using System;

    namespace Models
    {
        public class User : EntityBase
        {
            public virtual string Username { get; set; }
            public virtual string PasswordHash { get; set; }
            public virtual string Salt { get; set; }
            public virtual Guid Role { get; set; }
            public virtual string Token { get; set; }
            public virtual DateTime TokenStamp { get; set; }
        }
    }

Role Class:

namespace Models
{
    public class Role : EntityBase
    {
        public virtual string Name { get; set; }
    }
}

EntityBase:

using System;

namespace Models
{
    public class EntityBase
    {
        public virtual Guid Id { get; set; }
    }
}

User Map:

using FluentNHibernate.Mapping;
using Models;

namespace NHibernate.Mapping
{
    public class UserMap : ClassMap<User>
    {
        public UserMap()
        {
            Table("User");
            Id(x => x.Id).GeneratedBy.GuidComb();
            LazyLoad();
            References(x => x.Role).Column("Role");
            Map(x => x.Username).Column("Username");
            Map(x => x.PasswordHash).Column("PasswordHash").Not.Nullable();
            Map(x => x.Salt).Column("Salt").Not.Nullable();
            Map(x => x.Token).Column("Token").Not.Nullable();
            Map(x => x.TokenStamp).Column("TokenStamp");
        }
    }
}

Role Map:

using FluentNHibernate.Mapping;
using Models;

namespace NHibernate.Mapping
{
    public class RoleMap : ClassMap<Role>
    {
        public RoleMap()
        {
            Table("Role");
            Id(x => x.Id).GeneratedBy.GuidComb();
            LazyLoad();
            Map(x => x.Name).Column("Name");
        }
    }
}

CustomForeignKeyConvention:

using FluentNHibernate;
using FluentNHibernate.Conventions;

namespace NHibernate.Conventions
{
    public class CustomForeignKeyConvention : ForeignKeyConvention
    {
        protected override string GetKeyName(Member property, System.Type type)
        {
            if (property == null)
            {
                return type.Name;
            }

            return property.Name;
        }
    }
}

Session Factory:

using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using NHibernate.Conventions;

namespace NHibernate
{
    public static class SessionFactory
    {
        private static ISessionFactory _sessionFactory;

        public static ISessionFactory Instance
        {
            get
            {
                if (_sessionFactory == null)
                {
                    _sessionFactory = CreateSessionFactory();
                }

                return _sessionFactory;
            }
        }

        private static ISessionFactory CreateSessionFactory()
        {
            return Fluently.Configure()
                        .Database(MsSqlConfiguration.MsSql2012
                            .ConnectionString(c => c.FromConnectionStringWithKey("DatabaseConnectionString")))
                        .Mappings(m =>
                        {
                            m.FluentMappings.Conventions.AddFromAssemblyOf<CustomForeignKeyConvention>();
                            m.FluentMappings.AddFromAssemblyOf<Models.EntityBase>();
                        })
                        .BuildSessionFactory();
        }
    }
}

WebService.cs

using System.Linq;
using System.Net;
using System.Web.Services;
using NHibernate;
using Models;

[WebService(Namespace = "http://LambdAlarm.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

public class LambdAlarmWebService : WebService
{
    [WebMethod]
    public HttpStatusCode Login(string username, string password)
    {
        var factory = SessionFactory.Instance;
        var session = factory.OpenSession();
        var result = session.QueryOver<User>().List<User>();

        var login = result.Where(u => u.Username == username).Where(p => p.PasswordHash == password);

        return HttpStatusCode.NotFound;
    }
}

So yeah... This is not an easy task. I think there is something with the Foreign Key relationship in the database with the User and Role tables. The Role Column shall be referenced to the Id in the Role Table.

Please help!

like image 616
Andre Korosh Kordasti Avatar asked Dec 03 '14 14:12

Andre Korosh Kordasti


2 Answers

The problem is that References() is meant to reference another entity, not a type. If you want to use a type, you should use Map(x => x.Role) instead of References(x => x.Role)

Change User to this:

public class User : EntityBase
{
    public virtual string Username { get; set; }
    public virtual string PasswordHash { get; set; }
    public virtual string Salt { get; set; }
    public virtual Role Role { get; set; } //CHANGED HERE
    public virtual string Token { get; set; }
    public virtual DateTime TokenStamp { get; set; }
}

And your UserMap to:

public UserMap()
{
    Table("User");
    Id(x => x.Id).GeneratedBy.GuidComb();
    LazyLoad();
    References(x => x.Role).Column("Role");
    Map(x => x.Username).Column("Username");
    Map(x => x.PasswordHash).Column("PasswordHash").Not.Nullable();
    Map(x => x.Salt).Column("Salt").Not.Nullable();
    Map(x => x.Token).Column("Token").Not.Nullable();
    Map(x => x.TokenStamp).Column("TokenStamp");
}

Also, there's no reason to specify your column names when you're mapping with Fluent NHibernate. By default it will just use the name of your property, so something like Map(x => x.Name).Column("Name").Not.Nullable() is just the same as, Map(x => x.Name).Not.Nullable()

Some other suggestions:

Make a base class for your mapping to make it easier:

public abstract class ClassMapBase<T> : ClassMap<T> where T: EntityBase
{
    protected ClassMapBase()
    {
        Id(x => x.Id).Not.Nullable().GeneratedBy.GuidComb();
        LazyLoad();
    }
}

Also, I'm surprised that NHibernate isn't complaining about your Id on EntityBase having a public setter. It should be set to protected or private. There's also no need to specify your table name, unless you want it to be something different than the name of your entity

like image 179
Jedediah Avatar answered Sep 17 '22 22:09

Jedediah


Although there is a correct answer I will just let another solution others may find useful. This error is caused when your application is not reachable to your database. So:

  1. check in services.exe and see if your SQL Server is running or not
  2. OR simple solution, check your connection string is pointing to your database or not.
like image 25
Prayan shakya Avatar answered Sep 19 '22 22:09

Prayan shakya