"User not found" Error when creating a child entity using ControllerB action, soon after an aspUser is created in controllerA - asp.net-mvc-5

After the successful creation of an application user and the following line of code (in Register action in AccountController) :
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
I am trying to add a child object
var controller=DependencyResolver.Current.GetService<AnotherController>();
controller.ControllerContext = new ControllerContext(Request.RequestContext, controller);
var res = controller.Create(
new ChildEntity
{
ApplicationUserId = user.Id,
IsAcative = true
});
my create Method looks like this
public async Task<ActionResult> Create(ChildEntity entity)
{
if (ModelState.IsValid)
{
db.ChildEntity.Add(entity);
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(entity);
}
My object is not created. the return valueres contains the error "user not found" propertyName : "ApplicationUserId"
Can anybody help me to understand what is going on?
ps : i have noticed that the User.Identity.GetUserId() return null !!! (may be fo some other reason, may be my problem is linked to this..)

First and foremost, the user principal is not populated until after the next page load. The sign-in process merely sets the auth cookie. That cookie needs to be sent back and the auth machinery needs to run (as part of the request pipeline), before you can get anything from User.
Second, what you're doing here is just absolutely wrong. If you want to reuse the user creation code, factor it out into another class that all your controllers can utilize. It's absolutely the wrong approach to try to new up a controller inside another action to call an action on that.

Related

Microsoft Bot Framework start the conversation from specific waterfall step in dialog

Microsoft Bot Framework V4, I have a waterfall Dialog defined in a dialog as below
var waterfallSteps = new WaterfallStep[]
{
CallConfirmAsync,
SimilarProductAsync,
CheckNewVersionAsync,
};
AddDialog(new WaterfallDialog("productenquiry", waterfallSteps));
After the execution of the first two waterfall steps, my conversation is stop due to unresponsiveness from user's end. So I want to resume from the third method when i.e., CheckNewVersionAsync when the user comes back again to the bot.
Can anyone please help me here.
So, at the bot level, this should happen automatically if you've configured the IStatePropertyAccessor<DialogState> with the ConversationState. No matter how long the user takes to respond, your WaterfallDialog will stay at the top of the stack and it will remember exactly what step it was on. Assuming your user comes back to the same conversation, then it will pick right up where it left off.
Given that, the fact that you are asking this question leads me to believe that perhaps you are using WebChat which doesn't maintain the same conversationId across page loads unless you set that up yourself. If that's the case, then I would suggest you ask another question about how to do that if you can't figure out how since that's a separate issue from the dialog state being persisted correctly.
Edit: Drew's answer is correct, but mine provides another potential solution. You can find more info here: Managing State. In particular:
User state is available in any turn that the bot is conversing with
that user on that channel, regardless of the conversation Conversation
state is available in any turn in a specific conversation, regardless
of user (i.e. group conversations) Private conversation state is
scoped to both the specific conversation and to that specific user
Tip
Both user and conversation state are scoped by channel. The same
person using different channels to access your bot appears as
different users, one for each channel, and each with a distinct user
state.
Additional Solution
This solution is best for if you're able to specify the from Id, but cannot ensure that conversation Id remains the same (see below, under Gotchas).
You could save what step the user is on in their UserState.
BasicBot
BasicBot does this with its GreetingState class.
From its GreetingDialog:
In the first step, it initializes the GreetingState, which tracks how far along in the dialog the user is by seeing what user variables have already been set:
private async Task<DialogTurnResult> InitializeStateStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var greetingState = await UserProfileAccessor.GetAsync(stepContext.Context, () => null);
if (greetingState == null)
{
var greetingStateOpt = stepContext.Options as GreetingState;
if (greetingStateOpt != null)
{
await UserProfileAccessor.SetAsync(stepContext.Context, greetingStateOpt);
}
else
{
await UserProfileAccessor.SetAsync(stepContext.Context, new GreetingState());
}
}
return await stepContext.NextAsync();
}
And then in each step, it loads the GreetingState:
var greetingState = await UserProfileAccessor.GetAsync(stepContext.Context);
And checks to see if the step has already been completed with something like:
if (greetingState != null && !string.IsNullOrWhiteSpace(greetingState.Name) && !string.IsNullOrWhiteSpace(greetingState.City))
If there's no greetingState or .Name or .City exists, it prompts for them, and if they are already filled out, it moves on with:
return await stepContext.NextAsync();
At each step, it saves to the GreetingState with something like:
greetingState.Name = char.ToUpper(lowerCaseName[0]) + lowerCaseName.Substring(1);
await UserProfileAccessor.SetAsync(stepContext.Context, greetingState);
Simplifying for your use case
For you, if you don't need to save user information, you could create a simple Step class:
{
/// <summary>
/// User state properties for Waterfall Step.
/// </summary>
public class Step
{
public string StepNumber { get; set; }
}
}
Make the first step of your WaterfallDialog:
private async Task<DialogTurnResult> InitializeStateStepAsync(WaterfallStepContext stepContext, CancellationToken cancellationToken)
{
var StepState = await UserProfileAccessor.GetAsync(stepContext.Context, () => null);
if (StepState == null)
{
var StepStateOpt = stepContext.Options as StepState;
if (StepStateOpt != null)
{
await UserProfileAccessor.SetAsync(stepContext.Context, StepStateOpt );
}
else
{
await UserProfileAccessor.SetAsync(stepContext.Context, new StepState());
}
}
return await stepContext.NextAsync();
}
On each step, load the current Step:
var stepState = await UserProfileAccessor.GetAsync(stepContext.Context);
Check to see if they're already past the current step:
if (stepState.StepNumber <= 2)
{
// ...do stuff
// Save that user has completed step
stepState.StepNumber++;
await UserProfileAccessor.SetAsync(stepContext.Context, stepState);
}
else
{
return await stepContext.NextAsync();
}
Gotchas
A couple big things to watch out for:
The UserState only persists for the same from ID and channel ID. Make sure that the user that leaves in the middle of a waterfall has the same from ID when they re-enter it and that they re-enter it from the same channel. This isn't the default for the Emulator--in the Emulator, when a session is restarted, a new from ID is created. (Note: Consider from ID to be synonymous with User ID. It just comes from Activity.From.Id)
The ConversationState only persists for the same conversation ID and channel ID. Persistence of the conversation ID within the channel varies by channel.
More info on the different IDs: ID fields in the Bot Framework.

