ソリューションに新しい WebApi プロジェクトを追加しました。コントローラーの Get メソッドは、 Xml を返す関数を呼び出します。Nhibernate ISession を使用してインスタンス化する関数を呼び出しています。Db に MySql を使用していますが、次のエラーが発生します。
ここにエラーのトレースがあります
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Object reference not set to an instance of an object.
</ExceptionMessage>
<ExceptionType>System.NullReferenceException</ExceptionType>
<StackTrace>
at comp.rest.RestApi.Controllers.RestApiController.Get() in C:\GitHub\rea-rest\src\comp.rest.RestApi\Controllers\RestApiController.cs:line 23 at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass13.<GetExecutor>b__c(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.<>c__DisplayClass5.<ExecuteAsync>b__4() at System.Threading.Tasks.TaskHelpers.RunSynchronously[TResult](Func`1 func, CancellationToken cancellationToken)
</StackTrace>
</Error>
アプリの起動時にglobal.asaxファイルから呼び出す依存関係リゾルバーがあります
public class ApiDependencyResolver : IDependencyResolver
{
private static ISession _session;
private static ISettings _settings;
private static IDiscountService _discountService;
private static IAuctionService _auctionService;
private static IAuditService _auditService;
private NhProductAdminService productAdminService = new NhProductAdminService(_session, _settings,
_discountService,
_auctionService,
_auditService);
public IDependencyScope BeginScope()
{
// This example does not support child scopes, so we simply return 'this'.
return this;
}
public object GetService(Type serviceType)
{
if (serviceType == typeof(RestApiController))
{
return new RestApiController(productAdminService);
}
else
{
return null;
}
}
public IEnumerable<object> GetServices(Type serviceType)
{
return new List<object>();
}
public void Dispose()
{
// When BeginScope returns 'this', the Dispose method must be a no-op.
}
}
通常、コントローラーがヒットすると、Nhibernate セッションがインスタンス化されます。これは、global.asax Application_Start でセッションを既に開いているためです。これで数日間立ち往生しています。ばかげたことをしています。WebApi は初めてです。
この Web アプリケーションでは、global.asax を使用して Nhibernate セッションを開きます。
builder.RegisterModule(new WebNHibernateModule());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
WebHibernate クラスは次のようになります。
public class WebNHibernateModule : NHibernateModule
{
protected override IPersistenceConfigurer DatabaseConfig
{
get
{
return
MySQLConfiguration.Standard
.ConnectionString(s => s.FromConnectionStringWithKey("ApplicationServices"))
.Driver<ProfiledSqlClientDriver>();
//.ShowSql();
}
}
protected override Action<MappingConfiguration> MappingConfig
{
get { return AutoConfig.Mappings; }
}
}
public class ProfiledSqlClientDriver : MySqlDataDriver
{
public override IDbCommand CreateCommand()
{
var command = base.CreateCommand();
if (MiniProfiler.Current != null)
{
command = DbCommandProxy.CreateProxy(command);
}
return command;
}
}
NHibernateModule クラスは次のようになります。
public abstract class NHibernateModule : Module
{
protected abstract IPersistenceConfigurer DatabaseConfig { get; }
protected abstract Action<MappingConfiguration> MappingConfig { get; }
protected override void Load(ContainerBuilder builder)
{
builder.RegisterGeneric(typeof(NhSessionQueryable<>)).As(typeof(IQueryable<>));
builder.RegisterType<NhQueryContext>().As<IQueryContext>();
builder.RegisterType<WebSessionTracker>().As<ISessionTracker>()
.InstancePerHttpRequest();
builder.Register(c => c.Resolve<ISessionFactory>().OpenSession())
.InstancePerHttpRequest()
.OnActivated(e =>
{
e.Context.Resolve<ISessionTracker>().CurrentSession = e.Instance;
e.Instance.BeginTransaction();
});
builder.Register(c =>
Fluently.Configure().Database(DatabaseConfig)
.Mappings(MappingConfig)
.BuildConfiguration())
.SingleInstance()
.OnActivated(e =>
{
e.Instance.Initialize(e.Context.Resolve<ValidatorEngine>());
new SchemaValidator(e.Instance).Validate(); // Validate the schema when we create the session factory
});
builder.Register(c => c.Resolve<Configuration>().BuildSessionFactory())
.SingleInstance();
}
}
通常、Web アプリケーションでは、同様の Autofac を使用してセッションを事前設定します。WebApi についても同じことを行っていますが、Nhibernate セッションはまだ null です。