Weird override problem with Fluent NHibernate and .NET 4 - nhibernate

I recently asked a question about using Fluent NHibernate with .NET 4 - I solved that problem, but met a new one.
Summary
My main problem (at the moment) is configuring the database. I'm following this guide, but trying to work against SQL Server 2008 Express instead, as that's what I'll be using and thus what I need to learn.
The failing code:
public static ISessionFactory CreateSessionFactory()
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(c => c.FromConnectionStringWithKey("mssql")))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<Program>())
.ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true, true))
.BuildSessionFactory();
}
When I try to run my application, I get the following exception on the last line (.BuildSessionFactory()):
Inheritance security rules violated while overriding member: 'FluentNHibernate.Cfg.FluentConfigurationException.GetObjectData(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)'. Security accessibility of the overriding method must match the security accessibility of the method being overriden.
What is causing this?

From the Microsoft Connect issue:
Security attributes need to be
re-applied on types that derive from
other types that also have security
attributes.
Maybe FluentConfigurationException needs to apply a [SecurityPermission] attribute to its GetObjectData() method.
Else check out this blog post.
EDIT: The final solution was adding [SecurityCritical] to FluentConfigurationException.GetObjectData()

Related

How do I auto-register/resolve services by their interface?

I'm developing a MVC .NET Core 3/Angular/Entity Framework application. My application will likely have a lot of repositories in it. To support this I would like to resolve the service (repository) by its default interface (i.e. I request IRepository and the DI resolver gives me Repository). I know I can manually wire up the dependencies, but all of my DI frameworks in the past have had a means of auto-registering/resolving based on patterns or the like.
For example, with Castle Winsdor I could wire it up like this:
container.Register(Classes
.FromAssemblyNamed("MyLibary.Repository")
.InNamespace("MyLibrary.Repository")
.WithService.DefaultInterfaces()
.LifestyleTransient()
);
This would register all classes in the MyLibrary.Repository namespace to be resolved by their default interfaces they implement. How can this be done in .NET Core 3? If this isn't built-in, I'm assuming I will have to use reflection to query all the classes in the assembly, iterate through each class and register it by its interface it implements.
I would recommend AutoRegisterDI lib to not reinvent a bicycle. It's fast, simple and based on Microsoft Dependency Injection. This benchmark will show you the speed difference.
And this is the article about how to use it
Install this package:
NetCore.AutoRegisterDi
Add this code to your program.cs:
builder.Services.RegisterAssemblyPublicNonGenericClasses()
.Where(c => c.Name.EndsWith("Service"))
.AsPublicImplementedInterfaces(ServiceLifetime.Scoped); // default is Transient
If you have a Singleton service , add [RegisterAsSingleton] on top of your service class.
If you want to ignore injection of an particular interface add this line after .Where() :
.IgnoreThisInterface<IMyInterface>()
you can do this with reflection in c#.first create an extension method like this :
public static void AddScopedServices(this IServiceCollection serviceCollection)
{
}
and use it in startup.cs ,ConfigureServices method : services.AddScopedServices();
now to implement this method like this:
var allProviderTypes = System.Reflection.Assembly.GetAssembly(typeof(ICartRepository))
.GetTypes().Where(t => t.Namespace != null).ToList();
foreach (var intfc in allProviderTypes.Where(t => t.IsInterface))
{
var impl = allProviderTypes.FirstOrDefault(c => c.IsClass && intfc.Name.Substring(1) == c.Name);
if (impl != null) serviceCollection.AddScoped(intfc, impl);
}
you just need to put all your interfaces in a namespace and introduce one of them in this method ,in my case I used ICartRepository ,so it takes all interfaces and search for classes which inherit from that interface.
one point you need to consider is that class names must be like interfacenames without 'I' in the beginning ,like 'CartRepository'
I recently got tired of writing the same old
services.AddTransient<IInterface,IImplementation>
so I created a simple library to help me auto-register services.
You can check it out here.
Register the library in Startup.cs
There are 3 interface -> ITransient, IScoped, ISingleton generic and non-generic versions.
Let's say you want to register service "TestService" as transient.
TestService: ITransient<ITestService>, ITestService
Inherit ITransient interface and its done.
For more detailed information please refer to the Readme section.
Currently it lacks registering services with implementation factory, but it's something I'm willing to do in the near future.

.net Core 2.0 OData - EnableQuery attribute not allowing operations

I am trying to use Microsoft.AspNetCore.OData, v7.0.0.0-beta1, in a simple project.
I am failing to filter, select, and use top or skip.
Overriding the ValidateQuery of the EnableQueryAttribute, I can successfully perform these type of operations so I believe the library is buggy.
I could not find the right channel to report the issue, can anyone help?
The sample code to reproduce is available here: https://github.com/norcino/AspNetCoreSamples/tree/master/SampleODataApp
The solution to the problem was the actual initialization of the MVC route builder.
Like in the .net framework version it is possible to specify which operation is allowed for OData query. In the example below I am whitelisting everything but you can do a more fine tuning passing an instance of QueryOptionSetting.
app.UseMvc(routeBuilder =>
{
routeBuilder
.Select()
.Expand()
.Filter()
.OrderBy(QueryOptionSetting.Allowed)
.MaxTop(2000)
.Count();
routeBuilder.EnableDependencyInjection();
});
Note that, the attribute [HttpGet, EnableQuery(AllowedOrderByProperties = "Id")], will effectively enforce the order by to the sole Id property specified in the attribute, but first you need to enable all from the configuration.

