Add role to AspNetUserRoles - asp.net-mvc

Well im kind wasting too much time trying to accomplish this objective and im kinda frustrated, what i want to do is something like that:
**table aspNetUserRoles
userId
roleId
table aspNetRole
roleId
RoleName**
i already did the first part i already filled the aspNetUserRoles with the seed method and have some roles in my database, and i already created a dropdownlist with all my roles, but i have a problem when i press Register i get a error : "UserId not found" i will show here what i alrady did and will place my 2 tables
what i did
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, Sobre = model.Sobre, Idade = model.Idade, Telemóvel = model.Telemóvel, Nome = model.Nome };
var result = await UserManager.CreateAsync(user, model.Password);
var roleStore = new RoleStore<IdentityRole>(db);
var roleManager = new RoleManager<IdentityRole>(roleStore);
var userStore = new UserStore<ApplicationUser>(db);
var userManager = new UserManager<ApplicationUser>(userStore);
userManager.AddToRole(user.Id, "Name");
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
if someone can me explain what i am doing wrong i appreciate a lot :)

use Like this
if (result.Succeeded)
{
userManager.AddToRole(user.Id, "Name");
}

Related

Pass Query String Into Register Form

I'm going to have a subscription flow as follows:
User goes to pricing page, chooses plan, is redirected to ../Register?planId=1
User registers with username and password, is forwarded to billing page, which needs to be ../Subscription/Billing?planId=1
I added an integer, planId, to my RegisterViewModel
On pricing page, I have the links working correctly.
For register controller, I have:
[AllowAnonymous]
public ActionResult Register(RegisterViewModel model, int planId)
{
if (Request.IsAuthenticated) {
return RedirectToAction("Pricing", "Home");
}
RegisterViewModel model1 = new RegisterViewModel();
model1.planId = Convert.ToInt32(Request.QueryString["planId"]);
return View(model1);
}
And in Register view I have:
#Html.HiddenFor(m => m.planId)
However, this value is blank everytime I've run the application. If I can get the planId to be included as part of the register form submission, then I think I can redirect the controller to "../Subscription/Billing?planId=1" after registration.
Here's the current register post controller, where I think I just need to add the planid to the redirectToAction:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email, Role = "Admin", ReportsTo = "", ActiveUntil = DateTime.Now.AddDays(-1) };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
return RedirectToAction("Pricing", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
My question is, how do I get the planid to pass from the query string to a hidden field in the login form?
You can try model1.planId = planId

return view stopped working

I've modified the mvc5 registration to allow the user to upload a profile image. Everything works fine, the file gets uploaded, the database get properly populated, and the email confirmation email gets sent.
The problem is that since adding the file handling code, the return view("info") no longer does anything, the registration page just refreshes instead. I've stepped through the code, and it's still hitting return view("info") without any problems. Anybody know the cause/solution? I was wondering if it was something to do with the register action being a async?
Here's the code:
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var userD = new UserDetails();
userD.Name = model.Name;
Regex rgx = new Regex("[^a-zA-Z0-9]");
string UserFolder = rgx.Replace(model.Email + DateTime.Now, "");
userD.UserRootFolder = UserFolder;
//create root folder
string RootPath = #"~/UserFiles/" + UserFolder + "/";
//check it doesnt already exist
if (!Directory.Exists(Server.MapPath(RootPath)))
{
//create the directory
DirectoryInfo di = Directory.CreateDirectory(Server.MapPath(RootPath));
if(!di.Exists)
{
//if the folder still doesnt exist return to view as something went wrong
//return View(model);
}
userD.UserRootFolder = RootPath;
}
HttpPostedFileBase TheFile = model.file;
if (TheFile != null)
{
string path = Server.MapPath(RootPath + model.file.FileName);
model.file.SaveAs(path);
userD.UserPictureLocation = path;
model.file.InputStream.Close();
}
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
PaypalEmail=model.PaypalEmail,
UserDetails = userD
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
code = System.Web.HttpUtility.UrlEncode(code);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking here");
ViewBag.Message = "Check your email and confirm your account, you must be confirmed "
+ "before you can log in.";
return View("info");
// return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
Do you know if debugging and waiting the email be sent you can render your screen?
A: If it's Yes, I think it's better you register this CONFIRMATION EMAIL in the DB and them make another call to send ALL CONFIRMATION EMAIL that hasn't been sent.
By the way, could you share the code of your View Info and the path?
I've fixed it. I've no idea why, but saving the image after the email gets sent got it working again.
If anyone knows why, then i'd love to know.

Have different version of SendEmailAsync

I am using the default ASP.NET MVC, Identity template... I want to send a confirmation email to my clients.
The default implementation which comes with a new project template, has a Register Method in AccountController.cs
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email.Trim(), Email = model.Email.Trim(), FirstName = model.FirstName.Trim(), LastName = model.LastName.Trim() };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
string message = "Please confirm your account by clicking here";
await UserManager.SendEmailAsync(user.Id, "Confirm your account", HttpUtility.UrlEncode(message));
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
There is a call to UserManager.SendEmailAsync, now this method is defined in Microsoft.AspNet.Identity and I don't want to change it.
The actual send email function is in IdentityConfig.cs
public class SendGridEmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
var apiKey = ConfigurationManager.AppSettings["SendGridApiKey"];
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("info#mycompany.com", "DX Team"),
Subject = message.Subject,
PlainTextContent = message.Body,
HtmlContent = message.Body
};
msg.TemplateId = /* I want to pass templateId here */
msg.Personalizations[0].Substitutions.Add("confirmurl", /* I want to pass Username here */);
msg.Personalizations[0].Substitutions.Add("confirmurl", /* I want to pass confirm url here */);
msg.AddTo(new EmailAddress("info#mycompant.com", "Test User"));
var response = await client.SendEmailAsync(msg);
}
}
Now as you see, I am using Sendgrid to send email... so I don't want a message.body to email... I have made some templates and I I want to pass teplate Id with some substituation tags, like username to be replaced in the template.
So I don't want this generic SendAsync method... I want something like
SendGridAsync(SendGridMessage message)
Is it possible to add this method, so I can choose when to call SendAsync and when to call SendGridAsync?
You don't need to use the built in mail service, especially when you want to do something that's a little more complicated.
Define your own messaging service:
public interface IMyMessageService
{
Task SendConfirmationMessage(string confirmUrl, string to)
// define methods for other message types that you want to send
}
public class MyMessageServie : IMyMessageService
{
public async Task SendConfirmationMessage(string confirmUrl, string to)
{
var apiKey = ConfigurationManager.AppSettings["SendGridApiKey"];
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("info#mycompany.com", "DX Team"),
Subject = message.Subject,
PlainTextContent = message.Body,
HtmlContent = message.Body
};
msg.TemplateId = /* I want to pass templateId here */
msg.Personalizations[0].Substitutions.Add("confirmurl", confirmUrl);
msg.AddTo(new EmailAddress(to, "Test User"));
var response = await client.SendEmailAsync(msg);
}
}
Register IMyMessageService in your DI framework, and inject it into the controller where the emails are being sent from (e.g. the AccountController).
Now, your register action would look like this (assumes I've injected IMyMessageService and have an instance in _myMessageService):
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email.Trim(), Email = model.Email.Trim(), FirstName = model.FirstName.Trim(), LastName = model.LastName.Trim() };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// USE YOUR MESSAGE SERVICE
await _myMessageService.SendConfirmationMessage(callbackUrl, user.Email);
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}

