Правильное использование UnitOfWork в сервисах?

Доброго времени суток!

Система спроектирована на N-Layer архитектуре:
  • слой данных DAL (Data Access Layer) (Entity Framework 6, Repositories, UnitOfWork)
  • слой логики BLL (Busisness Logic Layer)
  • слой отображения PL (Presentation layer) (ASP.NET MVC 4)


Вопрос заключается в следующем -

Какой из вариантов использования UnitOfWork в сервисах BLL является более правильным?

Вариант 1 (использование свойства, и явно вызывая Dispose() в контроллере ASP.NET MVC):
namespace MyApp.BLL.Services
{
    public class MyService
    {
		private UnitOfWork _uow { get; set; }
		
		public MyService()
		{
			_uow = new UnitOfWork();
		}
		
		public List<SomeDTO> SomeGetMethod()
		{
			IEnumerable<Entity> entities = _uow.SomeRepository.Get(x => x.Id==1);
			...
			return ...
		}
		
		public void SomeSetMethod(int value)
		{
			_uow.SomeRepository.Insert(new Entity { Value = value });
			
			_uow.Commit(); // SaveChanges();
		}
		
		public Dispose()
		{
			_uow.Dispose();
		}
	}
}


Вариант 2 (использование конструкции using):
namespace MyApp.BLL.Services
{
    public class MyService
    {
		public List<SomeDTO> SomeGetMethod()
		{
			using(UnitOfWork uow = new UnitOfWork())
			{
				IEnumerable<Entity> entities = uow.SomeRepository.Get(x => x.Id==1);
			}
			....
			return ...
		}
		
		public void SomeSetMethod(int value)
		{
			using(UnitOfWork uow = new UnitOfWork())
			{
				uow.SomeRepository.Insert(new Entity { Value = value });
				
				uow.Commit(); // SaveChanges();
			}
		}
	}
}


А также второй вопрос про сервисы:
Допустим есть сервис, который отвечает за работу модуля сообщений в системе - IMessagesService и есть второй сервис, который отвечает за работу другого модуля ISomeService. В результате выполнения какого-то метода в сервисе ISomeService необходимо отправить сообщение в систему. Правильно ли будет вызвать метод другого сервиса IMessagesService для отправки сообщения?

Пример:
public interface IMessagesService
{
	void Send(int userFrom, int userTo, string message);
	// other methods...
}

public class MessageService
{
	public void Send(int userFrom, int userTo, string message)
	{
		// some logic here
	}
}

public interface ISomeService
{
	void SomeMethod(int somevalue);
}

public class SomeService: ISomeService
{
	public void SomeMethod(int somevalue)
	{
		// some logic here
		
		// после необходимо отправить сообщение
		messageService = new MessageService();
		messageService.Send(1, 2, "some text");
	}
}


Другими словами, правильно ли вызывать из одного сервиса методы другого сервиса?

Заранее благодарю за любую помощь!
  • Вопрос задан
  • 1660 просмотров
Пригласить эксперта
Ответы на вопрос 2
@WhiteNinja Автор вопроса
Up. Необходим дельный совет
Ответ написан
Комментировать
Valeriy1991
@Valeriy1991
Разработчик .NET C# (ASP.NET MVC) в Alfa-B, Moscow
Добрый день!

По первому вопросу я бы отдал предпочтение using, потому как можно случайно забыть явно вызвать Dispose. А using, как известно, вызовет его сам.

А вот по второму вопросу - боюсь, не смогу подсказать единственно верного решения. Я сам как-то столкнулся с такой проблемой, и долго думал, как ее решить. Особенно когда идет использование IoC-контейнеров. На одном из проектов компании, где сейчас работаю, используется такой подход: создается синглтон, у которого в качестве свойств перечислены интерфейсы, например:

public sealed class Endpoint
    {
        ...
        // Закрытый конструктор
        private Endpoint()
        {
            Initialization();
        }
        ...
        
        // Реализация синглтона
        public static Endpoint Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (InstanceLocker)
                    {
                        if (_instance == null)
                            _instance = new Endpoint();
                    }
                }

                return _instance;
            }
        }
        ...
        public IMyService MyService { get; private set; }
        public ISomeService SomeService { get; private set; }
        ...


И затем эта некая общая "точка доступа" используется следующим образом:

var serviceResult = Endpoint.Instance.MyService.GetData();

Т.к. это синглтон, то обращение Endpoint.Instance всегда создаст единственную реализацию вместе со всеми необходимыми сервисами.
Из плюсов - доступ из любого места (в рамках разумного, конечно же) к любому сервису.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы