2012-06-02 3 views
9

Задача (аннотация)Autofac - Lifetime и модули

Данный модуль, который регистрирует X. зависимость Зависимость X имеет различный срок эксплуатации в приложении MVC3 (срок службы за HttpRequest), то в консольном приложении (зависимость в lifetimecope с именем). Где или как указать время жизни зависимости X?

Case

Я поставил код, связанный всю базу данных в сборе с модулем в нем, который регистрирует все хранилища. Теперь в модуле также включена регистрация ISession (Nhibernate).

ISession - это зависимость X (в данном случае). ISession имеет другое время жизни в приложении MVC3 (время жизни на запрос), а затем в консольном приложении, где я определяю названный lifetimecope.

Следует ли регистрировать ISession вне модуля? Было бы странно, поскольку это детализация реализации.

Что такое лучший случай здесь? Недостаток дизайна или есть ли для этого умные конструкции :)?

+0

У вас есть конкретные времена жизни в виду для соединений? Если да, являются ли они разными сроками жизни для каждого приложения или они всегда одинаковы независимо от типа приложения? Как насчет пула? Собираетесь ли вы в некоторых приложениях, а не в других? –

+0

Как будто вы сказали: «Расширения MVC используют именованный объем, чтобы достичь механизма один раз за запрос». Http с именем scope не существует, когда вы используете модуль в консольном приложении. В настоящее время я смотрю, какая единица работы будет и которая будет инкапсулирована в область. –

ответ

7

Учитывая ваше описание использования, я бы сказал, что у вас есть несколько вариантов.

Во-первых, вы можете просто зарегистрировать свой собственный набор зависимостей, включая продолжительность жизни. Наличие одного или двух «дублирующих» фрагментов кода в этом отношении не является чем-то большим, учитывая различия между приложением и тот факт, что регистрации выглядят довольно маленькими.

Во-вторых, вы можете обернуть общую часть (минус область видимости) в метод расширения ContainerBuilder, который может использоваться в каждом приложении. Это все равно означает, что каждое приложение имеет небольшой «дублирующий код», но общая логика будет завернута в простое расширение.

public static IRegistrationBuilder<TLimit, ScanningActivatorData, DynamicRegistrationStyle> 
    RegisterConnection<TLimit, ScanningActivatorData, DynamicRegistrationStyle>(this ContainerBuilder builder) 
{ 
    // Put the common logic here: 
    builder.Register(...).AsImplementedInterfaces(); 
} 

Потребляя такое расширение в каждом приложении будет выглядеть следующим образом:

builder.RegisterConnection().InstancePerHttpRequest(); 
// or 
builder.RegisterConnection().InstancePerLifetimeScope(); 

Наконец, если вы знаете, что это либо веб или не веб, вы могли бы сделать пользовательский модуль, который обрабатывает переключатель :

public class ConnectionModule : Autofac.Module 
{ 
    bool _isWeb; 
    public ConnectionModule(bool isWeb) 
    { 
    this._isWeb = isWeb; 
    } 

    protected override void Load(ContainerBuilder builder) 
    { 
    var reg = builder.Register(...).AsImplementedInterfaces(); 
    if(this._isWeb) 
    { 
     reg.InstancePerHttpRequest(); 
    } 
    else 
    { 
     reg.InstancePerLifetimeScope(); 
    } 
    } 
} 

В каждом приложении, вы можете затем зарегистрировать модуль:

// Web application: 
builder.RegisterModule(new ConnectionModule(true)); 

// Non-web application: 
builder.RegisterModule(new ConnectionModule(false)); 

В качестве альтернативы вы упомянули, что ваша продолжительность жизни в других приложениях имеет имя.Вы можете сделать свой модуль взять имя:

public class ConnectionModule : Autofac.Module 
{ 
    object _scopeTag; 
    public ConnectionModule(object scopeTag) 
    { 
    this._scopeTag = scopeTag; 
    } 

    protected override void Load(ContainerBuilder builder) 
    { 
    var reg = builder.Register(...) 
        .AsImplementedInterfaces() 
        .InstancePerMatchingLifetimeScope(this._scopeTag); 
    } 
} 

Потребление схожа:

// Web application (using the standard tag normally provided): 
builder.RegisterModule(new ConnectionModule("httpRequest")); 

// Non-web application (using your custom scope name): 
builder.RegisterModule(new ConnectionModule("yourOtherScopeName")); 

Я бы не рекомендовал просто использовать InstancePerLifetimeScope в веб-приложении, если это не на самом деле то, что вы собираетесь. Как указано в других ответах/комментариях, InstancePerHttpRequest использует конкретную область видимости по времени, чтобы было безопасно создавать дочерние области жизни; использование InstancePerLifetimeScope не имеет такого ограничения, поэтому вы фактически получите одно соединение на одну дочернюю область, а не одно соединение для запроса. Я лично не предполагаю, что другие разработчики не будут использовать охват жизненного цикла ребенка (which is a recommended practice), поэтому в моих приложениях я очень специфичен. Если вы полностью контролируете свое приложение, и вы можете гарантировать, что вы не создаете дополнительные дочерние области или вам действительно нужно одно соединение для каждой области, то, возможно, InstancePerLifetimeScope решит вашу проблему.

+0

Спасибо за обширный ответ! Я придумал это: https://gist.github.com/2883596 Вы вызываете ConfigureUnitOfWork для настройки зависимости IUnitOfWork, которая скрывает детали реализации. Также это решение не зависит от расширений MVC3. Единственным недостатком этого решения является то, что вы можете сконфигурировать все, в то время как вы хотите только продлить жизнь, можно отвлечь, но на самом деле разрезать, если на данный момент :) –

0

Общепринятой практикой является использование одного соединения для каждого запроса HTTP. В этом случае соединения будут зарегистрированы с использованием .InstansePerLifetimeScope(). Например, вы можете сделать что-то вроде:

builder 
    .Register(c => { 
         var conn = new SqlConnection(GetConnectionString()); 
         conn.Open(); 
         return conn; 
        }) 
    .AsImplementedInterfaces() 
    .InstancePerLifetimeScope(); 
+0

Да, я знаю, вы можете это сделать. Моя проблема в том, где это сделать? Это то, за что должен отвечать модуль данных. Однако, похоже, нет способа зарегистрировать соединение внутри модуля и установить время жизни вне модуля. –

+0

Я зарегистрировал бы соединение и установил бы время жизни внутри модуля данных. –

+0

Thats проблема в приложении MVC, время жизни отличается от того, как в консольном приложении, где нет такой вещи, как контекст, такой как Http –

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