В настоящее время я запускаю проект ASP.NET с использованием MVC3, Spring.NET и FluentNHibernate.Spring.NET, C#, Injection Dependency и транзакции
Мой фон - это в основном java, но с некоторой экспозицией Spring Framework, поэтому Spring.NET должен быть легким, peasy, правильно?
Архитектура приложения довольно ванильная, с контроллерами, использующими Службы, Службы, использующие DAO и DAO с использованием объектов и сопоставлений NHibernate.
На данный момент, я почесал голову в текущем сценарии:
Один из моих методов обслуживания использует Дао, который вводится с помощью Spring.NET. Когда я аннотирую метод службы с помощью атрибута [Транзакция], зависимость DAO перестает вставляться в мою службу, вызывая NullReferenceExceptions.
Любые идеи относительно того, почему это может произойти, будут очень признательны.
Некоторые коды, чтобы проиллюстрировать проблему. Это не настоящий код, но он довольно близок. Первый абстрактный класс теста, который расширяет весну класса 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:
Благодаря советы от Макса и 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 решил это. Спасибо! :) –