Interceptors with StructureMap and Fluent NHibernate - fluent-nhibernate

I have successfully configured StrctureMap and FluentNHibernate to work together with a parameter-less constructor. What I need to do now is set the interceptor with parameters.
The following code below works well in my MVC application:
protected void Application_Start()
{
//Code removed from here to save space...
ObjectFactory.Initialize(x => {
x.For<IInterceptor>().Singleton().Use(context => new MyInterceptor());
x.For<ISessionFactory>().Singleton().Use(context => CreateSessionFactory(context.GetInstance<IInterceptor>()));
x.For<ISession>().HttpContextScoped().Use(context => context.GetInstance<ISessionFactory>().OpenSession());
x.For<IAuditDao>().Use<AuditDao>().Ctor<ISessionFactory>().Is(context => context.GetInstance<ISessionFactory>());
});
}
public static ISessionFactory CreateSessionFactory(IInterceptor interceptor)
{
return Fluently.Configure()
.Database(MySQLConfiguration
.Standard
.ConnectionString(c => c.FromConnectionStringWithKey("MySqlConnectionString")))
.Mappings(m => { m.FluentMappings.Add<AuditItemMap>(); })
.ExposeConfiguration(config => new SchemaUpdate(config).Execute(true, true))
.ExposeConfiguration(config => config.SetInterceptor(interceptor))
.BuildSessionFactory();
}
What I now need to do is pass an instance of AuditDao into the the interceptor. At the moment 'MyInterceptor' which inherits from the NHibernate 'EmptyInterceptor' has two constructors:
public class MyInterceptor : EmptyInterceptor
{
private IAuditDao AuditDao;
public MyInterceptor()
{
}
public MyInterceptor(IAuditDao auditDao)
{
AuditDao = auditDao;
}
}
Now obviously an instance of AuditDao needs an instance of SessionFactory and SessionFactory would need an instance of AuditDao.
How do I solve this circular reference problem?

Related

Servicestack NHibernate Auth Repo No CurrentSessionContext configured

I have the following configuration:
_container = new WindsorContainer ();
var factory = new SessionFactoryManager().CreateSessionFactory();
_container.Register(Component.For<NHibernate.ISessionFactory>().Instance(factory));
And then elsewhere I have:
var authRepo = new NHibernateUserAuthRepository (_container.Resolve<NHibernate.ISessionFactory>());
_container.Register (Component.For<IAuthRepository>().Instance(authRepo));
public class SessionFactoryManager
{
public ISessionFactory CreateSessionFactory()
{
try {
var autoMap = AutoMap.AssemblyOf<Artist>()
.Where(t => typeof(Entity).IsAssignableFrom(t))
.UseOverridesFromAssemblyOf<LocationMappingOverride>();
return Fluently.Configure()
.Database(PostgreSQLConfiguration.PostgreSQL82.ConnectionString(c => c.FromConnectionStringWithKey("ConnectionString")).AdoNetBatchSize(50))
.Mappings(m => m.AutoMappings.Add(autoMap))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<ServiceStack.Authentication.NHibernate.UserAuthMap>())
.ExposeConfiguration(TreatConfiguration)
.BuildSessionFactory();
} catch (Exception ex) {
var m = ex;
}
return null;
}
protected virtual void TreatConfiguration(NHibernate.Cfg.Configuration configuration)
{
configuration.SetProperty("generate_statistics", "true");
configuration.SetProperty("current_session_context_class", "thread");
var update = new SchemaUpdate(configuration);
update.Execute(false, true);
}
}
This all works for the rest of my app but when i try to use anything to do with the NH auth repo I get:
No CurrentSessionContext configured (set the property current_session_context_class)!
Anyone got any clues wha gwarn?
[UPDATE]
In my AppHost.Configure method I have added the following:
this.GlobalRequestFilters.Add ((req, res, vm) => {
CurrentSessionContext.Bind(container.Resolve<NHibernate.ISession>());
});
To no avail - I also have no idea how i would dispose of that :p
Also I am confused as ISessionFactory is injected in like every other part of my app:
https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Authentication.NHibernate/NHibernateUserAuthRepository.cs#L20
So surely that should just work?
Yes, you need to explicitly bind the current session to the context:
CurrentSessionContext.Bind(session);
After you built the session. Don't forget to dispose of it too when you no longer need it.

MVC Ninject into Automapper Profile

I'm trying to inject my dependencies into an automapper profile; the profile is like so;
public class UserProfile : Profile
{
private IIdentityService _identity;
public UserProfile(IIdentityService identity)
{
_identity = identity;
}
protected override void Configure()
{
Mapper.CreateMap<User, UserViewModel>();
Mapper.CreateMap<List<User>, UsersViewModel>()
.ForMember(d => d.Users, o => o.MapFrom(s => s))
.ForMember(d => d.Domains, o => GetDomains());
}
public List<string> GetDomains()
{
return _identity.AvailableDomains();
}
}
Several articles suggest using code like so;
kernel.Bind<IMappingEngine>().ToMethod(ctx => Mapper.Engine);
I've tried adding this in NinjectWebCommon (both in CreateKernel and RegisterServices), but i'm still getting runtime errors as AutoMapper can't resolve without a default (empty) constructor. I'm guessing the issue is with the Ninject side of things (my implementation of it that is).