Convert NodeJS asynchronous code to Spring Project Reactor

I have below NodeJS code:
// req and resp are http request, response objects
var uri = req.getURI()
var pageView = new PageView(uri)
var token = req.token
if (token) {
UserRepository.findByToken(token, function(notFound, user){
if(notFound) { // means user not found by specified token
var newUser = new User('John Doe')
user.foo = 'some value'
processUser(newUser, pageView)
} else { // user found by token
user.foo = 'some value'
processUser(user, pageView)
}
})
} else { // token does not exist
token = new Token('some value')
resp.setToken(token)
var newUser = new User('John Doe')
user.foo = 'some value'
processUser(newUser, pageView)
}
processUser(user, pageView) {
PageViewRepositiry.save(pageView, function(error, savedPageView){
if(error) {
throw 'error'
}
user.pageViews.push(savedPageView)
// save the modified savedUser
UserRepository.save(user , function(error, savedUser){
})
})
}
It uses Repository pattern as abstraction over database layer (same as the Repository pattern in Spring applications).
Basically it finds user by incoming token (from http req object). If user is found then updates user entity and adds the saved pageView entity and saves the modified user. If user is not found by token then it creates a new User, updates the user with saved pageView, saves the user.
How the same code will be written in Spring Project Reactor (Flux) ?
Is it possible to solve this problem without using block()? Ideally I would like a solution that does not use block().
First of all, you have some logic to generate a token if a token isn't present. For example:
private Mono<String> getToken(String token) {
return Mono
.just(token)
.switchIfEmpty(Mono.just("some token"));
}
In this case, it's a bit overkill to use switchIfEmpty for this, but I assume your process to generate a token is a bit more complex, otherwise you could have worked with Optional<String> in stead (eg. token.orElse("some token")).
Additionally, we also have some logic to either find the user by its token, or create a new user if there is no user by the given token:
private Mono<User> findUserByToken(String token) {
return userRepository
.findByToken(token)
.switchIfEmpty(userRepository.save(new User("John Doe", token)));
}
Now that we have these methods, we can create a PageView and use these methods along the way. The reason I start with creating a PageView is because that's the first "constant" in the entire token, regardless of whether there is a token/user found:
return Mono
.just(new PageView(uri))
.flatMap(pageViewRepository::save)
.flatMap(pageView -> getToken(token)
.flatMap(this::findUserByToken)
.doOnNext(user -> user.setFoo("foo"))
.doOnNext(user -> user.getPageView().add(pageView)))
.flatMap(userRepository::save)
.map(User::getToken);
Now, since you need the token to add to the response, and I figured out that the token is part of the User object somehow (otherwise UserRepository.findByToken() wouldn't work?), it would be easier to just use User::getToken at the end to retrieve the token to pass to the response.
Be aware though, the repository pattern does work properly with Spring, but there is only reactive support for MongoDB, Cassandra, Couchbase and Redis. Other than that there's also reactive support for PostgreSQL through rdbc, but I don't think Spring data has support for that.

Using 2FA for password reset

My application uses Asp.Net Identity and sends a Two Factor code to my Auth app on login. This is pretty standard (as there lots of examples on the net) and uses the SendCode() method. My understanding is that the 'magic' is done by this line:
// Generate the token and send it
if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider))
{
View("Error");
}
My requirement is to ensure the user goes through the same process of 2FA when they want to change their password after they have logged in.
My issue is that when the code to send the 2FA code is executed:
if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider))
{
View("Error");
}
I receive the error 'UserID not found':
Server Error in '/MSPortal' Application.
UserId not found.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: UserId not found.
Source Error:
Line 555:
Line 556: // Generate the token and send it
Line 557: if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider))
Line 558: {
Line 559: return View("Error");
I know SendTwoFactorCodeAsync() calls GetVerifiedUserIdAsync() but my understanding is that the user is verified now that I have already logged in using 2FA.
Does anyone know why I would be getting this error?
Thanks.
I've worked around this by overriding SendTwoFactorCodeAsync() in IdentityConfig.cs. In this override, I first call GetVerifiedUserIdAsync() as per usual but then if that is 0 I get the User's ID from the Current HttpContext.
I am not stating this is the best way but it's what I have done thus far and its got me moving ahead in my aim of having 2FA for login, change password and forgot password.
The code (likely to go through some refactoring if I get feedback) is:
public override async Task<bool> SendTwoFactorCodeAsync(string provider)
{
int userId = 0;
try
{
userId = await GetVerifiedUserIdAsync();
if (userId == 0)
{
userId = Convert.ToInt32(HttpContext.Current.User.Identity.GetUserId());
}
if (userId == 0)
return false;
}
catch
{
return false;
}
var token = await UserManager.GenerateTwoFactorTokenAsync(userId, provider);
// See IdentityConfig.cs to plug in Email/SMS services to actually send the code
await UserManager.NotifyTwoFactorTokenAsync(userId, provider, token);
return true;
//return base.SendTwoFactorCodeAsync(provider);
}

Retrieve role in jhipster immediately after Auth.login

I want to send a user to a particular view after login based on a role that person has. For example, I want to send a user with ROLE_STUDENT to a student page, and a person with ROLE_TEACHER to a teacher page. Unfortunately, if I call isInRole in the controller immediately after Auth.login, that fails. Specifically, in the login function (which I moved to main.controller.js so that the login dialog appears on the main page), I have code like this:
$scope.login = function () {
Auth.login({
username: $scope.username,
password: $scope.password
}).then(function (account, $state) {
Principal.identity(true);
$scope.authenticationError = false;
$scope.account = account;
$scope.isAuthenticated = Principal.isAuthenticated;
$scope.isInRole = Principal.isInRole;
if ($scope.isInRole('ROLE_STUDENT')) {
$scope.state.go('student_dashboard');
}
}).catch(function () {
$scope.authenticationError = true;
});
};
However, the isInRole method always returns false. If I debug it, I can see in principal.service.js shows that at this point, _authenticated is false and _identity is undefined.
Now, if I comment out the isInRole conditional in the controller, so that the user always goes to the student_dashboard page, I can put isInRole code on the student_dashboard page itself, and it works great. So, it appears that something is happening between the time of the redirect, and the time the target page loads, and I want to know what that is so that I can cause it to happen and thus determine if a user has a particular role and then redirect appropriately.
I believe your problem is with
Principal.identity(true);
This actually returns a promise which does an ajax call to update the principal user, so to use the principal functions you will need to do something like this
Principal.identity(true).then(function(profile) {
$scope.authenticationError = false;
$scope.account = account;
$scope.isAuthenticated = Principal.isAuthenticated;
$scope.isInRole = Principal.isInRole;
if ($scope.isInRole('ROLE_STUDENT')) {
$scope.state.go('student_dashboard');
}
});
Otherwise the current identity is undefined.

NUnit & MVC4 SimpleMembership

I'm having a really difficult time creating unit tests for my MVC4 application, using NUnit. Right now I'm just focusing on this one test in particular, which logs a user in OR creates them if they don't exist, and then logs them in. Here is the test :
[Test]
public void LoginValidUser()
{
//Start up the DB connection
App_Start_DB();
//Setup our default test user
string UserName = "LocalTestUser#penrouse.com";
string Password = "books";
bool LoginWorked = false;
//check and see if our test user exists
if (!WebSecurity.UserExists(UserName))
{
//If not, create them
WebSecurity.CreateUserAndAccount(UserName, Password, new
{
Name = "Local Test User",
IsPromotional = true,
IsAllowShare = true
});
//Log them in
LoginWorked = WebSecurity.Login(UserName, Password);
}
else
{
//This user already exists, just log them in
LoginWorked = WebSecurity.Login(UserName, Password);
}
Assert.IsTrue(LoginWorked);
Trace.WriteLine("Login Valid User Result : " + LoginWorked.ToString());
}
The problem is that every time I attempt WebSecurity.Login(), I get a null reference exception, and the stack trace points to :
System.Web.Security.FormsAuthentication.SetAuthCookie(String userName, Boolean createPersistentCookie, String strCookiePath);
Calling that method directly before the login attempt the does not change the behavior. Thus, I have two questions :
Is there a better way to go about testing these parts of SimpleMembership?
If not, is there a good way to override or mock out the AuthCookie so that the login will work when tested in this way?
Any help\insight would be hugely appreciated.

Resources