私は現在、MVC3、Spring.NET、FluentNHibernateを使用してASP.NETプロジェクトの開発を開始しています。Spring.NET、C#、Dependency Injection and transactions
私の背景は主にJavaですが、いくつかのSpringフレームワークエクスポージャーがあるため、Spring.NETは簡単で、ピースでなければなりません。
アプリケーションアーキテクチャは、サービスを使用するコントローラ、NHibernateエンティティとマッピングを使用するDAOとDAOを使用するサービスではかなりバニラです。
瞬間、私は現在のシナリオで私の頭を悩まています:
私のサービスメソッドの一つがspring.netを用いて注入されダオを、使用しています。 [Transaction]属性でサービスメソッドに注釈を付けると、DAO依存関係が私のサービスに注入されなくなり、NullReferenceExceptionsが発生します。
なぜこのようなことが起こるかについてのご意見をお待ちしております。
問題を説明するコードです。これは実際のコードではありませんが、かなり近いです。第1ばねクラスAbstractTransactionalSpringContextTestsを拡張し、抽象テストクラス、:
using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Namespace.Dao;
using Namespace.Entities;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Spring.Testing.Microsoft;
namespace Namespace.Tests.Services
{
[TestClass]
public class AbstractServiceTest : AbstractTransactionalSpringContextTests
{
public AbstractServiceTest()
{
}
protected override string[] ConfigLocations
{
get { return new string[]
{
"assembly://Assembly/Namespace.Config/dao.xml",
"assembly://Assembly/Namespace.Config/Services.xml",
"assembly://Assembly/Namespace.Config/web.xml"
};
}
}
}
}
このクラスは、実際のテストクラスを作成するために拡張されています
using System.Collections.Generic;
using Namespace.Entities;
using Namespace.Services.Assets;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Namespace.Tests.Services
{
[TestClass]
public class AssetsServiceTest : AbstractServiceTest
{
public AssetsServiceTest()
{
}
private AssetsService assetsService;
public AssetsService AssetsService
{
get { return assetsService; }
set { assetsService = value; }
}
[TestMethod]
public void TestGetFacilities()
{
Assert.IsNotNull(assetsService);
/* THIS ASSERTION FAILS when assetsService.GetFacilities has the [Transaction] attribute */
Assert.IsNotNull(assetsService.FacilityDao);
IList<Facility> facilities = assetsService.GetFacilities();
Assert.IsNotNull(facilities);
}
}
}
そしてここでは、サービスクラスです:
using System.Collections.Generic;
using Namespace.Dao;
using Namespace.Entities;
using Namespace.Models;
using Spring.Transaction;
using Spring.Transaction.Interceptor;
using Facility = Namespace.Entities.Facility;
namespace Namespace.Services.Assets
{
public class AssetsService
{
public AssetsService()
{
System.Console.Out.WriteLine("AssetsService created");
}
private FacilityDao _facilityDao;
public FacilityDao FacilityDao
{
get
{
return _facilityDao;
}
set
{
_facilityDao = value;
}
}
[Transaction(TransactionPropagation.Required, ReadOnly = true)]
public IList<Facility> GetFacilities()
{
return _facilityDao.FetchAll();
}
}
}
最後に、圧縮されて統合されたweb.xml/applicationContext:
<?xml version="1.0" encoding="utf-8"?>
<objects xmlns="http://www.springframework.net">
<db:provider id="DbProvider"
provider="System.Data.SqlClient"
connectionString="Data Source=localhost;...;"/>
<object id="transactionManager"
type="Spring.Data.NHibernate.HibernateTransactionManager, Spring.Data.NHibernate32">
<property name="DbProvider" ref="DbProvider"/>
<property name="SessionFactory" ref="SessionFactory"/>
</object>
<tx:attribute-driven transaction-manager="transactionManager"/>
<object type="Namespace.Dao.FacilityDao, Namespace" id="FacilityDao">
<property name="SessionFactory" ref="SessionFactory"/>
</object>
<object type="Namespace.Services.Assets.AssetsService, Namespace" id="AssetsService">
<property name="FacilityDao" ref="FacilityDao" />
</object>
</objects>
EDIT:MaxとMarijnからヒントを
おかげで、私は今のインタフェースではなく、実際の実装を使用するように私のAssetsServiceを変更しました。しかし、問題は解決しません。ここに改訂された詳細があります。
namespace Namespace.Services.Assets
{
public class AssetsService
{
public AssetsService()
{
System.Console.Out.WriteLine("AssetsService created");
}
public IFacilityDao FacilityDao { get; set; }
[Transaction(TransactionPropagation.Required, ReadOnly = true)]
public IList<Facility> GetFacilities()
{
return FacilityDao.FetchAll();
}
}
}
IFacilityDao:
namespace Namespace.Dao
{
public interface IFacilityDao : IDao<Facility>
{}
public class FacilityDao : DaoBase<Facility>, IFacilityDao
{
}
}
IDao:
namespace Namespace.Dao
{
public interface IDao<T>
{
T Fetch(int id);
T FindByName(string name);
IList<T> FetchAll();
void SaveOrUpdate(T entity);
void Delete(T entity);
}
}
DaoBase:
namespace Namespace.Dao
{
public abstract class DaoBase<T> : IDao<T>
{
public ISessionFactory SessionFactory { get; set; }
public T Fetch(int id)
{
var result = SessionFactory
.GetCurrentSession()
.CreateCriteria(typeof(T))
.Add(Restrictions.Eq("ID", id))
.UniqueResult<T>();
return result;
}
//....
}
}
問題が解決しない場合、私は詳細を追加しました。 –
私の更新を参照してください。 'GetFacilities'を仮想化するか、' IAssetService'インタフェースを作成してください。 – Marijn
IAssetServiceが解決しました。ありがとうございました! :) –