FluentNHibernate.MissingConstructorException when building the SessionFactory - c#

I'm trying to fluently configure a SessionFactory to access an Oracle9i database, using ODP.Net, and I'm getting this MissingConstructorException. I've got the actual fluent mappings sorted out ok, but I'm not sure what else it is that I've done wrong.
Here is the exception:
BasicConnectionTests.AssertThatWeCanConnectToADatabase :
FailedFluentNHibernate.MissingConstructorException: 'FluentNHibernate.Automapping.IAutoClasslike, FluentNHibernate, Version=1.1.0.685, Culture=neutral, PublicKeyToken=8aa435e3cb308880' is missing a parameterless constructor.
at FluentNHibernate.Utils.Extensions.InstantiateUsingParameterlessConstructor(Type type)
at FluentNHibernate.PersistenceModel.Add(Type type)
at FluentNHibernate.Utils.CollectionExtensions.Each<T>(IEnumerable`1 enumerable, Action`1 each)
at FluentNHibernate.PersistenceModel.AddMappingsFromSource(ITypeSource source)
at FluentNHibernate.Cfg.FluentMappingsContainer.Apply(Configuration cfg)
at FluentNHibernate.Cfg.MappingConfiguration.Apply(Configuration cfg)
at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration()
FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
at FluentNHibernate.Cfg.FluentConfiguration.BuildConfiguration()
at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory()
FluentNHibernate.Cfg.FluentConfigurationException: An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory()
at MyAwesomeApp.sessionFactories.Oracle9SessionFactoryWrapper.Configure(String userName, String passWord, String dataBase) in Oracle9SessionFactoryWrapper.cs: line 26
at MyAwesomeApp.Tests.oracle.BasicConnectionTests.AssertThatWeCanConnectToADatabase() in BasicConnectionTests.cs: line 17
Here is the fluent mapping:
public ISessionFactory Configure(string userName, string passWord, string dataBase)
{
var config = Fluently.Configure();
config.Database(
OracleDataClientConfiguration.Oracle9
.ConnectionString(cs => cs.Username(userName).Password(passWord).Instance(dataBase))
.Driver("NHibernate.Driver.OracleDataClientDriver")
#if DEBUG
.ShowSql()
#endif
);
config.Mappings(
m => m.FluentMappings.AddFromAssembly(Assembly.GetCallingAssembly()));
return config.BuildSessionFactory();
}
If anyone can point out where I'm going wrong, I'd be most grateful.

As James Gregory pointed in his comment on my question, I was doing something really stupid when informing Fluent were my mappings were.
When the code was exercised from the context of a unit test, m => m.FluentMappings.AddFromAssembly(Assembly.GetCallingAssembly()) tried to tell Fluent to look in the unit test assembly for the mappings - which is going to fail, miserably.
The answer is to use m => m.FluentMappings.AddFromAssemblyOf<Foo>(), where Foo is a type in the assembly were the mappings are.

Related

Health check for AddDbContextCheck by TContextService and TContextImplementation

I'm setup my DBContext by TContextService and TContextImplementation options.
Something like this:
services.AddDbContext<IMyDbContext, MyDbContext>(options => options.UseNpgsql(myDatabaseConnectionString));
I try to enable health check from Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
When I try to use this code
services.AddHealthChecks().AddDbContextCheck<MyDbContext>()
I got from health end point response that
InvalidOperationException: Unable to resolve service for type 'MyDbContext' while attempting to activate 'Microsoft.Extensions.Diagnostics.HealthChecks.DbContextHealthCheck`1[MyDbContext]'.
Microsoft.Extensions.DependencyInjection.ActivatorUtilities+ConstructorMatcher.CreateInstance(IServiceProvider provider)
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.CreateInstance(IServiceProvider provider, Type instanceType, object[] parameters)
Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider)
Do you know any method to use two options TContextService and TContextImplementation for health check by Entity Framework?
You seem to have hit a case where the two cannot work together. I think you have two options:
First is to register the DbContext directly and then just resolve the interface from this registration.
services.AddDbContext<MyDbContext>(options => options.UseNpgsql(myDatabaseConnectionString));
services.AddTransient<IMyDbContext>(c=>c.GetRequiredService<MyDbContext>());
Another option is to implement the health check functionality yourself. Which is not exactly hard.
See : EntityFrameworkCoreHealthChecksBuilderExtensions.cs and DbContextHealthCheck.cs