NHibernate config properties in Fluent NHibernate

I am considering using Fluent NHibernate for my project and I haven't found any documentation on whether FH supports NHibernate settings such as show_sql and prepare_sql. I could live without show_sql in a pinch, but prepare_sql is important for ensuring good performance at run time.
Can anyone tell me if it's possible to configure these settings in Fluent NHibernate?
Yes, you can.
Fluently.Configure()
.Database(ConfigureDatabase())
.Mappings(ConfigureMapping)
.ExposeConfiguration(ModifyConfiguration)
.BuildConfiguration();
And now in ModifyConfiguration method you have plain NHibernate's Configuration object to modify
private void ModifyConfiguration(Configuration configuration)
{
// set parameters here like this:
configuration.Properties["show_sql"] = "true";
}
Some of the settings are exposed through the fluent API.
See here for examples: Database Configuration
Anything that isn't supported through specific fluent calls can be set by manipulating the native NHibernate.Cfg.Configuration object. Either way you can do everything in code that you can with the configuration file.

Splitting configuration in Fluent NHibernate

I am trying to split the configuration in Fluent NHibernate between two classlibraries (dll's).
The first classlibrary would configure certain listeners in NHibernate (for auditing and security) and the second would map/automap the entities. Any good ideas for how to pass the Fluent config between the libraries?
One idea I have is using Castle Windsor (part of my infrastructure already) and installers to pass the config via the container between the libraries. Does that sound reasonable?
i have a similar scenario where configure the mappings somewhere else. I dont pass the config around, i just take the mappings as a whole from different providers.
For example:
Fluently.Configure()
.Mappings(m => m.AutoMappings.Add(Container.Resolve<IAutoMapProvider>().Get())
public class AutoMapProvider : IAutomapProvider
{
...
public static AutoPersistenceModel Get()
{
return AutoMap
.AssemblyOf<MyObjectBase>(new MyConfiguration())
.IgnoreBase<MyObjectBase>()
.Conventions.Setup(c =>
// ...
}
}

NHibernate caching entities across sessions using SysCache

I'm developing a web application and I would like caching to persist across web requests.
I am aware that the first level cache is per-session only. I have second-level caching enabled and this is working for queries.
However, the second-level cache does not seem to work for "getting" entities... therefore most of the DB work the application does is not being cached across web requests.
Is this normal / desirable behaviour? I'm reviewing one particular page that makes lots of round trips to the database, although each query is quick, these seem unnecessary if the entities could be cached.
Edit
Okay so I have second level cache enabled, and working for queries. I just can't seem to get it working for entities. I have Cache.Is(c => c.ReadWrite()) (fluent nhibernate) on my main entity that I'm testing. But nope, it still hits the DB each time. Any ideas?
Edit
I've tried using transactions like so:
public override Accommodation Get(int id)
{
using (var tx = Session.BeginTransaction())
{
var accomm = Session.Get<Accommodation>(id);
tx.Commit();
return accomm;
}
}
My mapping is such (and you can see we have a nasty schema):
public void Override(AutoMapping<Core.Entities.Itinerary.Accommodation.Accommodation> mapping)
{
mapping.HasManyToMany(x => x.Features).Table("AccommodationLinkFeatureType").ChildKeyColumn("FeatureTypeId").NotFound.Ignore();
mapping.HasManyToMany(x => x.SimilarAccommodation).Table("AccommodationLinkSimilarAccommodation").ChildKeyColumn("SimilarAccommodationId").NotFound.Ignore();
mapping.HasMany(x => x.TourItinerary).Table("AccommodationTourItinerary");
mapping.HasOne(x => x.Images).ForeignKey("AccommodationId").Cascade.All().Not.LazyLoad();
mapping.References(x => x.CollectionType).NotFound.Ignore().Not.LazyLoad();
mapping.References(x => x.AccommodationUnitType).NotFound.Ignore().Not.LazyLoad();
Cache.Is(c => c.ReadWrite());
}
However, this still doesn't seem to fetch from the 2nd level cache.
Incidentally, I see a lot of examples online using Cache.ReadWrite() but I can only see an Is method on the Cache helper, so I'm trying Cache.Is(c => c.ReadWrite()) -- has the fluent interface changed?
I have not tested this, but my understanding is that committing transactions is the magic that places objects into second level cache. If you are doing read operations outside of a transaction then the objects will not be placed in the second level cache.
I had the same problem.
In my case the cause was the References is mapped with NotFound().Ignore() (i.e if no entity is found with this foreign key just ignore it, which is actualy a data consistency error anyway). Remove NotFound.Ignore and fix your db.
Maybe you´re having some problem with the configuration of your cache provider. I´ve been able to do want you want using Couchbase as 2nd level cache provider, as described here:
http://blog.couchbase.com/introducing-nhibernate-couchbase-2nd-level-cache-provider
If your deployment enviroment is on Azure, i guess this might be useful. Note that The SysCache module can’t co-exist with the AzureMemcached module.
http://www.webmoco.com/webmoco-development-blog/orchard-cms-second-level-caching