I'm trying to use FluentNHibernate in ServiceStack with the Funq IoC container on a session-per-request basis and I'm running into a problem where upon the second request to my service, I get an ObjectDisposedException. Shouldn't Funq create a new Session for each request?
My understanding is that by using ReusedWithin(ReuseScope.Request) in Funq, each request would get a new ISession, but that's only happening for the first request. In my AppHost I have the following:
public static NH.ISession CurrentSession
{
get
{
SessionFactory = GetFactory();
NH.ISession session = SessionFactory.OpenSession();
return session;
}
}
private static NH.ISessionFactory GetFactory()
{
return Fluently.Configure().Database(MsSqlConfiguration.MsSql2008
.ConnectionString(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString)).Mappings(m =>
{ m.FluentMappings.AddFromAssemblyOf<Case>(); })
.BuildSessionFactory();
}
And the registration with the container:
container.Register<NH.ISession>(c => CurrentSession).ReusedWithin(Funq.ReuseScope.Request);
container.Register<ILog>(c => LogManager.GetLogger(GetType()));
So I figured out what my problem was. When using a request scope of per-request in Funq for a NHibernate ISession, make sure the other services that depend on it are also scoped per-request or their backing dependency (ISesssion in this case) will be disposed of on the next request. I changed my container registration to the below:
container.Register<NH.ISession>(c => CurrentSession).ReusedWithin(Funq.ReuseScope.Request);
container.Register<ILog>(c => LogManager.GetLogger(GetType()));
container.Register<IRequestService>(c => new Services.RequestService(c.Resolve<NH.ISession>(), c.Resolve<ILog>())).ReusedWithin(Funq.ReuseScope.Request);
The key is that the Request service must also be scoped per-request.
Related
I’ve to configure my web application to use the ServiceStack built-in ApiKeyAuthProvider. I’ve registered in the container the OrmLiteAuthRepository with the IAuthRepository interface but it throws an exception saying that I’ve not registered the IUserAuthRepository.
Could someone explain me the difference?
Thanks in advance
EDIT:
Sorry, i've made confusion
The error is
System.NotSupportedException: 'ApiKeyAuthProvider requires a registered IAuthRepository'
Our AppHost's Configure method is
public override void Configure(Container container)
{
var dbFactory = new OrmLiteConnectionFactory("connString", SqlServerDialect.Provider);
container.Register<IDbConnectionFactory>(dbFactory);
container.Register<IUserAuthRepository>(_ => new OrmLiteAuthRepository(dbFactory));
container.Resolve<IUserAuthRepository>().InitSchema();
var authProvider = new ApiKeyAuthProvider()
{
RequireSecureConnection = false
};
Plugins.Add(new AuthFeature(
() => new AuthUserSession(),
new IAuthProvider[] {
authProvider
}
));
}
Could you explain me the difference between these two interfaces? we can't figure out (ServiceStack v.6.0.2)
Please refer to the Auth Repository docs for examples of correct usage, e.g:
container.Register<IDbConnectionFactory>(c =>
new OrmLiteConnectionFactory(connectionString, SqlServer2012Dialect.Provider));
container.Register<IAuthRepository>(c =>
new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()));
container.Resolve<IAuthRepository>().InitSchema();
The IAuthRepository is the minimum interface all Auth Repositories have to implement whilst IUserAuthRepository is the extended interface to enable extended functionality to enabled additional features which all ServiceStack built-in Auth Repositories also implement. But you should never need to register or resolve a IUserAuthRepository, i.e. they should only be registered against the primary IAuthRepository interface.
Resolving Auth Repository
If you need to, the Auth Repository can be accessed from base.AuthRepository or base.AuthRepositoryAsync in your Service where you'll be able to use any IUserAuthRepository APIs since they're all available as extension methods on IAuthRepository, e.g. This example Service calls the IUserAuthRepository.GetUserAuth() method:
public class MyServices : Service
{
public object Get(MyRequest request) =>
AuthRepository.GetUserAuth(request.UserId);
}
Whilst here are the recommended APIs to access the Auth Repository outside of your Services:
var authRepo = HostContext.AppHost.GetAuthRepository();
var authRepoAsync = HostContext.AppHost.GetAuthRepositoryAsync();
I am trying to migrate from .NET Core 1.1 to 2.0, and am stuck migrating the JWT Token configuration. I have an interface/class that provides the JWTBearerOptions, and in .NET Core 2.0 I cannot access my DI Graph objects (since in 2.0, JWT is configured in the ConfigureServices() function). I want to keep my Startup.cs file clean of so many lines of code configuring JWT.
Is there any way to delegate the JWTBearerOptions object creation to a provider created through DI? I want something like the below:
public virtual void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication()
.AddJwtBearer(MyAuthicationScheme.JwtAuthName, options =>
{
myInjectedInstance.SetJwtBearOptions(options, Configuration);
})
}
#flodin
I came across this same problem for the AddJwtBearer and there is a cludgey way to get access to the HttpContext by plugging into OnMessageRecieved Events
jwt.Events = new Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerEvents()
{
OnMessageReceived = context =>
{
// setting the issuer validator delegate here instead of in the jwt.TokenValidationParameters
// allows for accessing the HttpContext items and DI container
context.Options.TokenValidationParameters.IssuerValidator = (issuer, token, parameters) =>
{
// di in callbacks!
var test = context.HttpContext.RequestServices.GetService<ITenant>();
return Task.CompletedTask;
}
Found the answer on microsoft's docs. It is impossible to access DI objects during the ConfigureServices call: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/index?tabs=basicconfiguration#additional-notes
I have ASP.NET Web API application. The application is using Unity as IoC container. The application is also using Hangfire and I am trying to configure Hangfire to use Unity.
So based on documentation i am using Hangfire.Unity which registers the unity container as a current job activator in Hangfire.
I have a class which has dependency on IBackgroundJobClient
public class MyService
{
private MyDBContext _dbContext = null;
private IBackgroundJobClient _backgroundJobClient = null;
public MyService(MyDbContext dbContext, IBackgroundJobClient backgroundJobClient)
{
_dbContext = dbContext;
_backgroundJobClient = backgroundJobClient;
}
}
However even after configuring Hangfire.Unity it could not create & pass instance of BackgroundJobClient
So i had to register every dependency of BackgroundJobClient with unity container.
Unity Registration
public class UnityConfig
{
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
{
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
public static IUnityContainer GetConfiguredContainer()
{
return container.Value;
}
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<MyDbContext>(new HierarchicalLifetimeManager(), new InjectionFactory(x => new MyDbContext()));
// register hangfire dependencies
container.RegisterType<IBackgroundJobClient, BackgroundJobClient>();
container.RegisterType<JobStorage, SqlServerStorage>(new InjectionConstructor("HangfireConnectionString"));
container.RegisterType<IJobFilterProvider, JobFilterAttributeFilterProvider>(new InjectionConstructor(true));
container.RegisterType<IBackgroundJobFactory, BackgroundJobFactory>();
container.RegisterType<IRecurringJobManager, RecurringJobManager>();
container.RegisterType<IBackgroundJobStateChanger, BackgroundJobStateChanger>();
}
}
OWIN Startup
public class Startup
{
public void Configuration(IAppBuilder app)
{
var container = UnityConfig.GetConfiguredContainer();
Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage("HangfireConnectionString");
Hangfire.GlobalConfiguration.Configuration.UseUnityActivator(container);
// if i dont call UseSqlServerStorage() above then UseHangfireDashboard() method fails with exception
//JobStorage.Current property value has not been initialized. You must set it before using Hangfire Client or Server API.
app.UseHangfireDashboard();
app.UseHangfireServer();
RecurringJob.AddOrUpdate<MyService>(x => x.Prepare(), Cron.MinuteInterval(10));
}
}
Code is working with such configuration. However i have questions:
Is this the correct way of configuring Unity with Hangfire?
Why do i need to invoke Hangfire.GlobalConfiguration.Configuration.UseSqlServerStorage("HangfireConnectionString") in OWIN startup even though SqlServerStorage is already registered with Unity container as JobStorage?
If i dont invoke UseSqlServerStorage() method in OWIN startup then i get exception on app.UseHangfireDashboard() method.
JobStorage.Current property value has not been initialized. You must
set it before using Hangfire Client or Server API.
I believe there is a problem where you want to kick off Hangfire outside of the Unity ecosystem, but also want Unity to understand how to instantiate the appropriate Hangfire interfaces with the associated implementations. Since Hangfire itself doesn't use Unity, you will need to start up Hangfire with the appropriate configuration, such as the SQL Server connection string, and then use that configuration to inform Unity how to instantiate the Hangfire interfaces. I was able to solve this problem by setting the global Hangfire configuration for SQL and then use that same Hangfire static instance to set up Unity.
Here's example code where first you will see how I start the hangfire dashboard and server with a connection string:
public void Configuration(IAppBuilder app)
{
var configuration = new Configuration(); // whatever this is for you
GlobalConfiguration.Configuration.UseSqlServerStorage(
configuration.GetConnectionString());
GlobalConfiguration.Configuration.UseActivator(
new HangfireContainerActivator(UnityConfig.GetConfiguredContainer()));
app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
Authorization = new[] {new HangfireAuthorizationFilter()}
});
app.UseHangfireServer();
}
As the second example, here's the configuration of Unity for Hangfire; notice how this code is using the static JobStorage Hangfire object to instantiate any requests for JobStorage.
public static void RegisterHangfire(IUnityContainer container)
{
container.RegisterType<JobStorage>(new InjectionFactory(c => JobStorage.Current));
container.RegisterType<IJobFilterProvider, JobFilterAttributeFilterProvider>(new InjectionConstructor(true));
container.RegisterType<IBackgroundJobFactory, BackgroundJobFactory>();
container.RegisterType<IRecurringJobManager, RecurringJobManager>();
container.RegisterType<IBackgroundJobClient, BackgroundJobClient>();
container.RegisterType<IBackgroundJobStateChanger, BackgroundJobStateChanger>();
}
I believe this approach gives you the best of both worlds where you only set up your SQL Server connection once and you do it early to kick off Hangfire, but then you use that instance to tell Unity how to behave.
builder.Register(c => new ChannelFactory<IBuildingInfoService>
("BasicHttpBinding_IBuildingInfoService"))
.SingleInstance();
builder.Register(c => c
.Resolve<ChannelFactory<IBuildingInfoService>>().CreateChannel())
.As<IBuildingInfoService>()
.UseWcfSafeRelease();
I have got these lines of code in dependency injection for WCF client..
Can somebody explain how does it work.. ?
How does single instance work ?
What is channel Factory doing internally ?
SingleInstance
The above is creating a Singleton. You will get the same instance every time you request it.
There are different ways to create a WCF Client and Channel Factory is one of them. The Channel Factory class is used to construct a channel between the client and server without creating a proxy.
When you create a channel factory - it calls Open internally.
You can see the source code here and if you dig into it, CreateChannel eventually calls EnsuredOpen.
protected void EnsureOpened()
{
base.ThrowIfDisposed();
if (this.State != CommunicationState.Opened)
{
lock (this.openLock)
{
if (this.State != CommunicationState.Opened)
{
this.Open();
}
}
}
}
I need to setup session management in MVC. what is the correct way of doing so?
How to setup nhibernate session management in mvc using structuremap so I don't get:
Session is closed
or
Using a single Session in multiple threads is likely a bug.
My current configuration is:
in GlobalAssax:
protected void Application_Start()
{
ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
Bootstrapper.ConfigureStructureMap();
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
}
in my BootStrapper I do:
var cfg = NHibernateManager.Configuration(assembly);
For<Configuration>().Singleton().Use(cfg);
For<ISessionFactory>().Singleton().Use(cfg.BuildSessionFactory());
For<ISession>().HttpContextScoped().Use(ctx => ctx.GetInstance<ISessionFactory>().OpenSession());
I Inject ISession into repositoryes that I use in application layer.
Edit: What happens if I do this?:
For().LifecycleIs(Lifecycles.GetLifecycle(InstanceScope.PerRequest)).Use(ctx => ctx.GetInstance().OpenSession());
Have you added a dispose for the session?
//In Global.asax.cs
protected void Application_EndRequest()
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
Otherwise it looks correct.