Thank you for your advice
i'll let you know my progress
actually this issue help me to fix my problem [https://github.com/aspnetboilerplate/aspnetboilerplate/issues/1354])
but i don't what i'm doing in the previous snippet of code is right or not is there any way to exclude some properties from being mapped or updated what is the good practice for such a cases ? thank you
Hello
i'm trying to update record but must be sure to prevent updating some fields so i retrieve the old record before editing but i got this error nHandling.AbpApiExceptionFilterAttribute - Attaching an entity of type 'Umbrella.Models.Patient.Patient' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
protected virtual async Task EditRecordAsync(CreateOrEditPatientDto input)
{
Debug.Assert(input.Patient.Id != null, "input.Patient.Id should be set.");
var patient = input.Patient.MapTo<Models.Patient.Patient>();
//Make sure some fields not editied in patien object
var oldPatient = await _patientRepository.GetAsync(patient.Id);
patient.IsActive = oldPatient.IsActive;
patient.IsCertified = oldPatient.IsCertified;
patient.ParentId = oldPatient.ParentId;
patient.DateEnd = oldPatient.DateEnd;
await _patientRepository.UpdateAsync(patient); // the error been thrown at this line
await _unitOfWorkManager.Current.SaveChangesAsync();
input.User.Name = input.Patient.NameAr;
input.User.Surname = input.Patient.NameEn;
Debug.Assert(input.User.Id != null, "input.User.Id should be set.");
var user = await UserManager.FindByIdAsync(input.User.Id.Value);
//Update user properties
input.User.MapTo(user);
CheckErrors(await UserManager.UpdateAsync(user));
}
if i removed these lines it work fine
var oldPatient = await _patientRepository.GetAsync(patient.Id);
patient.IsActive = oldPatient.IsActive;
patient.IsCertified = oldPatient.IsCertified;
patient.ParentId = oldPatient.ParentId;
patient.DateEnd = oldPatient.DateEnd;
but i need to do this anyway what's wrong with my code as i faced this error many times ?
Hello everyone
i implement Odata against patient table and add the attribute [AbpApiAuthorize] to secure it to authenticated users , then tried to secure it to users how have the permissions on patient table by add attribute [AbpAuthorize(AppPermissions.Pages_Patient)] but unfortunately it didn't work how can i achieve that because not all authenticated users have the permissions to access such an information like that
PatientsController.cs
[AbpApiAuthorize]
[AbpAuthorize(AppPermissions.Pages_Patient)]
public class PatientsController : AbpODataEntityController<Patient, long>
{
private readonly IRepository<Patient, long> _repository;
public PatientsController(IRepository<Patient, long> repository)
: base(repository)
{
_repository = repository;
}
}
Hi maybe you right :D but i will try to implement it to understand exactly the idea of domain service thank you
Hi, i appreciate your help
1- i think you forgot to write down link of documentation for unit of work transaction
2- actually i tried for hours to convert _iUserAppService to a DomainService to be used in my PatientAppService but unfortunately i didn't succeeded , i'm so confused about that , i reviewed the link you provided many times but the situations is totally different when it related to UserAppService i follow the steps carefully trying to achieve it till i reach to create UserManager class which should inherit from DomainService class but as you know UserManager Class already exists and already inherits from AbpUserManager<Tenant, Role, User> class , so i tried to create another class and continue but i think i running in wrong way so can you please provide me with snippet code that help me in my case and i think you already have a fresh copy of my project files if you want to do it & test from your side
regards
sent waiting for your response
Hello everyone
i have a case that require all changes are saved together if one of them failed then rollback should be executed
the scenario is that i have a patient table that related to User table with a foreign key UserId so when the someone register on the system or from users page i have to create user first then patient the same way when creating a patient from patients pages i have to create user as well everything for now is just fine but i didn't sure if what i'm doing is correct but need to make sure when something happen when saving it should rollback all changes otherwise accept all changes please refer to this post [ <a class="postlink" href="http://stackoverflow.com/questions/815586/entity-framework-using-transactions-or-savechangesfalse-and-acceptallchanges#answer-815660">http://stackoverflow.com/questions/8155 ... wer-815660</a> ])
PatientAppService.cs
private readonly IPatientRepository _patientRepository;
private readonly IUserAppService _iUserAppService;
public PatientAppService(IPatientRepository patientRepository, IUserAppService iUserAppService)
{
_patientRepository = patientRepository;
_iUserAppService = iUserAppService;
}
[AbpAuthorize(AppPermissions.Pages_Patient_Create)]
protected virtual async Task CreateRecordAsync(CreateOrEditPatientDto input)
{
input.User.IsActive = true;
input.User.ShouldChangePasswordOnNextLogin = true;
if (string.IsNullOrEmpty(input.User.EmailAddress))
{
input.User.EmailAddress = string.Format("{0}{1}", input.User.UserName, "@hotmail.com");
}
CreateOrUpdateUserInput userInput = new CreateOrUpdateUserInput
{
AssignedRoleNames = new string[] { "user" },
SendActivationEmail = true,
SetRandomPassword = false,
User = input.User
};
await _iUserAppService.CreateOrUpdateUser(userInput);
var u = await UserManager.FindByNameAsync(input.User.UserName);
input.Patient.UserId = u.Id;
var patient = input.Patient.MapTo<Models.Patient.Patient>();
await _patientRepository.InsertAsync(patient);
}
ok please provide me with your email or should i use this one <a href="mailto:[email protected]">[email protected]</a>
Hi, thank you for coming back
Register.cshtml
@model Umbrella.Web.Models.Account.RegisterViewModel
@using System.Web.Script.Serialization
@using Abp.Extensions
@using Abp.Web.Mvc.Extensions
@using Umbrella.MultiTenancy
@using Recaptcha.Web
@using Recaptcha.Web.Mvc
@section Scripts
{
<script>
window.passwordComplexitySetting = @(new JavaScriptSerializer().Serialize(Model.PasswordComplexitySetting).Replace("\"", ""));
</script>
@Html.IncludeScript("~/Views/Account/Register.js")
}
<form class="register-form" action="@Url.Action("Register")" method="post">
<h3>@L("SignUp")</h3>
@if (@ViewBag.ErrorMessage != null)
{
<div class="alert alert-danger">
<i class="fa fa-warning"></i> @ViewBag.ErrorMessage
</div>
}
@Html.AntiForgeryToken()
@if (ViewBag.IsMultiTenancyEnabled)
{
if (Model.TenancyName.IsNullOrEmpty())
{
<p class="hint hide">
@L("TenantInformations")
</p>
<div class="form-group hide">
<label class="control-label visible-ie8 visible-ie9">@L("TenancyName")</label>
<input class="form-control placeholder-no-fix input-ltr" type="text" placeholder="@L("TenancyName")" name="TenancyName" value="@(Model.TenancyName ?? "Default")" required maxlength="@Tenant.MaxTenancyNameLength" />
</div>
}
else
{
<input type="hidden" name="TenancyName" value="@Model.TenancyName" />
}
}
<input type="hidden" name="IsExternalLogin" value="@Model.IsExternalLogin.ToString()" />
<p class="hint">
@L("PersonalInformations")
</p>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("QuadName")</label>
<input class="form-control placeholder-no-fix" type="text" placeholder="@L("QuadName")" name="Name" required value="@Model.Name" maxlength="@Umbrella.UmbrellaConsts.MaxNameLength" autocomplete="off" onkeypress="return checkCharacters(event,'ar');" onpaste="return false;"/>
@Html.ValidationMessageFor(m => m.Name, "", new { @class = "text-danger" })
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("Mobile")</label>
<input class="form-control placeholder-no-fix" type="text" placeholder="@L("Mobile")" name="Mobile" required value="@Model.Mobile" maxlength="@Umbrella.UmbrellaConsts.MaxMobileLength" data-val-regex="@L("InvalidMobile")" data-val-regex-pattern="05(0|3|5|4|6|8|9)[0-9]{7}" data-val="true" autocomplete="off" onkeypress="return checkNumbers(event)" onpaste="return false;"/>
@Html.ValidationMessageFor(m => m.Mobile, "", new { @class = "text-danger" })
</div>
@*<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("Surname")</label>
<input class="form-control placeholder-no-fix" type="text" placeholder="@L("Surname")" name="Surname" required value="@Model.Surname" maxlength="@Umbrella.Authorization.Users.User.MaxSurnameLength" />
</div>*@
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("EmailAddress")</label>
<input class="form-control placeholder-no-fix" type="email" placeholder="@L("EmailAddress")" name="EmailAddress" value="@Model.EmailAddress" maxlength="@Umbrella.Authorization.Users.User.MaxEmailAddressLength" autocomplete="off" onkeypress="return checkEnglishAndNumbersAtSymbol(event);" onpaste="return false;" />
@Html.ValidationMessageFor(m => m.EmailAddress, "", new { @class = "text-danger" })
</div>
@if (!Model.IsExternalLogin)
{
<p class="hint">
@L("AccountSettings")
</p>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("IdentityNumber")</label>
<input class="form-control placeholder-no-fix input-ltr" type="text" autocomplete="off" placeholder="@L("IdentityNumber")" name="UserName" value="@Model.UserName" required maxlength="@Umbrella.UmbrellaConsts.MaxIdentityLength" data-val-regex="@L("InvalidIdentityNumber")" data-val-regex-pattern="10[0-9]{8}" data-val="true" onkeypress="return checkNumbers(event)" onpaste="return false;"/>
@Html.ValidationMessageFor(m => m.UserName, "", new { @class = "text-danger" })
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("Password")</label>
<input class="form-control placeholder-no-fix" type="password" autocomplete="off" id="RegisterPassword" placeholder="@L("Password")" name="Password" required data-val="true" onpaste="return false;"/>
@Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
</div>
<div class="form-group">
<label class="control-label visible-ie8 visible-ie9">@L("PasswordRepeat")</label>
<input class="form-control placeholder-no-fix" type="password" autocomplete="off" placeholder="@L("PasswordRepeat")" name="PasswordRepeat" required data-val="true" data-val-equalto-other="Password" data-val-equalto="@L("PasswordNotMatch")" onpaste="return false;"/>
@Html.ValidationMessageFor(m => m.PasswordRepeat, "", new { @class = "text-danger" })
</div>
}
@if (ViewBag.UseCaptcha)
{
<p class="hint">
@L("Captha_Hint")
</p>
<div class="form-group margin-bottom-20">
@Html.Recaptcha(theme: RecaptchaTheme.Red)
</div>
}
<div class="form-actions">
<a href="@Url.Action("Login","Account")"><button type="button" id="register-back-btn" class="btn btn-default">@L("Back")</button></a>
<button type="submit" id="register-submit-btn" class="btn btn-primary uppercase">@L("Submit")</button>
</div>
</form>
Register.js
var CurrentPage = function () {
jQuery.validator.addMethod("customUsername", function (value, element) {
if (value === $('input[name="EmailAddress"]').val()) {
return true;
}
return !$.validator.methods.email.apply(this, arguments);
}, abp.localization.localize("RegisterFormUserNameInvalidMessage"));
var _passwordComplexityHelper = new app.PasswordComplexityHelper();
var handleRegister = function () {
$('.register-form').validate({
errorElement: 'span', //default input error message container
errorClass: 'help-block', // default input error message class
focusInvalid: false, // do not focus the last invalid input
ignore: "",
rules: {
PasswordRepeat: {
equalTo: "#RegisterPassword"
},
UserName: {
required: true,
customUsername: true
}
},
messages: {
},
invalidHandler: function (event, validator) {
},
highlight: function (element) {
$(element).closest('.form-group').addClass('has-error');
},
success: function (label) {
label.closest('.form-group').removeClass('has-error');
label.remove();
},
errorPlacement: function (error, element) {
if (element.closest('.input-icon').size() === 1) {
error.insertAfter(element.closest('.input-icon'));
} else {
error.insertAfter(element);
}
},
submitHandler: function (form) {
form.submit();
}
});
$('.register-form input').keypress(function (e) {
if (e.which == 13) {
if ($('.register-form').valid()) {
$('.register-form').submit();
}
return false;
}
});
var $element = $('#RegisterPassword');
_passwordComplexityHelper.setPasswordComplexityRules($element, window.passwordComplexitySetting);
}
return {
init: function () {
handleRegister();
}
};
}();
Note that i'm using jquery unobtrusive validation because i need ti use regex annotation in RegisterViewModel , as jquery validation will not show up validation message if i didn't add some attributes to Password Input
RegisterViewModel
public class RegisterViewModel : IValidatableObject
{
/// <summary>
/// Not required for single-tenant applications.
/// </summary>
[StringLength(Tenant.MaxTenancyNameLength)]
public string TenancyName { get; set; }
[Required]
[StringLength(UmbrellaConsts.MaxNameLength)]
public string Name { get; set; }
//[Required]
[StringLength(UmbrellaConsts.MaxNameLength)]
public string Surname { get; set; }
[StringLength(User.MaxUserNameLength)]
[RegularExpression("10[0-9]{8}")]
public string UserName { get; set; }
//[Required]
[EmailAddress]
[StringLength(User.MaxEmailAddressLength)]
public string EmailAddress { get; set; }
[Required]
[StringLength(User.MaxPlainPasswordLength)]
[DisableAuditing]
public string Password { get; set; }
[Required]
[StringLength(User.MaxPlainPasswordLength)]
[DisableAuditing]
public string PasswordRepeat { get; set; }
public bool IsExternalLogin { get; set; }
public PasswordComplexitySetting PasswordComplexitySetting { get; set; }
[Required]
[StringLength(UmbrellaConsts.MaxMobileLength)]
[RegularExpression("05(0|3|5|4|6|8|9)[0-9]{7}")]
public string Mobile { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!UserName.IsNullOrEmpty())
{
if (!UserName.Equals(EmailAddress) && new ValidationHelper().IsEmail(UserName))
{
yield return new ValidationResult("Username cannot be an email address unless it's same with your email address !");
}
}
}
}
by the way the same situation in reset password page but i didn't made any changes on that page , the validation show up tell me that password should contains small letter but it accept from me numbers only but if i set settings the password should contains both small and uppercase letter it works just fine Thank you for your concern