We have WCF Services using autofac and FluentNhibernate. The issue is that it is resulting in memory leak. After every 2-3 hours our application becomes very slow and we have to restart our app-pool.
The following is the code in our Application_start for Autofac registration of componenets in our Global.asax file
What can I do to solve this? Or where start to look for?
var builder = new ContainerBuilder();
builder.RegisterAssemblyTypes(typeof(IPwoSummaryCategoryService).Assembly).AsImplementedInterfaces();
builder.RegisterType<TemplateServiceCollection>().As<ITemplateServiceCollection>();
// Register Singletons
builder.RegisterType<QueryFacade>().As<IQueryFacade>().SingleInstance();
builder.RegisterType<CommandAggregator>().As<ICommandAggregator>().SingleInstance();
// Register open generics builder.RegisterAssemblyTypes(typeof(ICommandHandler<>).Assembly).AsClosedTypesOf(typeof(ICommandHandler<>));
builder.RegisterInstance<MessageBrokerClient>(new MessageBrokerClient(Activator.CreateInstance<CustomMessageFormatter>(), AppConfiguration.MSMQRequestQueueUri, AppConfiguration.MSMQUser, false))
.As<IMessageBrokerClient>().SingleInstance();
builder.RegisterInstance<Logger>(new Logger(HostingEnvironment.ApplicationPhysicalPath)).As<ILogger>();
builder.RegisterType<QuotesUnlockedByAdmin>().As<IQuotesUnlockedByAdmin>().SingleInstance();
// Register the Seed Data Builder
builder.RegisterType<SeedDataBuilder>();
// Register WCF Web Services
builder.RegisterType<QueryService>();
builder.RegisterType<CommandService>();
builder.RegisterType<MasterDataService>();
builder.RegisterType<AuthenticationService>();
builder.RegisterType<UserProfileService>();
//builder.RegisterType<OfflineSyncService>();
builder.RegisterType<ExternalDataQueryService>();
builder.RegisterType<DataContextProvider>().As<IDataContextProvider>().SingleInstance();
builder.RegisterAssemblyTypes(typeof(IDataContext).Assembly,typeof(DataContext).Assembly).AsImplementedInterfaces();
// Create a single Session Activator (manages multiple Session Factories) per AppDomain
builder.Register(context => SessionActivator.Build.FromConfiguration(new Configuration())).As<ISessionActivator>().SingleInstance();
builder.RegisterType<DataContextProxy>();
// Custom Registration for the CurrencyConverter
builder.Register(context => new CurrencyConverter(context.Resolve<IMasterQueryFacade>().GetCurrencies())).As<ICurrencyConverter>().SingleInstance();
var container = builder.Build();
AutofacHostFactory.Container = container;
ServiceLocator.SetLocatorProvider(() => new AutofacContrib.CommonServiceLocator.AutofacServiceLocator(container));
// Pre-populate the database with seed data (if missing)
container.Resolve<SeedDataBuilder>().InitializeSeedData();
Related
Azure App Functions 3.0
I am attempting to log activities and errors from an internal class used by functions but the logs are not correct written, since I cannot instantiate/find the service binded to the correct "ILogger" (the one naturally injected in constructors and functions).
I do not want to pass down the Logger instance through classes from the entry point, but inject it correctly.
Tried new LoggerFactory() with no success.
var loggerFactory = new LoggerFactory();
var logger = loggerFactory.CreateLogger("InfoLogger");
logger.LogInformation("Please, log this information!");
Tried ActivatorUtilities.CreateInstance() with Ninject registering the service provider associated with the logger at startup with no success.
// Startup.cs
NinjectKernel._kernel
.Bind<IServiceProvider>()
.ToMethod(context => builder.Services.BuildServiceProvider())
.InSingletonScope();
// MyInternalClass.cs
var serviceProvider = NinjectKernel.Get<IServiceProvider>();
var logger = ActivatorUtilities.CreateInstance<ILogger>(serviceProvider);
logger.LogInformation($"Information Ticket: {ticket} | Data: ...");
Any help are welcome!
In ASP.NET Core 1.x the IoC container could be used to get a concrete implementation of Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IDefaultKeyServices but no such interface is registered with the IoC in ASP.NET Core 2.0. Where did IDefaultKeyServices go? Or what replaces it?
The interface looked like this:
public interface IDefaultKeyServices {
//
// Summary:
// Gets the default Microsoft.AspNetCore.DataProtection.XmlEncryption.IXmlEncryptor
// service (could return null).
IXmlEncryptor GetKeyEncryptor();
//
// Summary:
// Gets the default Microsoft.AspNetCore.DataProtection.Repositories.IXmlRepository
// service (must not be null).
IXmlRepository GetKeyRepository();
}
Microsoft documents the interface here.
I realize that this interface is in an "Internal" namespace and is subject to change (and change it did!). But how does one now get the default key repository and the default key encryptor in 2.x?
IDefaultKeyServices and its implementation DefaultKeyServices were removed with this commit.
Instances of IXmlRepository and IXmlEncryptor could be accessed via XmlRepository and XmlEncryptor properties of KeyManagementOptions.
Key storage providers article lists built-in implementations of IXmlRepository. You setup appropriate repository by calling PersistKeysTo...() extension method on IDataProtectionBuilder, e.g.:
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp\"));
or
services.AddDataProtection()
.PersistKeysToRegistry(Registry.CurrentUser.OpenSubKey(#"SOFTWARE\Sample\keys"));
Key Encryption At Rest article lists built-in implementations of IXmlEncryptor. You setup appropriate encryptor by calling ProtectKeysWith...() extension method on IDataProtectionBuilder, e.g.:
services.AddDataProtection()
.ProtectKeysWithDpapi();
Here is a demo sample (Microsoft.AspNetCore.DataProtection NuGet required):
static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(#"c:\temp\"))
.ProtectKeysWithDpapi();
var serviceProvider = services.BuildServiceProvider();
var options = serviceProvider.GetService<IOptions<KeyManagementOptions>>();
var keyManagementOptions = options.Value;
var xmlRepository = keyManagementOptions.XmlRepository;
// Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository
var repositoryType = xmlRepository?.GetType();
var xmlEncryptor = keyManagementOptions.XmlEncryptor;
// Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlEncryptor
var encryptorType = xmlEncryptor?.GetType();
}
One more useful article in addition to already linked: Key management extensibility
I am using the Change Password functionality that visual studio generated for the accountcontroller. I am able to change the password without errors but when I go to login using the new password, I get a login error but if I use the old password, it works.
If I restart the app then the newly changed password takes effect. I am also using Autofac, may be I am not configuring the container correctly.
var builder = new ContainerBuilder();
builder.Register(c => new ApplicationDataContext(connectionString)).InstancePerLifetimeScope();
builder.RegisterType<ApplicationUserManager>().AsSelf();
builder.RegisterType<ApplicationRoleManager>().AsSelf();
builder.Register(c => new UserStore<ApplicationUser>(c.Resolve<ApplicationDataContext>())).AsImplementedInterfaces();
builder.Register(c => new RoleStore<IdentityRole>(c.Resolve<ApplicationDataContext>())).AsImplementedInterfaces();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();
builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager>
{
DataProtectionProvider = new DpapiDataProtectionProvider("Application")
});
builder.Register(c => new ApplicationOAuthProvider(publicClientId, c.Resolve<ApplicationUserManager>())).As<IOAuthAuthorizationServerProvider>();
Any help will be much appreciated.
Thanks
--------UPDATED----------
ContanierConfig.cs
public static void Configure(HttpConfiguration config)
{
// Configure the application for OAuth based flow
const string publicClientId = "self";
// ContainerConfig Config
var connectionString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
var elasticsearchUrl = ConfigurationManager.AppSettings["ElasticSearchUrl"];
var elasticSearchName = ConfigurationManager.AppSettings["ElasticSearchName"];
var builder = new ContainerBuilder();
builder.Register(c => new BimDataContext(connectionString)).InstancePerRequest();
builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
builder.RegisterType<ApplicationRoleManager>().AsSelf().InstancePerRequest();
builder.Register(c => new UserStore<ApplicationUser>(c.Resolve<BimDataContext>())).AsImplementedInterfaces().InstancePerRequest();
builder.Register(c => new RoleStore<IdentityRole>(c.Resolve<BimDataContext>())).AsImplementedInterfaces().InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>().InstancePerRequest();
builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager>
{
DataProtectionProvider = new DpapiDataProtectionProvider("Application")
}).InstancePerRequest(); ;
builder.RegisterType<SimpleRefreshTokenProvider>().As<IAuthenticationTokenProvider>().InstancePerRequest();
builder.RegisterType<AuthRepository>().As<IAuthRepository>().InstancePerRequest();
builder.Register(c => new ApplicationOAuthProvider(
publicClientId,
c.Resolve<ApplicationUserManager>(),
c.Resolve<IAuthRepository>()))
.As<IOAuthAuthorizationServerProvider>().InstancePerRequest();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).InstancePerRequest();
// UoW registration: being explicit
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerRequest();
// Repositories registration
builder.RegisterAssemblyTypes(typeof(ClientRepository).Assembly)
.AsImplementedInterfaces()
.InstancePerRequest();
// Services registration
builder.RegisterAssemblyTypes(typeof(ClientService).Assembly)
.AsImplementedInterfaces()
.InstancePerRequest();
builder.RegisterAssemblyTypes(typeof(ClientSearchService).Assembly)
.AsImplementedInterfaces()
.InstancePerRequest();
builder.RegisterType<IfcFileImportTask>().As<IIfcFileImportTask>().InstancePerRequest();
builder.RegisterType<COBieFileImportTask>().As<ICOBieFileImportTask>().InstancePerRequest();
// Hangfire registration
builder.RegisterType<BackgroundJobClient>().As<IBackgroundJobClient>().InstancePerRequest();
// OPTIONAL: Register the Autofac filter provider.
builder.RegisterWebApiFilterProvider(config);
// Set the dependency resolver to be Autofac.
var container = builder.Build();
JobActivator.Current = new AutofacJobActivator(container);
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
Startup.Auth.Cs
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
// Configure the db context and user manager to use a single instance per request
//app.CreatePerOwinContext(BimDataContext.Create);
//app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
var oAuthAuthorizationServerProvider = GlobalConfiguration.Configuration.DependencyResolver.GetRequestLifetimeScope().Resolve<IOAuthAuthorizationServerProvider>();
var authenticationTokenProvider = GlobalConfiguration.Configuration.DependencyResolver.GetRequestLifetimeScope().Resolve<IAuthenticationTokenProvider>();
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = oAuthAuthorizationServerProvider,
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5),
RefreshTokenProvider = authenticationTokenProvider,
// In production mode set AllowInsecureHttp = false,
AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
Getting error
"value cannot be null. parameter name context autofac" on line var oAuthAuthorizationServerProvider = GlobalConfiguration.Configuration.DependencyResolver.GetRequestLifetimeScope().Resolve<IOAuthAuthorizationServerProvider>();
I was missing a key component of oauth2, the solution to this problem is refresh_tokens. On change password, invalidate the refresh token and force user to log out.
http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/
If using ASP.NET (this includes MVC and Web API, Web Forms, etc) and AutoFac you should register all your components using the extension method .InstancePerRequest(). The only exception is for components that are thread safe and where you do not have to worry about errors/unexpected results occurring from one request accessing the same (stale) data as another. An example might be a Factory or a Singleton.
Example of use on a line of code:
builder.Register(c => new UserStore<ApplicationUser>(c.Resolve<ApplicationDataContext>())).AsImplementedInterfaces().InstancePerRequest();
This ensures that every new incoming Http Request will get its own copy of that implementation (resolved and injected hopefully via an interface). Autofac will also cleanup the Disposable instances at the end of each request.
This is the behavior you need. It ensures that there is no cross request interference (like one request manipulating data on a shared dbcontext on another request). It also ensures that data is not stale as it is cleaned up after each request ends.
See the Autofac documentation for more details (here an excerpt).
Instance Per Request
Some application types naturally lend themselves to “request” type semantics, for example ASP.NET web forms and MVC applications. In these application types, it’s helpful to have the ability to have a sort of “singleton per request.”
Instance per request builds on top of instance per matching lifetime scope by providing a well-known lifetime scope tag, a registration convenience method, and integration for common application types. Behind the scenes, though, it’s still just instance per matching lifetime scope.
Changing your DI definitions above to include this should resolve your issues (I think based on what you have provided). If not then it might be a problem with your Identity registration in which case you should post that code so it can be scrutinized.
Given the following code from my Configure method:
OrmLiteConnectionFactory dbFactory = new OrmLiteConnectionFactory(ConfigUtils.GetConnectionString("Oracle:FEConnection"), OracleOrmLiteDialectProvider.Instance);
container.Register<IDbConnectionFactory>(dbFactory)).ReusedWithin(ReuseScope.Request); // <== this does NOT work
// But these work
container.Register<IPreprocessorRepository>(c => new CachedPreprocessorRepository(dbFactory, c.Resolve<ICacheClient>())).ReusedWithin(ReuseScope.Default);
container.Register<IPreprocessor>(c => new DirectApiPreprocessor(c.Resolve<IPreprocessorRepository>(), c.Resolve<IValidator<LeadInformation>>())).ReusedWithin(ReuseScope.Default);
How can I make sure that the dbFactory instanciated is used in other registrations will per request?
Thank you,
Stephen
You can't change the scope of this:
container.Register<IDbConnectionFactory>(dbFactory)
.ReusedWithin(ReuseScope.Request);
Because you're only passing in an instance of an object, and not a factory function that the IOC would need to be able to instantiate instances of the object itself. All the IOC can do in this case is return the instance, making it a singleton.
To be able to change the scope you would need to register a delegate that can create an instance, i.e:
container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(...))
.ReusedWithin(ReuseScope.Request);
But you never want to do this with any connection or client factories like IDbConnectionFactory or IRedisClientsManager since they're designed to be used as singletons.
i.e. They're thread-safe singleton factories used to create single client/connection instances:
using (var db = container.Resolve<IDbConnectionFactory>().Open())
{
//...
}
using (var redis = container.Resolve<IRedisClientsManager>().GetClient())
{
//...
}
I'd like (through app/web configuration perhaps) to change the cache client used in my ServiceStack application, during runtime.
For example, I have this currently:
container.Register<ICacheClient>(new MemoryCacheClient());
I'd like at runtime to change this to a Redis ICacheClient usage. What if I had two containers registered (one Memory and on Redis). Is it possible to switch between containers at runtime in a call like this in my service:
public object Get(FooRequest request)
{
string cacheKey = UrnId.CreateWithParts("Foo", "Bar");
return RequestContext.ToOptimizedResultUsingCache(base.Cache, cacheKey, sCacheDuration, () =>
{
return TestRepository.Foos;
});
}
EDIT:
Note, after more research, if you have more than one ICacheClient registered:
container.Register<IRedisClientsManager>(c => new PooledRedisClientManager("localhost:6379"));
container.Register(c => c.Resolve<IRedisClientsManager>().GetCacheClient());
container.Register<ICacheClient>(new MemoryCacheClient());
Then accessing base.Cache within your service will return the most recent ICacheClient that was registered... ie: in the case above, MemoryCacheClient.
So with the ability to access the Cache object from within the service, I'd just need a way to get a particular Cache from my registered caches, which I can't see any property for.
Doing something like this would allow you to register different providers with the container based on a web config setting:
var redisCacheString = ConfigurationManager.AppSettings["UseRedis"];
var useRedis = false;
if (!bool.TryParse(redisCacheString, out useRedis))
{
container.Register<IRedisClientsManager>(c => new PooledRedisClientManager("localhost:6379"));
container.Register(c => c.Resolve<IRedisClientsManager>().GetCacheClient());
}
else
{
container.Register<ICacheClient>(new MemoryCacheClient());
}
Hope that helps!
It seems to me that you'll need more flexibility rather than just a simple registration on the composite root, you can try to implement the composite pattern in your container registration.
steven explains this pattern using simple injector but I think it can be implemented with the IOC provided OOB by SS or any other
I hope that helps