I'm using latest Stripe.net version
await SubscriptionsFacade.SubscribeUserAsync(user, planId, taxPercent: taxPercent);
raises
[MissingMethodException: Method not found: 'Void Stripe.StripeCustomerCreateOptions.set_Card(Stripe.StripeCreditCardOptions)'.]
Has something changed? I updated to the latest version and now my Stripe.net app is broken. Did Stripe introduce a new way of creating cards?
Here's the full code:
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var userIP = GeoLocation.GetUserIP(Request).Split(':').First();
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
RegistrationDate = DateTime.UtcNow,
LastLoginTime = DateTime.UtcNow,
IPAddress = userIP,
IPAddressCountry = GeoLocationHelper.GetCountryFromIP(userIP),
BillingAddress = new BillingAddress()
};
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// Create Stripe user
var taxPercent = user.IPAddressCountry != null && EuropeanVat.Countries.ContainsKey(user.IPAddressCountry) ?
EuropeanVat.Countries[user.IPAddressCountry] : 0;
// if no plan set, default to professional
var planId = string.IsNullOrEmpty(model.SubscriptionPlan)
? "starter"
: model.SubscriptionPlan;
var customer = new StripeCustomerService();
var customerInfo = customer.Get(user.CustomerIdentifier);
await SubscriptionsFacade.SubscribeUserAsync(user, planId, taxPercent: taxPercent);
await UserManager.UpdateAsync(user);
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
await UserManager.EmailService.SendWelcomeEmail(user.UserName, user.Email);
TempData["flash"] = new FlashSuccessViewModel("Congratulations! Your account has been created.");
return RedirectToAction("Index", "Notes");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
and SubscribeUserAsync:
https://github.com/pedropaf/saas-ecom/blob/1370ac169807e97ffb7414610d5be4de4a3cc9ae/SaasEcom.Core/Infrastructure/Facades/SubscriptionsFacade.cs
as far as I can tell SubscribeUserAsync is requiring a card with its call.
private async Task<Subscription> SubscribeUserAsync
(SaasEcomUser user, string planId, CreditCard creditCard, int trialInDays = 0, decimal taxPercent = 0)
or
public async Task<Subscription> SubscribeUserAsync
(SaasEcomUser user, string planId, decimal taxPercent = 0, CreditCard creditCard = null)
since you are subscribing a user it probably wants a credit card to go with it. I would add either a card via creating a token or via calling and existing one with
var customer = new StripeCustomerService();
var customerInfo = customer.Get(user.CustomerIdentifier);
//then store card with customerInfo.DefaultSourceId somewhere and use it
Related
Not able to insert the user object in UserRegister method of Account repository as I am using dependency injection. Please refers the attached images for your better understanding.
Error Image: Please see it.
Main Code Image: Please refer it.
Dependency Injection Image: Please refer it
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
User _userObj = new User();
_userObj.Id = user.Id;
_userObj.Email = user.Email;
_userObj.EmailConfirmed = user.EmailConfirmed;
_userObj.PasswordHash = user.PasswordHash;
_userObj.SecurityStamp = user.SecurityStamp;
_userObj.PhoneNumber = user.PhoneNumber;
_userObj.PhoneNumberConfirmed = user.PhoneNumberConfirmed;
_userObj.TwoFactorEnabled = user.TwoFactorEnabled;
_userObj.LockoutEndDateUtc = user.LockoutEndDateUtc;
_userObj.LockoutEnabled = user.LockoutEnabled;
_userObj.AccessFailedCount = user.AccessFailedCount;
_userObj.UserName = user.UserName;
_accountObj.UserRegister(_userObj);//𝗼𝗯𝗷𝗲𝗰𝘁 𝗿𝗲𝗳𝗲𝗿𝗲𝗻𝗰𝗲 𝗻𝗼𝘁 𝘀𝗲𝘁 𝘁𝗼 𝗮𝗻 𝗶𝗻𝘀𝘁𝗮𝗻𝗰𝗲 𝗼𝗳 𝗮𝗻 𝗼𝗯𝗷𝗲𝗰𝘁.'_𝗮𝗰𝗰𝗼𝘂𝗻𝘁𝗼𝗯𝗷 𝘄𝗮𝘀 𝗻𝘂𝗹𝗹'.
await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
I want to make an email confirmation callback link from asp.net core web API repository class,
This is easy when done in the controller of the API, but I am having trouble doing this from the repository class.
I keep getting this error:
Could not find an IRouter associated with the ActionContext. If your application is using endpoint routing then you can get a IUrlHelperFactory with dependency injection and use it to create a UrlHelper, or use Microsoft.AspNetCore.Routing.LinkGenerator.
this is what I have so far:
this is my repository code for registration:
public async Task<(bool IsSuccess, string ErrorMessage)> Register(RegisterDTO model)
{
if (model != null)
{
var user = _mapper.Map<ApplicationUser>(model);
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _userManager.AddToRoleAsync(user, "Admin");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
string _scheme = _urlHelper.ActionContext.HttpContext.Request.Scheme;
//var callbackurl = _urlHelper.Link("ConfirmEmail", new { email =
user.Email, code = code });
var callbackurl =
_urlHelper.Action("ConfirmEmail",nameof(AccountController), new { email = user.Email, code = code }, _scheme);
var mailresult = _mailSender.SendEmail(model.Email, "Please confirm your
account by clicking here: link");
return (true, "Account created successfully");
}
return (false, "Eror occured while creating your account");
}
return (false, "Please provide the user data");
}
Account Controller
[HttpGet("{token}/{email}")]
public async Task<IActionResult> ConfirmEmail(string token, string email)
{
var result = await _repository.ConfirmEmail(token, email);
if (result.IsSuccess)
return Ok(result.ErrorMessage);
else
return BadRequest(result.ErrorMessage);
}
I managed to get it to work.
see the code below:
enter code here
public async Task<(bool IsSuccess, string ErrorMessage)>
Register(RegisterDTO model)
{
if (model != null)
{
var user = _mapper.Map<ApplicationUser>(model);
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _userManager.AddToRoleAsync(user, "Admin");
var _urlHelper = _urlHelperFactory.GetUrlHelper(
_actionContextAccessor.ActionContext);
var code = await _userManager.
GenerateEmailConfirmationTokenAsync(user);
string _scheme = _urlHelper.ActionContext.
HttpContext.Request.Scheme;
var callbackurl = _urlHelper.Action(action:
nameof(AccountController.ConfirmEmail),
controller: "Account", values:
new { email = user.Email, code = code },
protocol: _scheme);
var mailresult = _mailSender.SendEmail(model.Email, "Please
confirm your account by clicking here: <a href=\"" +
callbackurl + "\">link</a>");
if (mailresult.IsSuccess)
{
return (true, "Account created successfully, Please visit
your email to confirm your email");
}
else
{
return (true, $"Account created successfully,
{mailresult.ErrorMessage}");
}
}
return (false, result.Errors.ToString());
}
return (false, "Please provide the user data");
}
This API is intended for a mobile application. The goal is to let the user confirm the email upon registration. When the user registers, a confirmation link is generated and sent over the email. I've done it the same way in a MVC project, it worked fine, but in a Web API project looks like it ain't gonna cut.
Now when the user clicks that link, the respective action method should be hit and do the job.
The only problem is, the ConfirmEmail action method is just not getting triggered when clicking the confirmation link although it looked fine.
Here are the main configurations which might help
MVC service configuration
services.AddMvc(options =>
{
options.EnableEndpointRouting = true;
options.Filters.Add<ValidationFilter>();
})
.AddFluentValidation(mvcConfiguration => mvcConfiguration.RegisterValidatorsFromAssemblyContaining<Startup>())
.SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_3_0);
Identity Service
public async Task<AuthenticationResult> RegisterAsync(string email, string password)
{
var existingUser = await _userManager.FindByEmailAsync(email);
if(existingUser != null)
{
return new AuthenticationResult { Errors = new[] { "User with this email address exists" } };
}
// generate user
var newUser = new AppUser
{
Email = email,
UserName = email
};
// register user in system
var result = await _userManager.CreateAsync(newUser, password);
if (!result.Succeeded)
{
return new AuthenticationResult
{
Errors = result.Errors.Select(x => x.Description)
};
}
// when registering user, assign him user role, also need to be added in the JWT!!!
await _userManager.AddToRoleAsync(newUser, "User");
// force user to confirm email, generate token
var token = await _userManager.GenerateEmailConfirmationTokenAsync(newUser);
// generate url
var confirmationLink = _urlHelper.Action("ConfirmEmail", "IdentityController",
new { userId = newUser.Id, token = token }, _httpRequest.HttpContext.Request.Scheme);
// send it per email
var mailresult =
await _emailService.SendEmail(newUser.Email, "BingoApp Email Confirmation",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(confirmationLink)}'>clicking here</a>.");
if (mailresult)
return new AuthenticationResult { Success = true };
else
return new AuthenticationResult { Success = false, Errors = new List<string> { "Invalid Email Address"} };
}
Controller
[HttpPost(ApiRoutes.Identity.Register)]
public async Task<IActionResult> Register([FromBody] UserRegistrationRequest request)
{
if (!ModelState.IsValid)
{
return BadRequest(new AuthFailedResponse
{
Errors = ModelState.Values.SelectMany(x => x.Errors.Select(xx => xx.ErrorMessage))
});
}
// register the incoming user data with identity service
var authResponse = await _identityService.RegisterAsync(request.Email, request.Password);
if (!authResponse.Success)
{
return BadRequest(new AuthFailedResponse
{
Errors = authResponse.Errors
});
}
// confirm registration
return Ok();
}
[HttpGet]
public async Task<IActionResult> ConfirmEmail(string userId, string token)
{
if (userId == null || token == null)
{
return null;
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return null;
}
var result = await _userManager.ConfirmEmailAsync(user, token);
if (result.Succeeded)
{
await _emailService.SendEmail(user.Email, "BingoApp - Successfully Registered", "Congratulations,\n You have successfully activated your account!\n " +
"Welcome to the dark side.");
}
return null;
}
Your _urlHelper.Action(..) looks a bit suspicious to me.
I'm not sure you should pass the full controller name, that is, including the actual word controller.
Try _urlHelper.Action("ConfirmEmail", "Identity", instead.
As a tip: I try to avoid magic strings like these by using nameof(IdentityController) because it will return the controller name without the controller postfix.
I use asp net core Identity. This is what I am trying to do and I have no Idea how to do this so need some expert help on this. When a new user registers in my application , a password reset link is sent to the person's email, Now when the link token in the link has expired and the user clicks on the link I need to show a message as token expired. How do I find out If the token has expired or not when the user clicks on the link which is in the email. Can any one suggest ways to achieve this scenario?
The ASP.NET Core has a built-in Claims system to store information about the user .
To do that ,
add a helper method to store the expiration datetime in Register.cshtml.cs:
private async Task AddTokenExpirationInfo(IdentityUser user, int span=1*24*60)
{
var expiresAt = DateTime.Now.Add(TimeSpan.FromMinutes(span));
var tokenExpiredAtClaim = new Claim("ActivtationTokenExpiredAt", expiresAt.ToUniversalTime().Ticks.ToString());
await _userManager.AddClaimAsync(user, tokenExpiredAtClaim);
}
add a helper method to check whether the token has expired in the ConfirmEmail.cshtml.cs :
private async Task<bool> TokenExpiredValidate(IdentityUser user) {
var claims = (await _userManager.GetClaimsAsync(user))
.Where(c => c.Type == "ActivtationTokenExpiredAt");
var expiredAt = claims.FirstOrDefault()?.Value;
bool expired = true; // default value
if (expiredAt != null)
{
var expires = Convert.ToInt64(expiredAt);
var now = DateTime.Now.Ticks;
expired= now <= expires? false : true;
}
else {
expired = false;
}
// clear claims
await _userManager.RemoveClaimsAsync(user, claims);
return expired;
}
invoke AddTokenExpirationInfo when there's a registeration request :
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { userId = user.Id, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
///////////////// invoke here ////////////////////
AddTokenExpirationInfo(user);
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
invoke TokenExpiredValidate in your ConfirmEmail.cshtml.cs:
public async Task<IActionResult> OnGetAsync(string userId, string code)
{
if (userId == null || code == null)
{
return RedirectToPage("/Index");
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return NotFound($"Unable to load user with ID '{userId}'.");
}
var result = await _userManager.ConfirmEmailAsync(user, code);
if (!result.Succeeded)
{
throw new InvalidOperationException($"Error confirming email for user with ID '{userId}':");
}
if (await TokenExpiredValidate(user))
throw new InvalidOperationException($"Token has alread expired '{userId}':");
return Page();
}
When a user registers , there' will be a record in the AspNetUserClaims table :
When a user confirmed successfully , the record will be removed . Just as a reminder , a more robust method is to use a background service to clear the expired record .
Hello I have the problem
when I try to call a function GetDataById method controller doesn't work
I try to debug but after calling method GetDataById I can't go any further
[HttpPost]
public async Task<ActionResult> CreateEmployee(RegisterModel model)
{
var d = new DistrictService();
var r = new RegionService();
var region = r.GetDataById(model.RegionId);
var district = d.GetDataById(model.DistrictId);
var user = new User
{
UserName = model.Email,
FullName = model.FullName,
Email = model.Email,
District = district,
Region = null,
Address = model.Address
};
var result = await userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
var resOfAddRoleToUser = userManager.AddToRole(user.Id, model.Role);
await SignIn(user);
}
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
but program enter in GetDataById method