Add Primary Key of Linked Table to ASPNETUsers table Id field

I have successfully linked aspnetusers table to my custom users table as one-to-one relationship. Now when i go to register all information is successfully added to both tables except one thing - Id.
My pk userId in users table is an AutoIncrement key and i wish to add the same value in the id field of aspnetUsers table. I think i will have to override createAsync or do i remove from SignInAsync
await user.GenerateUserIdentityAsync(UserManager)
Inside AccountController Register method, I have
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var geUser = new User { Password = model.Password, Username = model.Email, AccessLevel = "0003", LoggedIn = false, Active = true, AllowOffline = false, LastSettingsRefreshed = DateTime.Now };
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email, user = geUser};
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
return View(model);
}
My Data Tables:
ASPNetUSers and Users respectively:
I want to enter 43 instead of 0 in aspnetusers table
UPDATE
On research i see that it has something to do with DatabaseGeneratedOption but exactly what and on which table should i do "DatabaseGeneratedOption.None"?

Control not hitting SendAsync function of Custom EmailService : MVC Email confirmation

I have created a new MVC Project in Visual Studio 2013. I noticed that the IdentityConfig.cs file was missing. I have heard that Microsoft removed it from newer versions of ASP.NET Identity. This file, when present, used to define the EmailService class.
So I implement my own EmailService class. The code looks like this
//EmailService.cs
public class EmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
await configGMailAsync(message);
}
private static async Task configGMailAsync(IdentityMessage message)
{
//mailing code
}
}
In my AccountController, I have the following Register method, which makes a call to UserManager.SendEmailAsync() method.
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
var provider = new DpapiDataProtectionProvider("myAppName");
UserManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("EmailConfirmation"));
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account",
new { userId = user.Id, code = code },
protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id,
"Confirm your account", "Please confirm your account by clicking <a href=\""
+ callbackUrl + "\">here</a>");
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
However, after the call to UserManager.SendEmailAsync(), the control (debugger) never hits the SendAsync() function of EmailService class.
I have another project where the IdentityConfig.cs was automatically added on project creation. There, after the call to UserManager.SendEmailAsync(), the control hits the SendAsync() function.
What am I missing here?
Turns out that you have to register your Service with the UserManager class before you send the mail. Upon adding the following line just above UserManager.SendEmailAsync(), the SendAsync() function is picked up successfully:
UserManager.EmailService = new EmailService();
Here is the full function including the newly added line
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser() { UserName = model.UserName };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, isPersistent: false);
var provider = new DpapiDataProtectionProvider("myAppName");
UserManager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(provider.Create("EmailConfirmation"));
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account",
new { userId = user.Id, code = code },
protocol: Request.Url.Scheme);
UserManager.EmailService = new EmailService();
await UserManager.SendEmailAsync(user.Id,
"Confirm your account", "Please confirm your account by clicking <a href=\""
+ callbackUrl + "\">here</a>");
return RedirectToAction("Index", "Home");
}
else
{
AddErrors(result);
}
}
// If we got this far, something failed, redisplay form
return View(model);
}
I created a new Web API 2 project with individual user accounts in VS 2017. There IdentityConfig.cs was present but it did not have an EmailService class. If this is the case and you do not wan't to write UserManager.EmailService = new EmailService(); every time you wan't to use this feature you can add it here instead.
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
manager.EmailService = new EmailService();

Resources