Registering factory method doesn't prevent Autofac from calling ctor

I have a service called ServiceConfiguration which has a non-default ctor. I'm trying to register it through Autofac with a factory method:
builder.Register(c=>LoadConfiguration())
.As<ServiceConfiguration>();
And here is the simple LoadConfiguration method:
private ServiceConfiguration LoadConfiguration() {
const string fileName = "app.json";
var json = File.ReadAllText(fileName, Encoding.UTF8);
var model = JsonConvert.DeserializeObject<ServiceConfiguration>(json);
return model;
}
I expect Autofac to call the LoadConfiguration when I asked to resolve ServiceConfiguration. But it seems it's trying to call a ctor on ServiceConfiguration. E.g. calling this line:
var c = container.Resolve<ServiceConfiguration>();
causes this error:
Autofac.Core.DependencyResolutionException: 'An error occurred during
the activation of a particular registration. See the inner exception
for details. Registration: Activator = ServiceConfiguration
(ReflectionActivator), Services = [ServiceConfiguration], Lifetime =
Autofac.Core.Lifetime.CurrentScopeLifetime, Sharing = Shared,
Ownership = OwnedByLifetimeScope'
and the InnerException is:
DependencyResolutionException: None of the constructors found with
'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'ServiceConfiguration' can be invoked with the available services and
parameters:
Cannot resolve parameter 'JobsConfiguration jobs' of constructor 'Void .ctor(JobsConfiguration)'.
Can you find out what I'm missing?
UPDATE:
I'm not missing a registration of JobsConfiguration. Actually it's not a registrable type and I don't want to register it. I don't want to ctor get called at all (the service is getting build from a json file), instead whenever somebody asked for ServiceConfiguration I want Autofac to call LoadConfiguration() and use it's returned value.
UPDATE2:
After a while, it seems extracting an interface from ServiceConfiguration - say IServiceConfiguration - and registering/resolving the interface works just fine. But I cannot figure out why! I mean this:
builder.Register(c=>LoadConfiguration())
.As<IServiceConfiguration>();
var c = container.Resolve<IServiceConfiguration>();
works. But the concrete version not. So why? What's the difference?
You should strive separating the loading of configuration files from Object Composition. This means that it's best not to load the configuration when Resolve is called. Changing this is trivial:
ServiceConfiguration configuration = LoadConfiguration();
builder.RegisterInstance(configuration);
That said, your given registration should work:
builder.Register(c => LoadConfiguration())
.As<ServiceConfiguration>();
Which is identical to:
builder.Register(c => LoadConfiguration());
With this registration, Autofac will not Auto-Wire the ServiceConfiguration constructor, but will leave that to the supplied delegate. There might be something going on that your post is not showing.
I used the following MCVE, using Autofav 4.8.1, to verify that this works:
class ServiceConfiguration
{
public ServiceConfiguration(int a, double b) => Console.WriteLine("ctor called.");
}
static ServiceConfiguration LoadConfiguration() => new ServiceConfiguration(2, 6);
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.Register(_ => LoadConfiguration()).As<ServiceConfiguration>();
builder.Build().Resolve<ServiceConfiguration>();
}
Last note: Make sure that ServiceConfiguration is not an application-wide configuration class that is injected into many consumers. To understand what's wrong with application-wide configuration classes, please read this Q/A.

Autofac fails to initailly resolve object from remote assembly (cast to know type)

