IoC - Autofac и регистрация нескольких сервисов с одним и тем же универсальным интерфейсом
У меня есть сервисный слой со следующими классами / интерфейсами (IServices - пустой интерфейс):
public interface IForoChanService<T> : IService
{
T GetById(int id);
IQueryable SearchBy(Expression<Func<T, bool>> predicate);
IEnumerable<T> GetAll();
int Create(T entity);
void CreateMany(IEnumerable<T> entities);
void Delete(T entity);
void Delete(int id);
void DeleteMany(IEnumerable<T> entities);
void Update(T entity);
}
Затем у меня есть абстрактный класс, реализующий эту сигнатуру:
public abstract class ForoChanServiceBase<T> : IForoChanService<T> where T : EntityBase
{
public T GetById(int id)
{
return ChanDbContext.Set<T>().Find(id);
}
//all the other methods as well
}
И наконец конкретные классы:
public class CategoryService : ForoChanServiceBase<Category>
{
}
Я пытаюсь использовать AutoFac для внедрения этих служб (многие: категория, клиент и т. Д.) В конструкторе: у меня есть базовый контроллер:
public abstract class ForoChanBaseController: Controller
{
protected ForoChanServiceBase<Post> PostService { get; private set; }
protected ForoChanServiceBase<Comment> CommentService { get; private set; }
protected ForoChanServiceBase<Category> CategoryService { get; private set; }
protected ForoChanBaseController()
{
}
protected ForoChanBaseController(
ForoChanServiceBase<Post> postService,
ForoChanServiceBase<Comment> commentService,
ForoChanServiceBase<Category> categoryService)
{
PostService = postService;
CommentService = commentService;
CategoryService = categoryService;
}
}
И я устанавливаю autofac следующим образом:
public static void ConfigureIoc()
{
var builder = new ContainerBuilder();
builder.RegisterType<CommentService>().As<ForoChanServiceBase<Comment>>().InstancePerRequest();
builder.RegisterType<CategoryService>().As<ForoChanServiceBase<Category>>().InstancePerRequest();
builder.RegisterType<PostService>().As<ForoChanServiceBase<Post>>().InstancePerRequest();
builder.Build();
}
Проблема в том, что у меня есть, когда в контроллере мне нужно использовать любой метод службы, что парень (CategoryService) является нулевым:
public ActionResult Create()
{
var p = new PostFormNewVm
{
Categories = CategoryService.GetAll().Select(c => new CategoryVm { Id = c.Id, Title = c.Title })
};
return View(p);
}
Помимо этой ошибки я делаю что-то не так? Я не могу заставить это работать.
Я тоже попробовал с интерфейсом.
1 ответ
Ваш ForoChanBaseController
содержит несколько конструкторов, что является анти-паттерном. Из-за существования этого конструктора по умолчанию существует производный класс, который использует этот конструктор вместо перегруженного, что вызывает зависимости null
,
Хотя этот ctor по умолчанию является причиной для того, чтобы вы задали вопрос здесь, есть еще более очевидные проблемы с вашим дизайном:
- Хотя вы можете удалить конструктор по умолчанию, вообще не используйте этот базовый класс. Базовые классы часто являются большими нарушениями Единого принципа ответственности и используются либо для заполнения сквозных задач, либо для других служебных функций. При наличии этого базового класса производные типы вынуждены требовать зависимости, которые они могут даже не использовать вообще. Это усложняет ваш код и усложняет тестирование.
- Так как у вас есть
IForoChanService<T>
интерфейс, потребители не должны зависеть отForoChanServiceBase
Базовый класс. На самом деле, тот же совет, что и раньше: этот базовый класс, вероятно, вообще не должен существовать. IForoChanService<T>
большой набор инструментов, где потребители используют только один или два из этих методов одновременно. Это означает, что вы нарушаете принцип разделения интерфейса.IForoChanService<T>
реализации могут нарушать принцип подстановки Лискова, так как будут реализации, которые не позволяют удалять сущности. Это вызовет вызовDelete
потерпеть неудачу с исключением, вместоDelete
не существует для этого лица.