ServiceStack Authenticate attribute results in null ref exception - pull request 267 - authentication

I am making an MVC3 site using ServiceStacks authentication mechanism. When I add the AuthenticateAttribute to a controller, I get a null reference exception:
System.NullReferenceException was unhandled by user code
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=ServiceStack.FluentValidation.Mvc3
StackTrace:
at ServiceStack.Mvc.ExecuteServiceStackFiltersAttribute.OnActionExecuting(ActionExecutingContext filterContext) in C:\src\ServiceStack\src\ServiceStack.FluentValidation.Mvc3\Mvc\ExecuteServiceStackFiltersAttribute.cs:line 21
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<>c__DisplayClass17.<InvokeActionMethodWithFilters>b__14()
at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
I can see in github that pull request #267 seems to make some null ref check exactly where my code currently throws. I have another project where authentication works, but the new failing code is running on a newer version of ServiceStack and I can't see what the difference is, so any ideas about what could cause this exception for new versions of service stack (v. 3.9.18)
Here is my configuration code:
Plugins.Add(new AuthFeature(
() => new AuthUserSession(), // Here a custom IAuthSession implementation could be used instead of UserSession.
// Allow authentication by using cookies set when authenticating with username/password credentials posted to the /auth/credentials service.
new IAuthProvider[]{ new CredentialsAuthProvider() }
)
);
//Enable Funq IOC in MVC controllers.
ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container));
IUserAuthRepository userRepository = new OrmLiteAuthRepository(dbFactory);
container.Register(userRepository);
container.Register<ICacheClient>(new MemoryCacheClient());
// Initialise Registration feature, providing the /register route.
Plugins.Add(new RegistrationFeature());
And my Controller base class:
public abstract class ControllerBase : ServiceStackController<AuthUserSession> {
public IDbConnectionFactory Db { get; set; }
public ILog Log { get; set; }
//Common extension point for all controllers. Inherits from ServiceStack to take advantage of SS powerpack + auth.
public override string LoginRedirectUrl {
get {
return "/Auth/Login?redirect={0}";
}
}
}

I've updated the ServiceStack.Mvc NuGet package that resolved a null reference exception in (v3.9.18+). Try updating and see if that resolves it.

Related

ObjectDisposedException on DbContext

I am getting the following error when using DbContext injected into a service from another service:
ObjectDisposedException: Cannot access a disposed object.
The lifetime of my DbContext is Scoped and the lifetimes of my services is Transient, but changing these other than to Singleton (which we don't want) does not solve the issue.
Interestingly, the error occurs seemingly at random. Sometimes there are no errors and everything runs fine.
In relation to this error, I am (also randomly) getting a InvalidOperationException right after startup, when my Angular app starts firing requests to the backend.
"An attempt was made to use the context while it is being configured. A DbContext instance cannot be used inside OnConfiguring since it is still being configured at this point."
My code:
public class MyService1 {
private static IMyService2 _myService2;
public MyService1(IMyService2 myService2){
_myService2 = myService2;
}
public async Task DoSomethingWithMyService2() {
await _myService2.DoSomething(new MyEntity());
}
}
public class MyService2 : IMyService2 {
private MyDbContext _dbContext;
public MyService2(MyDbContext myDbContext) {
_dbContext = myDbContext;
}
public async Task DoSomething(MyEntity myEntity) {
await _dbContext.MySet.AddAsync(myEntity); // <-- ObjectDisposedException
await _dbContext.SaveChangesAsync();
}
}
To answer my own question: the culprit is that MyService2 is stored in a static field after injection into MyService1.
Because the lifetime of DbContext is Scoped, it will be disposed after an initial request to the service. However, the service will live on during the lifetime of the entire app, with a reference to its disposed DbContext.
(I am not entirely sure about the latter (regarding lifetime of the app), because MyService1 itself is also Transient. Perhaps someone else can explain how that works.)

"No database provider has been configured for this DbContext"

I'm getting this error message when trying to reach my ASP .NET Core 3.1 Web API with Postman:
InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the DbContext.OnConfiguring method or by using AddDbContext on the application service provider. If AddDbContext is used, then also ensure that your DbContext type accepts a DbContextOptions object in its constructor and passes it to the base constructor for DbContext.
However, I do have configured it using AddDbContext in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
..
string connectionString = Configuration.GetConnectionString("ViewQlikDatabase");
services.AddDbContext<QlikDbContext>(options => options.UseSqlServer(connectionString));
}
I have checked the connection string and it is correctly retrieved.
The DbContext also has the recommended constructor:
public QlikDbContext(DbContextOptions<QlikDbContext> options)
: base(options)
{
}
The exception is raised when I try to call the context in my business class:
public string SedeGetTotaleElementiVista()
{
using (var db = new QlikDbContext())
{
// Exception raised here
int count = db.ViewQlikSede.Count();
return count.ToString();
}
}
Can someone please tell me what's wrong?
The context must be injected. If you new it up yourself, the service registration doesn't come into play at all. Here, you're creating it yourself, and not passing anything into it, so this instance definitely doesn't have a provider configured.