Servicestack UserAuth Persistence using Nhibernate (using ServiceStack.Authentication.NHibernate)

I'm trying to use the ServiceStack IUserAuthRepository implementation for Nhibernate.
I have registered NHibernateUserAuthRepository in my service IOC container but I don't know how to tell Nhibernate to map the AuthUser and roles to database table.
My mapping happens when the container instanciates ISessionFactory (using FluentNhibernate).
Here's AppHost code:
container.Register<ICacheClient>(new MemoryCacheClient());
container.Register<IDatabaseFactory>(c => new Oracle10DatabaseFactory(_DomainAssembly, _DomainAssemblyName,
c.Resolve<ConfigurationParameters>()));
// Register EventPublisher
container.RegisterAutoWiredAs<EventPublisher, IEventPublisher>().ReusedWithin(ReuseScope.Request);
container.RegisterAutoWiredAs<EventPublisherInterceptor, IInterceptor>().ReusedWithin(ReuseScope.Request);
// Register Session & UnitOfWork
container.Register<NHibernate.ISession>(item =>
container.Resolve<IDatabaseFactory>().SessionFactory.OpenSession(new EventPublisherInterceptor(container.Resolve<IEventPublisher>())))
.ReusedWithin(ReuseScope.Request);
container.Register<IUnitOfWork>(item => new UnitOfWork(container.Resolve<NHibernate.ISession>())).ReusedWithin(ReuseScope.Request);
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[] { new CredentialsAuthProvider() }));
Here's the Oracle10DatabaseFactory constructor:
public Oracle10DatabaseFactory(Assembly assembly, string namespace, ConfigurationParameters parameters)
{
var fileCache = new ConfigurationFileCache(assembly, parameters.PathToConfigurationFolder);
var config = fileCache.LoadConfigurationFromFile();
if (config == null)
{
var mapping = AutoMap.Assembly(assembly, new MappingConfiguration(new List<string>() { namespace }))
.Conventions.Add<ReferenceIndexConvention>()
.Conventions.Add<GuidIndexConvention>()
.UseOverridesFromAssemblyOf<MappingConfiguration>();
this.sessionFactory =
Fluently.Configure()
.Database(OracleClientConfiguration.Oracle10.ConnectionString(c => c.FromConnectionStringWithKey("ZetesMobility_DataAccess_Connectionstring_Oracle"))
.UseReflectionOptimizer())
.Mappings(m => m.AutoMappings.Add(mapping)) //.Add(baseMapping)
.CurrentSessionContext("web")
.ExposeConfiguration(c => c.BuildSchema(NHibernateExtensions.RecreateSchema()))
.ExposeConfiguration(x => x.SetProperty("hbm2ddl.keywords", "auto-quote"))
.ExposeConfiguration(fileCache.SaveConfigurationToFile)
.BuildSessionFactory();
config = fileCache.LoadConfigurationFromFile();
this.sessionFactory = config.BuildSessionFactory();
}
else
{
this.sessionFactory = config.BuildSessionFactory();
}
}
How do I add the Authentication classes to mapping configuration?
Many Thanks everyone.
In your Fluently.Config(), the section Mappings(m -> m..., you need to tell FluentNhibernate to include the mappings in the package, like so:
.Mappings(m =>
m.FluentMappings
.AddFromAssemblyOf<UserAuthPersistenceDto>())
Yours should probably end up looking something like
.Mappings(m =>
{
m.AutoMappings.Add(mapping);
m.FluentMappings
.AddFromAssemblyOf<UserAuthPersistenceDto>();
})

How to use AutoMapper with Post Action

in my solution I have an ASP.NET MVC3 project, and a WCF project that works with a database.
I use entity framework self tracking and AutoMapper to map objects.
My question is: how i can use AutoMapper with Post Action like crate and delete and Edit methods
i see this Questions but not help me
this give me an error argument type '...' is not assignable to parameter type '...'
[HttpPost]
public ActionResult Create(MUser muser)
{
if (ModelState.IsValid)
{
Mapper.CreateMap<User, MUser>();
var user = Mapper.Map<User, MUser>(muser);
_proxy.SaveUser(user);
return RedirectToAction("Index");
}
return View(muser);
}
You shouldn't place the Mapper.CreateMap in your controller, you need to perform that action only once, so create a bootstrapper or something like that and call it from your application start method.
I think that's where your error comes from: you can create a mapping only once.
Oh, and you're defining the wrong types. You aren't trying to convert a User to a MUser, but you're doing it the other way around, so it should be:
Mapper.CreateMap<MUser, User>();
Mapper.Map<MUser, User>(muser);
Example of how to do this:
public class MvcApplication : HttpApplication
{
// some methods
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
MappingsBootstrapper.Initialize(); // call the bootstrap class that I created
}
}
Then I've got a project called 'Mappings' and it contains the bootstrap class and some 'configuration' classes (just like Entity Framework has EntityTypeConfiguration classes and Ninject has NinjectModules):
public static class MappingsBootstrapper
{
public static void Initialize()
{
new UserMappings();
new BookcaseItemMappings();
}
}
And the mappings:
class UserMappings
{
public UserMappings()
{
Mapper.CreateMap<User, UserSetupViewModel>();
Mapper.CreateMap<UserSetupViewModel, User>();
}
}
class BookcaseItemMappings
{
public BookcaseItemMappings()
{
Mapper.CreateMap<NewBookViewModel, BookcaseItem>().ForMember(x => x.BookId, opt => opt.Ignore());
Mapper.CreateMap<BookcaseItem, BookcaseItemViewModel>()
.ForMember(x => x.Title, opt => opt.MapFrom(src => src.Book.Title))
.ForMember(x => x.Authors, opt => opt.MapFrom(src => src.Book.Authors.Select(x => x.Name).Aggregate((i, j) => i + ", " + j)))
.ForMember(x => x.Identifiers, opt => opt.MapFrom(src => (!string.IsNullOrEmpty(src.Book.Isbn10) ? ("ISBN10: " + src.Book.Isbn10 + "\r\n") : string.Empty) +
(!string.IsNullOrEmpty(src.Book.Isbn13) ? ("ISBN13: " + src.Book.Isbn13) : string.Empty)))
.ForMember(x => x.Pages, opt => opt.MapFrom(src => src.Book.Pages))
.ForMember(x => x.ImageUri, opt => opt.MapFrom(src => src.Book.ThumbnailUriSmall));
}
}
You can do it any way you like, you could just place all the mappings in your Application_Start() method, but I found this to be a clean and maintainable way.

