2016-10-14 3 views
0

Я использую WebAPI с Autofac и запускаю долговременную задачу (огонь и забыть), которая будет жива после жизни HTTP-запроса. Поэтому я бы хотел, чтобы ApiController автоматически удалял объект, который состоит из задачи с длительным сроком выполнения, после окончания срока службы ApiController.следу.инфо. <T>

В контроллере Web API, я хотел бы использовать Owned<T> класс для того, чтобы ввести одну из зависимостей, не связывая его с LifeTimeScope экземпляра ApiController. Кажется, Owned<T> - хороший выбор для этого, но я бы хотел наследовать его, чтобы иметь виртуальное (полиморфное) свойство Value, которое я могу высмеять с библиотекой Moq.

Однако, если унаследовано от Owned<T>, autofac не распознает (из-за отражения?) Мой MyOwned<T> и выдает исключение.

Ни один из конструкторов, найденных с «Autofac.Core.Activators.Reflection.DefaultConstructorFinder» по типу «autofak.Meta» не может быть вызван с помощью имеющихся услуг и параметров: Не удается разрешить параметр «System.Func'2 [ System.Int32, autofak.MyOwned'1 [autofak.Root]] root 'конструктора' Void .ctor (System.Func'2 [System.Int32, autofak.MyOwned'1 [autofak.Root]]) '.

Это мой класс верхнего уровня, который зависит от класса Root.

class Meta 
{ 
    public MyOwned<Root> Root { get; private set; } 

    public Meta(Func<int, MyOwned<Root>> root) 
    { 
     Root = root(2); 
    } 
} 

Мой регистрационный код ниже:

var container = new ContainerBuilder(); 

container.RegisterType<child>(); 
container.RegisterType<grandchild>(); 
container.RegisterType<Root>(); 
container.RegisterType<Meta>(); 

var builder = container.Build(); 

Можно ли наследовать от Владельца и заставить его работать, или я должен попробовать другой подход?

Update:

Помимо принятого решения, я также по другому пути, создав SingleInstance() фабрику для создания новых LifeTimeScope объектов из lifetimescope корня/приложения. Подобно классу Owned<T>, я создал новый класс, который также сохраняет это новое время жизни (созданное из области жизненного цикла root) для каждой задачи и позволяет вызвать Dispose(), как в Owned<T>.

+1

Мое предположение: вам нужно зарегистрировать свой 'MyOwned ' класс с контейнером, подобным тому, как настроено 'Owned '. – Amy

+0

Я думаю, что с 'Owned ' нам не нужна специальная регистрация, кроме регистрации типов, не так ли? – Deniz

+0

Да, он встроен для 'Owned ', но ваш нет. Не должно быть слишком сложно найти, где 'Owned ' зарегистрирован в источнике Autofac и в основном дублирует его для вашего класса. – Amy

ответ

2

Самый простой способ сделать то, что вы хотите, было бы создать новый компонент, который использует Owned<T> вместо унаследованного от Owned<T>

public interface IOwned<T> : IDisposable 
{ 
    T Value { get; } 
} 

public class MyOwned<T> : IOwned<T> 
{ 
    public MyOwned(Owned<T> owned) 
    { 
     this._owned = owned; 
    } 

    private readonly Owned<T> _owned; 

    public virtual T Value 
    { 
     get 
     { 
      return this._owned.Value; 
     } 
    } 

    public void Dispose() 
    { 
     this._owned.Dispose(); 
    } 
} 

Затем зарегистрировать компонент, используя метод RegisterGeneric и ExternallyOwned.

builder.RegisterGeneric(typeof(MyOwned<>)) 
     .As(typeof(IOwned<>)) 
     .ExternallyOwned(); 

Вы должны объявить его как ExternallyOwned, потому что без этого Autofac будет пытаться утилизировать этот компонент в конце его ILifetimeScope и цель Owned<T> это позволит вам решить, когда вы располагаете компонент.

Другим вариантом было бы создать свой собственный Owned<T> компонент, который является гораздо более сложным, так как вам нужно будет реализовать IRegistrationSource управлять ребенком ILifetimeScope созданного Owned<T> компонента.

+0

@Cryil Durand: Это приятное решение. Кроме того, я попробовал что-то другое. Я создал новый интерфейс/объект, такой как IOwned/MyOwned, не наследуя от Owned, но копируя его реализацию. Моя главная цель - создать независимую от жизни время для HTTP-запроса в WebAPI. Поэтому я создал фабрику объект (с 'SingleInstance()', который создает вложенные времена жизни из корня), который я бы хотел ввести и передать его контроллеру. Затем я вызываю 'Dispose()' вручную в свой собственный 'Owned ' класс. Мне нравится ваше решение. – Deniz

+0

@Deniz Не могли бы вы обновить свой вопрос, включив ваши изменения? –

 Смежные вопросы

  • Нет связанных вопросов^_^