ASP.NET Core Identity - Extending Password Hasher

I'm working towards moving an application from Web Forms to MVC and opted to go with MVC 6 using ASP.NET Core.
In my current application I have a custom password hasher used with Identity. The implementation is very simple in my custom UserManager class:
public ApplicationUserManager()
: base(new UserStore<IdentityUser>(new AuthContext()))
{
this.PasswordHasher = new SqlPasswordHasher();
}
I'm trying to do the same with .NET Core but the PasswordHasher property doesn't exist in UserManager. I see that the constructor will take an IPasswordHasher parameter so I tried this:
public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IServiceProvider serviceProvider, ILogger<UserManager<ApplicationUser>> logger)
: base(store, optionsAccessor, new SqlPasswordHasher(), userValidators, passwordValidators, keyNormalizer, errors,
serviceProvider, logger)
{
}
In SqlPasswordHasher I'm simply overriding the VerifyHashedPassword method which looks like this:
public override PasswordVerificationResult VerifyHashedPassword(ApplicationUser user, string hashedPassword, string providedPassword)
{
// My custom logic is here
...
}
However, the above doesn't work. I have a breakpoint set in the VerifyHashedPassword method of SqlPasswordHasher and it doesn't get triggered.
I thought I was going about this the wrong way and I should be utilizing DI to accomplish this. I updated the constructor of my user manager so that it doesn't instantiate a new SqlPasswordHasher, but uses the default interface parameter instead:
public ApplicationUserManager(IUserStore<ApplicationUser> store, IOptions<IdentityOptions> optionsAccessor,
IPasswordHasher<ApplicationUser> passwordHasher, IEnumerable<IUserValidator<ApplicationUser>> userValidators,
IEnumerable<IPasswordValidator<ApplicationUser>> passwordValidators, ILookupNormalizer keyNormalizer,
IdentityErrorDescriber errors, IServiceProvider serviceProvider, ILogger<UserManager<ApplicationUser>> logger)
: base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors,
serviceProvider, logger)
{
}
Then in Startup.cs I added a scoped service:
services.AddScoped<IPasswordHasher<ApplicationUser>, SqlPasswordHasher>();
But again, this doesn't work and the breakpoint in SqlPasswordHasher is never triggered.
I have a similar line for my custom Sign In Manager:
services.AddScoped<SignInManager<ApplicationUser>, ApplicationSignInManager>();
That works great. The ApplicationSignInManager takes a UserManager parameter and I can see that the UserManager takes an IPasswordHasher parameter.
I'm assuming SignInManager uses the UserManager which uses the PasswordHasher. So my question is, how do I get the UserManager to use my custom Password Hasher? Or if thats not the case, how do I get the SignInManager to use my Password hasher?
EDIT: I've been able to confirm that when my ApplicationUserManager is instantiated, my SqlPasswordHasher is being used in the constructor so the DI is working properly. I just can't figure out why my override of VerifyHashedPassword is not being triggered.
It turns out the problem was not related to code at all. Adding my SqlPasswordHasher to the services via
services.AddScoped<IPasswordHasher<ApplicationUser>, SqlPasswordHasher>();
worked perfectly.
The problem was with how I migrated the data. Since I was using an existing database that was being used with an older version of Identity, I had to add the following fields to my existing AspNetUsers table:
NormalizedUserName
ConcurrencyStamp
LockoutEnd
NormalizedEmail
However I didn't populate the NormalizedUserName or NormalizedEmail fields. So that's why it was never triggering my override of VerifyHashedPassword; because it never found my user since it was looking up based on NormalizedUserName.
Once I populated those fields it started triggering my VerifyHashedPassword method.

Windsor Dependencies injection in mvc 4 rc into parametereized apicontroller

