#servicestack #idisposable
#servicestack #idisposable
Вопрос:
Я использую funq от ServiceStack, и у меня есть код ниже в моем файле AppHost. Ошибка истечения времени ожидания API из-за превышения максимального предела размера пула приложений.
var dbFactory = new OrmLiteConnectionFactory(string.Empty, SqlServerDialect.Provider);
...
// Loop to get multiple different country connection string
foreach (string server in countryCodeList)
{
dbFactory.RegisterConnection(server, connectionString, SqlServerDialect.Provider);
}
this.RequestFilters.Add((httpReq, httpRes, requestDto) =>
{
requestInfo = requestDto.Dump();
...
container.Register<IReferenceRepository>(c => new ReferenceRepository(dbFactory, baseModel.db_country_code));
container.Register<ICompanyRepository>(c => new CompanyRepository(dbFactory, baseModel.db_country_code));
...
});
Я реализовал IDisposable в своем базовом классе репозитория. Но, похоже, он не удаляет соединение в конце каждого запроса. В perfmon.exe можно видеть, что NumberOfPooledConnections продолжает увеличиваться для каждого запроса, не удаляясь.
Коды в классе bass репозитория:
public class Repository : IDisposable
{
protected IDbConnectionFactory dbFactory { get; set; }
public string CountryCode { get; set; }
private IDbConnection db;
public Repository(IDbConnectionFactory dbConnectionFactory, string countryCode)
{
this.dbFactory = dbConnectionFactory;
this.CountryCode = countryCode;
}
protected virtual IDbConnection Db(string connectionKey)
{
return db ?? (db = dbFactory.OpenDbConnection(connectionKey));
}
public virtual void Dispose()
{
if (db != null)
db.Dispose();
}
}
Просто интересно, добавляет ли ReusedWithin(ReuseScope.Запрос) в контейнер.Регистрация части поможет ли это?
Может кто-нибудь подсказать мне, правильно ли я поступаю? Заранее спасибо.
Отредактировано: запрос API будет вызываться из одной службы в другую, и он получает данные из другого репозитория.
Комментарии:
1. (Соединения удаляются соответствующим образом, верно? Вероятно, это следует обрабатывать через связанный контейнер IoC ..)
2. @user2864740 Не совсем. Для запроса API он будет инициирован для другой службы и получит данные из другого репозитория. Не уверен, что это вызывает проблему?
Ответ №1:
Все зависимости в ServiceStack должны быть зарегистрированы, AppHost.Configure()
которые выполняются один раз при запуске и после этого должны считаться неизменяемыми.
Вы не должны регистрировать зависимости в RequestFilter (который запускается при каждом запросе).
OrmLiteConnectionFactory
(как и все фабрики в ServiceStack) предназначены для регистрации как одноэлементные, что также является временем жизни по умолчанию в Funq, т.е.:
container.Register<IDbConnectionFactory>(
c => new OrmLiteConnectionFactory(connString, SqlServerDialect.Provider));
Затем вы можете разрешить его из IOC, чтобы зарегистрировать свои именованные соединения, например:
var factory=(OrmLiteConnectionFactory)container.Resolve<IDbConnectionFactory>();
foreach (string server in countryCodeList)
{
factory.RegisterConnection(server, connString, SqlServerDialect.Provider);
}
Все другие зависимости, такие как ваши репозитории, также должны быть зарегистрированы AppHost.Configure()
. Если он реализует IDisposable
и имеет возможность повторного использования None
или Request
, он будет удален в конце запроса.
Использование данных запроса для создания зависимостей
Поскольку зависимости необходимо регистрировать при запуске, у него нет доступа к данным запроса. Если это то, что необходимо, его необходимо передать во время выполнения.
Вы можете уменьшить шаблон, добавив его в базовый класс обслуживания, например:
public abstract class AppServiceBase : Service
{
public IDbConnectionFactory DbFactory
{
get { return TryResolve<IDbConnectionFactory>(); }
}
ReferenceRepository refRepo;
public ReferenceRepository ReferenceRepo
{
get
{
if (refRepo == null)
refRepo = new ReferenceRepository(
DbFactory.OpenDbConnection(Request.Param("c_code")));
return refRepo;
}
}
public override Dispose()
{
base.Dispose();
if (refRepo != null)
refRepo.Dispose();
}
}
К которому ваши службы могут обращаться как к обычной зависимости, т.е.:
public class MyService : AppServiceBase
{
public object Get(Request request)
{
var foo = ReferenceRepo.GetById(request.Id);
}
}
Комментарии:
1. Могу ли я узнать, как получить DbFactory в классе AppServiceBase?
2. @aQing ok, да, пример обновлен. Вы можете использовать
TryResolve<T>
для разрешения зависимостей от класса Service. Таким же образом класс Service извлекает свою IDbConnection .3. Развернуты коды для производства и проблема решена. Спасибо @mythz за оперативную поддержку и решение! =)