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
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.
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).
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>();
})
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.
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);
}
}