So, i used Mark Seemann's example to do dependency injection with Windsor in MVC 4 RC Web Api, but i get an exception saying that it can't resolve the dependencies to my ApiController
public class StatisticsController : ApiController
{
private readonly ILogger _logger;
private readonly IClickMessageProducer _producer;
public StatisticsController(ILogger logger,
IClickMessageProducer clickMsgProducer)
{
_logger = logger;
_producer = clickMsgProducer;
}
public string Get(string msg, string con) {...}
}
My Global.asax looks like this:
protected void Application_Start()
{
// different configs removed for brevity
BootstrapContainer();
}
private static IWindsorContainer _container;
private static void BootstrapContainer()
{
_container = new WindsorContainer()
.Install(FromAssembly.This(), new ProducerInstaller())
.Install(FromAssembly.This(), new WebWindsorInstaller());
GlobalConfiguration.Configuration.Services.Replace(
typeof(IHttpControllerActivator),
new WindsorHttpControllerActivator(_container));
}
The Installers gives Windsor the references needed to IClickMessageProducer. I have it working with IController in a genuine MVC 4 project so i'm confident that part is working.
To specify, this is the error message i get, when trying to access a method in StatisticsController with a GET call to the API:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Can't create component 'APIMVC.Controllers.StatisticsController'
as it has dependencies to be satisfied.
'APIMVC.Controllers.StatisticsController' is waiting for the following
dependencies: - Service 'Castle.Core.Logging.ILogger' which was not registered.
</ExceptionMessage>
<ExceptionType>Castle.MicroKernel.Handlers.HandlerException</ExceptionType>
<StackTrace>...</StackTrace>
</Error>
The call being something like this:
"http://localhost:60000/api/statistics?msg=apitest&con=apimvc"
If anyone has a working example or just a comment to the problem about my Windsor implementation i'll be happy to see it.
Your ILogger implementation isn't registered with Windsor. Remove the ILogger parameter from StatisticsController and try again. If it works, you're going to need to register an ILogger implementation.
_container = new WindsorContainer().Install(FromAssembly.This(), new ProducerInstaller()).Install(FromAssembly.This(), new WebWindsorInstaller());
this was the part at fault. As you can see I call Install(FromAssembly.This()) twice witch caused the LoggerInstaller to try to add a LoggingFacilitytwice causing an error.
The new implementation would look like this:
_container = new WindsorContainer().Install(FromAssembly.This(), new ProducerInstaller(), new WebWindsorInstaller());

SimpleInjector: Injection does not work with MVC 4 ASP.NET Web API

I have this setup:
public static void Initialize(ISessionFactory factory)
{
var container = new Container();
InitializeContainer(container, factory);
container.RegisterMvcControllers(
Assembly.GetExecutingAssembly());
container.RegisterMvcAttributeFilterProvider();
container.Verify();
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
}
private static void InitializeContainer(
Container container, ISessionFactory factory)
{
container.RegisterPerWebRequest<ISession>(
() => factory.OpenSession(), true);
}
The Initialize method is called in Application_Start:
public class WebApiApplication : HttpApplication
{
protected void Application_Start()
{
SimpleInjectorInitializer.Initialize(
new NHibernateHelper(
Assembly.GetCallingAssembly(),
this.Server.MapPath("/"))
.SessionFactory);
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
But when i try to call the controller action I get an ArgumentException:
Type 'PositionReportApi.Controllers.PositionsController' does not have
a default constructor
Stack trace:
at System.Linq.Expressions.Expression.New(Type type) at
System.Web.Http.Internal.TypeActivator.Create[TBase](Type
instanceType) at
System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage
request, HttpControllerDescriptor controllerDescriptor, Type
controllerType)
I can't register an ISession.
How do i register an ISession that is created by a factory?
From the stack trace I can see that you are using the new .NET 4.5 ASP.NET Web API and Simple Injector is not in the presented call graph. This probably means that you haven't configured the Simple Injector for use with the new Web API, which is a different registration than what you need for MVC (for some strange reason, and I sincerely hope they fix this in the final release). Since you didn't register a Simple Injector specific System.Web.Http.Dependencies.IDependencyResolver implementation to the Web API's GlobalConfiguration.Configuration.DependencyResolver, you'll get the default behavior, which will only work with default constructors.
Take a look at this Stackoverflow answer Does Simple Injector supports MVC 4 ASP.NET Web API? to see how to configure Simple Injector with the new ASP.NET Web API.
UPDATE
Note that you can get this exception even if you configured the DependencyResolver correctly, but when you didn't register register your Web API Controllers explicitly. This is caused by the way Web API is designed.
Always register your Controllers explicitly.