Here is my WCF(vs2015#net452) autofac (v4.6.1) setup:
MyService.dll:
builder.Register(c => (ISession)RemoteObjectFactory.GetInstance(typeof(MySessionBase))).As<ISession>().SingleInstance();
...
var session = AutofacHostFactory.Container.Resolve<ISession>();
<Message>An exception was thrown while executing a resolve operation. See the InnerException for details.
Could not load file or assembly "MyRemotingHost, Version=1.0.6442.29085, Culture=neutral, PublicKeyToken=null" or one of its dependencies. File not found(See inner exception for details.)</Message>
<StackTrace>at Autofac.Core.Resolving.ResolveOperation.Execute(IComponentRegistration registration, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.TryResolveService(IComponentContext context, Service service, IEnumerable`1 parameters, Object& instance)
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
at My.DoSomeWork() at C:\Projects\...
<Type>Autofac.Core.DependencyResolutionException</Type>
MyService.dll refers to MyDefs.dll.
MyRemotingHost.dll refers to MyDefs.dll.
MyService.dll calls MyRemotingHost.dll via remoting. RemoteObjectFactory.GetInstance is a wrapper method that returns(via remoting) Transparent Proxy to MySession object from MyRemotingHost.dll.
Abstract class MySessionBase implements ISession. Both are defined in MyDefs.dll.
Class MySession is a sublcass of MySessionBase and is defined in MyRemotingHost.dll.
Strictly speaking MyService.dll does not know about MyRemotingHost.dll and should not know about it. Why then autofac tries to get information about this assembly which is remote??
Update
ISession session = (MySessionBase)RemoteObjectFactory.GetInstance(typeof(MySessionBase));
builder.RegisterInstance(session);
RegisterInstance throws same error.
Update2
Second(and subsequent) resolution attempts do not throw error which is weird.
builder.Register(c => (ISession)RemoteObjectFactory.GetInstance(typeof(MySessionBase))).As<ISession>().SingleInstance();
...
var session1 = AutofacHostFactory.Container.Resolve<ISession>();
var session2 = AutofacHostFactory.Container.Resolve<ISession>();
Line var session1 = ... throws error. If error is suppressed, then next line var session2 = ... DOES NOT produce error.
PDB-based step-by-step debugging shows that error source is at Autofac.Core.Resolving.ResolveOperation inside foreach loop at the 1st call to enumerator:
private void CompleteActivations()
{
var completed = _successfulActivations;
ResetSuccessfulActivations();
foreach (var activation in completed)
activation.Complete();
}
I cannot investigate more as I am stuck to VS2015 while autofac sources have VS2017 format already.
The problem was in the log4net autofac module:
var instanceType = instance.GetType();
Adding checks before that line solves the problem:
// cant use GetType() on TransparentProxy as it may throw error
if (RemotingServices.IsTransparentProxy(instance)) return;

Can't Mock interface method when parameter is MultipartFormDataStreamProvider

I have this weird problem when trying to mock an interface with MockedClass.Setup(x => x.Method()).
This is the interface I'm mocking.
public interface IClassFactory
{
object GetValueFromFormData(string key, MultipartFormDataStreamProvider provider);
}
This is my test.
[TestMethod]
[ExpectedException(typeof(NullReferenceException))]
public async Task ClassApiController_ImportClassList_ThrowsNullReferenceExceptionWhenNoClassId()
{
// Arrange
_classFactory = new Mock<IClassFactory>();
// THIS IS THE LINE THAT GIVES AN EXCEPTION
_classFactory.Setup(x => x.GetValueFromFormData("classIdNull", null)).Returns(string.Empty);
ClassApiController controller = new ClassApiController(_classRepository.Object, _surveyRepository.Object, _classFactory.Object);
// Act
string result = await controller.ImportClassList();
}
If you look at my comment "THIS IS THE LINE THAT GIVES AN EXCEPTION" you see I send null, but it doesn't matter if I send the MultipartFormDataStreamProvider as an instansiated class instead, I still get the same exception.
Exception message: System.ArgumentException: Expression of type 'System.Net.Http.MultipartFormDataStreamProvider' cannot be used for parameter of type 'System.Net.Http.MultipartFormDataStreamProvider' of method 'System.Object GetValueFromFormData(System.String, System.Net.Http.MultipartFormDataStreamProvider)'
If you know why I can't mock the method just because it has this object as parameter, please help me, I'm clueless.
Thanks!
EDIT:
See solution in my answer
you should try
_classFactory = Mock.Of<IClassFactory>();
Mock.Get(_classFactory).Setup(x => x.GetValueFromFormData("classIdNull", It.IsAny<MultipartStreamProvider>()))
.Returns(string.Empty);
With the help of #Vignesh.N I finally solved it. The simple answer in this case was that my solution is divided into several projects. Web, Test, Data and so on. In the web project I had referenced the web api .dll:s via Nuget and in the test project I had referenced them directly via Add references -> Assemblies -> Framework. Thereby the .dll:s had identical Versions but not File versions. After making Nuget take care of all the projects web api .dll files it worked instantly.
So all in all, stupid mistake and hard to spot.

Ensure that HttpConfiguration.EnsureInitialized()

I've installed Visual Studio 2013 and when I run my app I get the error below.
I've got no idea as to where I'm to initialized this object.
What to do?
Server Error in '/' Application.
The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[InvalidOperationException: The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.]
System.Web.Http.Routing.RouteCollectionRoute.get_SubRoutes() +101
System.Web.Http.Routing.RouteCollectionRoute.GetRouteData(String virtualPathRoot, HttpRequestMessage request) +63
System.Web.Http.WebHost.Routing.HttpWebRoute.GetRouteData(HttpContextBase httpContext) +107
System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext) +233
System.Web.Routing.UrlRoutingModule.PostResolveRequestCache(HttpContextBase context) +60
System.Web.Routing.UrlRoutingModule.OnApplicationPostResolveRequestCache(Object sender, EventArgs e) +82
System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +136
System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +69
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.18408
This is for AlumCloud
If you do it at the end of Application_Start it will be too late, as WebApiConfig.Register has been called.
The best way to resolve this is to use new initialization method by replacing in Global.asax :
WebApiConfig.Register(GlobalConfiguration.Configuration);
by
GlobalConfiguration.Configure(WebApiConfig.Register);
See #gentiane's answer below for the correct way to handle this now.
At the end of the Application_Start method in Global.Asax.cs try adding:-
GlobalConfiguration.Configuration.EnsureInitialized();
I actually got this error when I was using Attribute Routing within my WebApi.
I had
[Route("webapi/siteTypes/{siteTypeId"]
instead of
[Route("webapi/siteTypes/{siteTypeId}"]
for my route and got this error. I had simply missed out the closing curly bracket. Once I added it back in, this error didn't occur again.
This is old, but is the first result on google when searching for this error. After quite a bit of digging I was able to figure out what was going on.
tldr:
All GlobalConfiguration.Configure does is invoke your action and call EnsureInitialized(). config.MapAttributeRoutes() must be called before EnsureInitialized() since EnsureInitialized only runs once.
Meaning: if you're coming from an existing Mvc project, all you have to do is:
Add
GlobalConfiguration.Configuration.EnsureInitialized();
to the bottom of your Application_Start method.
OR
Move your entire configuration into a single call to GlobalConfiguration.Configure:
GlobalConfiguration.Configure(config =>
{
WebApiConfig.Register(config);
config.MapAttributeRoutes();
...
});
Digging Deeper
HttpConfiguration.Configuration has an "Initializer" property defined like this:
public Action<HttpConfiguration> Initializer;
HttpConfiguration.EnsureInitialized() runs this action and sets _initialized to true
public void EnsureInitialized()
{
if (_initialized)
{
return;
}
_initialized = true;
Initializer(this);
}
HttpConfiguration.MapAttributeRoutes calls internal method AttributeRoutingMapper.MapAttributeRoutes which sets HttpConfiguration.Initializer
public static void MapAttributeRoutes(...)
{
RouteCollectionRoute aggregateRoute = new RouteCollectionRoute();
configuration.Routes.Add(AttributeRouteName, aggregateRoute);
...
Action<HttpConfiguration> previousInitializer = configuration.Initializer;
configuration.Initializer = config =>
{
previousInitializer(config);
...
};
}
GlobalConfiguration.Configure runs EnsureInitialized immediately after invoking your action:
public static void Configure(Action<HttpConfiguration> configurationCallback)
{
if (configurationCallback == null)
{
throw new ArgumentNullException("configurationCallback");
}
configurationCallback.Invoke(Configuration);
Configuration.EnsureInitialized();
}
Don't forget, if you run in to a wall, the source for asp.net is available at http://aspnetwebstack.codeplex.com/SourceControl/latest
I've had a related issue. Sometimes calling GlobalConfiguration.Configure multiple times triggers this error. As a workaround, I've put all configuration initialization logic in one place.
IF THIS ERROR SEEMS TO HAVE COME "OUT OF NOWHERE", i.e. your app was working perfectly fine for a while, ask yourself: Did I add an action to a controller or change any routes prior to seeing this error?
If the answer is yes (and it probably is), you likely made a mistake in the process. Incorrect formatting, copy/pasting an action and forgetting to make sure the endpoint names are unique, etc. will all end you up here. The suggestion that this error makes on how to resolve it can send you barking up the wrong tree.
For me, the problem was that I was trying to use named parameters for query string fields in my routes:
[Route("my-route?field={field}")]
public void MyRoute([FromUri] string field)
{
}
Query string fields are automatically mapped to parameters and aren't actually part of the route definition. This works:
[Route("my-route")]
public void MyRoute([FromUri] string field)
{
}
Although the above answer works if incase that is not set, In my case this stuff was set already. What was different was that, for one of the APIs I had written, I had prefixed the route with a / . Example
[Route("/api/abc/{client}")]
.Changing this to
[Route("api/abc/{client}")]
fixed it for me
Call
GlobalConfiguration.Configuration.MapHttpAttributeRoutes();
before
GlobalConfiguration.Configure(c => ...);
completes its execution.
I got this error when the version of Newtonsoft.Json was different in my main project compared to the helper project
One typically gets this exception when route templates in "Attribute Routing" are not proper.
For example, i got this when i wrote the following code:
[Route("{dirName:string}/contents")] //incorrect
public HttpResponseMessage GetDirContents(string dirName) { ... }
In route constraints syntax {parameter:constraint}, constraint by default is of type string. No need to mention it explicitly.
[Route("{dirName}/contents")] //correct
public HttpResponseMessage GetDirContents(string dirName) { ... }
I began getting this error one day. After I'd altered our app to call EnsureInitialized() I was able to see the root cause.
I had a custom attribute, a filter, on an action. That attribute class had had a breaking change made in the NuGet package in which it lives.
Even though I'd updated the the code and it all compiled, the local IIS worker was loading an old DLL and not finding a class member during initialization, reading attributes on actions etc.
For some reason (possibly due to order/when our logging is initialized), this error was not discoverable, possibly leaving the WebAPI in a strange state, until I'd added EnsureInitialized() which caught the exception and surfaced it.
Performing a proper bin and obj clean via a handy script resolved it.
In my case I created the webservice in project A and started it from Project B and I got exactly this error. The problem was that some .dll-files which are required by A where missing in the build-output-folder of B. Ensure that these .dll-files are available fixed it.
In my case , i used an Entity as parameter of my action that its 'Schema' is missing.
Wrong attribute:
[Table("Table name", Schema = "")]
Correct :
[Table("Table name", Schema = "schema name")]
In my case I fixed replacing:
<Route("{id:string}")>
with
<Route("{id}")>
Strange that I was sure that the original code was working before suddenly stopping, go figure....
I experienced this similar error.
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>The object has not yet been initialized. Ensure that HttpConfiguration.EnsureInitialized() is called in the application's startup code after all other initialization code.</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace> at System.Web.Http.Routing.RouteCollectionRoute.get_SubRoutes() at System.Web.Http.Routing.RouteCollectionRoute.GetRouteData(String virtualPathRoot, HttpRequestMessage request) at System.Web.Http.WebHost.Routing.HttpWebRoute.GetRouteData(HttpContextBase httpContext)</StackTrace>
</Error>
After fiddling with it for a while, I realized two problems: directory name collides with routing prefix and routing prefix must not end with '/'. When starting up the service for debugging I got this browser error after adding the SampleController.cs.
The folder structure
/api/Controllers/SampleController.cs
/api/Model/...
SampleController.cs
[RoutePrefix("api/sub/{parameterId}/more/")]
public class SampleController : ApiController
{
[HttpGet]
[Route("")]
public IHttpActionResult Get(int parameterId)
{
return Ok("Knock Knock...");
}
}
Changing the routing prefix to not end in '/' and not colliding with the directory name solved the problem.

Categories

Resources