1

私は現在、MVC3、Spring.NET、および FluentNHibernate を使用して ASP.NET プロジェクトの開発を開始しています。

私のバックグラウンドは主に Java ですが、Spring フレームワークに少し触れているので、Spring.NET は簡単で、簡単ですよね?

アプリケーション アーキテクチャは、サービスを使用するコントローラー、DAO を使用するサービス、および NHibernate エンティティとマッピングを使用する DAO を使用する、かなり単純なものです。

現時点では、現在のシナリオに頭を悩ませています。

私のサービス メソッドの 1 つは、Spring.net を使用して注入される Dao を使用します。[Transaction] 属性でサービス メソッドに注釈を付けると、DAO 依存関係がサービスに注入されなくなり、NullReferenceExceptions が発生します。

なぜこれが起こるのかについてのアイデアは大歓迎です。

問題を説明するためのコード。これは実際のコードではありませんが、かなり近いコードです。まず、Spring クラス 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);
   }
  }
}

Service クラスは次のとおりです。

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>

編集:

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;
        }

     //.... 
}

} FacilityDao はプロキシされていません

4

2 に答える 2