<cite>ismcagdas: </cite> Hi,
ABP actually calls CheckModelState before calling the action method of controller by default. You can add [DisableValidation] attribute to your controller or action method, if you want to do validation manually.
You can also disable validation for all MVC controllers like this in PreInitialize of your web module.
Configuration.Modules.AbpMvc().IsValidationEnabledForControllers = false;
Thank you, that's good to know.
<cite>hikalkan: </cite> Hi @difuzzy,
What do you mean by clients of Web API? Browsers, mobile apps.. which calls Web API services remotely. If so, no problem, token provider will be valid since it's assigned in Web/WebApi layer, in Startup class: <a class="postlink" href="https://github.com/aspnetzero/aspnet-zero/blob/dev/src/MyCompanyName.AbpZeroTemplate.Web/App_Start/Startup.cs#L43">https://github.com/aspnetzero/aspnet-ze ... tup.cs#L43</a>
Beside that, if you worry about "good layering", you're right. Because, if you develop a Desktop application and want to use application layer (and don't use web/webapi layer), then tokenprovider will not be defined and you will get exception if you generate password reset token using UserManager.GeneratePasswordResetTokenAsync. That means, a functionality in application layer, indirectly depends on the web layer and it has not a built-in fallback mechanism (to allow work without web layer).
Why we did it like that? Because this is the most common way of getting a valid data protection validator, OWIN provides it to us. We haven't searched for another solution.
So, it's actually not a problem for you, but if you care about it, please create an issue here and we search for a better way: <a class="postlink" href="https://github.com/aspnetboilerplate/module-zero/issues/new">https://github.com/aspnetboilerplate/mo ... issues/new</a>
Thanks a lot.
No that all makes sense. You're right, I should be able to generate a token in WebAPI. I should be good to go. Thanks!
<cite>ismcagdas: </cite> @djfuzzy, I think you can gneerate tokens in the application layer, because you can use UserManager in application layer. But you need to set userManager's UserTokenProvider in web layer (probably in your web module).
How would this work for clients of the Web API? It sounds like having the Application layer being dependent on the Web layer defies the SOLID principles of programming. I don't want to have each client having to generate the token.
Is it possible to have this logic in the Application layer? I would much rather have the email confirmation tokens being generated there then having clients do it.
OK, I got it working! Sorry for the late reply. Thanks for your help.
Yes, I have used the template. I am running ABP v0.10.3. I also read the documentation and have set CustomErrors to "On". I am still getting an Internal Server Error with the stack trace I posted above. I still am unable to figure out how to show the specific validation error on the calling form instead of the unhandled exception as shown above. I don't think my DTOs are being automatically validated as I have the call to the application service that is failing in a try/catch in my MVC controller. I would expect to get a friendly error saying Nickname is required instead of the internal server error. Here is my action method in my MVC controller:
[HttpPost]
[UnitOfWork]
public virtual async Task<ActionResult> SignUp(SignUpViewModel model)
{
try
{
CheckModelState();
var input = new CreatePlayerWithNewUserInput()
{
User = new CreateUserInput
{
Nickname = model.Nickname,
EmailAddress = model.EmailAddress,
PasswordHashed = new PasswordHasher().HashPassword(model.Password),
IsActive = true
}
};
//Save user
await PlayerAppService.CreatePlayerWithNewUser(input);
await UnitOfWorkManager.Current.SaveChangesAsync();
//Directly login if possible
if (input.User.IsActive)
{
AbpUserManager<Tenant, Role, User>.AbpLoginResult loginResult;
loginResult = await GetLoginResultAsync(input.User.EmailAddress, model.Password);
if (loginResult.Result == AbpLoginResultType.Success)
{
await SignInAsync(loginResult.User, loginResult.Identity);
return Redirect(Url.Action("Index", "Home"));
}
Logger.Warn("New registered user could not be login. This should not be normally. login result: "
+ loginResult.Result);
}
//If can not login, show a register result page
return View("SignUpResult", new SignUpResultViewModel
{
Nickname = input.User.Nickname,
EmailAddress = input.User.EmailAddress,
IsActive = input.User.IsActive
});
}
catch (UserFriendlyException ex)
{
ViewBag.ErrorMessage = ex.Message;
ViewBag.ErrorDetails = ex.Details;
return SignUpView(model);
}
catch (Exception ex)
{
ViewBag.ErrorMessage = ex.Message;
return SignUpView(model);
}
}
Another thing that isn't working is when I have validation annotations in SignUpViewModel. I get a similar server error before the MVC controller action is even called. Something is not working.
Hi, yes I have read the documentation but there doesn't seem to be anything in there about the use of localization in models. Here is an example model where I am trying to do this:
public class CreateUserInput : ICustomValidate
{
[Required]
[StringLength(User.MaxNicknameLength, MinimumLength = User.MinNicknameLength)]
public string Nickname { get; set; }
[Required]
[EmailAddress]
[StringLength(AbpUserBase.MaxEmailAddressLength)]
public string EmailAddress { get; set; }
[Required]
[DisableAuditing]
public string PasswordHashed { get; set; }
public bool IsActive { get; set; }
public void AddValidationErrors(List<ValidationResult> results)
{
if (Regex.IsMatch(Nickname, User.NicknameFormatValidationRegex))
{
throw new UserFriendlyException(string.Format("Nickname must be between {0} and {1} characters, may " +
"only contain letters, numbers, spaces, hyphens, underscores and periods, and cannot begin or end " +
"with spaces.", User.MinNicknameLength, User.MaxNicknameLength));
}
}
I would like the UserFriendlyException content in the AddValidation method to be something like:
L("NicknameInvalidFormat", User.MinNicknameLength, User.MaxNicknameLength)
Thanks for your help! I'll create a non-authorized service method to use at Sign In.
About the localized string, it certainly does exist in my localization source. Are you able to reproduce it by trying to call a service method that requires authorization in the Sign In method?
If someone can please help me with this that would be great. I'm struggling to figure out why the AbpSession.UserId is null right after the AuthenticationManager.SignIn. From that SignInAsync method, I need to be able to call an application service method that requires authorization. Also, I would like to know why the proper localization source isn't being used to show the string for [CurrentUserDidNotLoginToTheApplication], which exists in my configured and otherwise working localization source.
I too would like a little help with this. It seems like a big downside if anonymous access to certain pages weren't allowed (home, about, contact, etc.). So far this is holding me back from going from MPA to SPA.