AutoMapping with FluentMapping doesn't quite seem to work for me

I'm a n00b. Here's what I want to do:
Use AutoMapping to configure every property between the model -> table. Then I would like to override 2 specific items in a fluent map. The two items are: Id & Table name.
So my Maps look like this:
public class BillMasterMap : ClassMap<BillMaster>
{
public BillMasterMap()
{
Table("BILLMAST");
Id(x => x.SYSKEY);
}
}
And my factory settings look like this:
public static ISessionFactory SessionFactory(string connectionString)
{
if (_sessionFactory == null)
{
_sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ShowSql()
.ConnectionString(c => c.Is(connectionString)).Cache(c => c.UseQueryCache().ProviderClass<HashtableCacheProvider>()))
.Mappings(m =>
m.AutoMappings.Add(AutoMap.AssemblyOf<BillMaster>()
.Where(x => x.Namespace.EndsWith("Entities"))))
.Mappings(m =>
m.FluentMappings.AddFromAssemblyOf<BillInvoiceMap>())
.BuildSessionFactory();
}
return _sessionFactory;
}
The problem is that FNH finds the Id override for BillMaster, but not for BillInvoice which looks like this (identical it seems)
public class BillInvoiceMap : ClassMap<BillInvoice>
{
public BillInvoiceMap()
{
Id(x => x.SYSKEY);
Table("BILLINV");
}
}
I've gotten around the problem by configuring my automapping with the Setup() as shown below:
.Mappings(m =>
m.AutoMappings.Add(AutoMap.AssemblyOf<BillMaster>()
.Setup(s => s.FindIdentity = property => property.Name == "SYSKEY")
.Where(x => x.Namespace.EndsWith("Entities"))))
But I would like to combine auto & fluent as other tables don't use "SYSKEY" as their Id column.
Thoughts? Is this a FNH bug?
Got it working.
1.) I have to setup AutoMapping with the Setup method I described above
2.) Additionally I have to setup fluentmappings with the Id method
when both are setup like this, then it works for me.
So
public static ISessionFactory SessionFactory(string connectionString)
{
if (_sessionFactory == null)
{
_sessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ShowSql()
.ConnectionString(c => c.Is(connectionString)).Cache(
c => c.UseQueryCache().ProviderClass<HashtableCacheProvider>()))
.Mappings(m =>
{
m.FluentMappings.AddFromAssemblyOf<BaseEntity>();
m.AutoMappings.Add(AutoMap.AssemblyOf<BaseEntity>()
.Setup(s => s.FindIdentity = property => property.Name == "SYSKEY")
.Where(x => x.Namespace.EndsWith("Entities")));
})
.BuildSessionFactory();
}
return _sessionFactory;
}
And the map
public class BillInvoiceMap : ClassMap<BillInvoice>
{
public BillInvoiceMap()
{
Table("BILLINV");
Id(x => x.SYSKEY);
}
}