protected override void init() { if (UserId.HasValue) { User = UserManagementStatics.GetUser(UserId.Value, true); } }
/// <summary> /// Initializes the class. This includes loading application settings from the configuration file. The application name should be scoped within the system. /// For non web applications, this method must be called directly from the main executable assembly and not from a supporting library. /// /// To debug this method, create a folder called C:\AnyoneFullControl and give Everyone full control. A file will appear in that folder explaining how far /// it got in init. /// </summary> /// <param name="appName"></param> /// <param name="isClientSideProgram"></param> /// <param name="systemLogic"></param> /// <param name="mainDataAccessStateGetter">A method that returns the current main data-access state whenever it is requested, including during this /// AppTools.Init call. Do not allow multiple threads to use the same state at the same time. If you pass null, the data-access subsystem will not be /// available in the application.</param> public static void Init(string appName, bool isClientSideProgram, SystemLogic systemLogic, Func <DataAccessState> mainDataAccessStateGetter = null) { var initializationLog = "Starting init"; try { if (initialized) { throw new ApplicationException("This class can only be initialized once."); } if (systemLogic == null) { throw new ApplicationException("The system must have a global logic class and you must pass an instance of it to AppTools.Init."); } // Initialize ConfigurationStatics, including the general provider, before the exception handling block below because it's reasonable for the exception // handling to depend on this. ConfigurationStatics.Init(systemLogic.GetType(), appName, isClientSideProgram, ref initializationLog); // Setting the initialized flag to true must be done before executing the secondary init block below so that exception handling works. initialized = true; initializationLog += Environment.NewLine + "Succeeded in primary init."; } catch (Exception e) { initializationLog += Environment.NewLine + e; StandardLibraryMethods.EmergencyLog("Initialization log", initializationLog); throw; } try { var asposeLicense = ConfigurationStatics.SystemGeneralProvider.AsposeLicenseName; if (asposeLicense.Any()) { new Aspose.Pdf.License().SetLicense(asposeLicense); new Aspose.Words.License().SetLicense(asposeLicense); } // This initialization could be performed using reflection. There is no need for AppTools to have a dependency on these classes. AppMemoryCache.Init(); BlobFileOps.Init(); DataAccessStatics.Init(); DataAccessState.Init(mainDataAccessStateGetter); EncryptionOps.Init(); HtmlBlockStatics.Init(); InstallationSupportUtility.ConfigurationLogic.Init1(); UserManagementStatics.Init(); systemLogic.InitSystem(); } catch (Exception e) { secondaryInitFailed = true; // Suppress all exceptions since they would prevent apps from knowing that primary initialization succeeded. EWF apps need to know this in order to // automatically restart themselves. Other apps could find this knowledge useful as well. try { EmailAndLogError("An exception occurred during application initialization:", e); } catch {} } }
protected override void init() { User = UserManagementStatics.GetUser(EmailAddress); if (User == null) { throw new ApplicationException("emailAddress"); } }
private PostBackAction getSendNewPasswordAction() { var userLocal = UserManagementStatics.GetUser(emailAddress.Value); if (userLocal == null) { throw new DataModificationException(getUnregisteredEmailMessage()); } return(new PostBackAction(ConfirmPasswordReset.GetInfo(userLocal.Email, info.ReturnUrl))); }
protected override PageContent getContent() { var content = new UiPageContent(omitContentBox: true); if (UserManagementStatics.IdentityProviders.OfType <SamlIdentityProvider>().Any()) { var certificate = UserManagementStatics.GetCertificate(); content.Add( new Section( "Identity providers", FormItemList.CreateStack( items: (certificate.Any() ? "Certificate valid until {0}.".FormatWith( new X509Certificate2(Convert.FromBase64String(certificate), UserManagementStatics.CertificatePassword).NotAfter .ToDayMonthYearString( false)) .ToComponents() : "No certificate.".ToComponents()).Concat(" ".ToComponents()) .Append( new EwfButton( new StandardButtonStyle("Regenerate", buttonSize: ButtonSize.ShrinkWrap), behavior: new ConfirmationButtonBehavior( "Are you sure?".ToComponents(), postBack: PostBack.CreateFull( "certificate", modificationMethod: () => UserManagementStatics.UpdateCertificate(generateCertificate(DateTimeOffset.UtcNow)))))) .Materialize() .ToFormItem(label: "System self-signed certificate".ToComponents()) .Concat( AuthenticationStatics.SamlIdentityProviders.Any() ? new EwfHyperlink(EnterpriseWebFramework.UserManagement.SamlResources.Metadata.GetInfo(), new StandardHyperlinkStyle("")) .ToFormItem(label: "Application SAML metadata".ToComponents()) .ToCollection() : Enumerable.Empty <FormItem>()) .Materialize()) .ToCollection(), style: SectionStyle.Box)); } content.Add( new Section( "System users", EwfTable.Create( tableActions: new HyperlinkSetup(new SystemUser(Es, null), "Create User").ToCollection(), headItems: EwfTableItem.Create("Email".ToCell().Append("Role".ToCell()).Materialize()).ToCollection()) .AddData( UserManagementStatics.SystemProvider.GetUsers(), user => EwfTableItem.Create( user.Email.ToCell().Append(user.Role.Name.ToCell()).Materialize(), setup: EwfTableItemSetup.Create(activationBehavior: ElementActivationBehavior.CreateHyperlink(new SystemUser(Es, user.UserId))))) .ToCollection(), style: SectionStyle.Box)); return(content); }
protected override void init() { if (!UserManagementStatics.UserManagementEnabled) { throw new ApplicationException("User management not enabled"); } if (User.Any() && User != "anonymous" && (UserObject = UserManagementStatics.GetUser(User)) == null) { throw new ApplicationException("user"); } }
protected override void loadData() { BasicPage.Instance.Body.Attributes["class"] = CssElementCreator.SelectUserPageBodyCssClass; ph.AddControlsReturnThis(new PageName()); if (AppTools.IsLiveInstallation) { ph.AddControlsReturnThis( new Paragraph( new Strong("Warning:"), " Do not impersonate a user without permission. Your actions will be attributed to the user you are impersonating, not to you.".GetLiteralControl())); } var pb = PostBack.CreateFull( actionGetter: () => new PostBackAction(new ExternalResourceInfo(info.ReturnUrl.Any() ? info.ReturnUrl : NetTools.HomeUrl))); DataValue <User> user = new DataValue <User>(); ph.AddControlsReturnThis( FormItem.Create( "User's email address (leave blank for anonymous)", new EwfTextBox(""), validationGetter: control => new EwfValidation( (pbv, validator) => { var errorHandler = new ValidationErrorHandler("user"); var emailAddress = validator.GetEmailAddress(errorHandler, control.GetPostBackValue(pbv), true); if (errorHandler.LastResult != ErrorCondition.NoError) { return; } if (!emailAddress.Any()) { user.Value = null; return; } user.Value = UserManagementStatics.GetUser(emailAddress); if (user.Value == null) { validator.NoteErrorAndAddMessage("The email address you entered does not match a user."); } }, pb)).ToControl(), new Paragraph( new PostBackButton( pb, new ButtonActionControlStyle( AppRequestState.Instance.ImpersonatorExists ? "Change User" : "Begin Impersonation", buttonSize: ButtonActionControlStyle.ButtonSize.Large)))); pb.AddModificationMethod(() => UserImpersonationStatics.BeginImpersonation(user.Value)); }
protected override void loadData() { var table = new DynamicTable(new EwfTableColumn("Email", Unit.Percentage(50)), new EwfTableColumn("Role", Unit.Percentage(50))); table.AddActionLink(new ActionButtonSetup("Create User", new EwfLink(new EditUser.Info(es.info, null)))); foreach (var user in UserManagementStatics.GetUsers()) { table.AddTextRow(new RowSetup { ClickScript = ClickScript.CreateRedirectScript(new EditUser.Info(es.info, user.UserId)) }, user.Email, user.Role.Name); } ph.AddControlsReturnThis(table); }
protected override void loadData() { ph.AddControlsReturnThis( EwfTable .Create( tableActions: new HyperlinkSetup(new EditUser.Info(es.info, null), "Create User").ToCollection(), headItems: EwfTableItem.Create("Email".ToCell().Append("Role".ToCell()).Materialize()).ToCollection()) .AddData( UserManagementStatics.GetUsers(), user => EwfTableItem.Create( user.Email.ToCell().Append(user.Role.Name.ToCell()).Materialize(), setup: EwfTableItemSetup.Create( activationBehavior: ElementActivationBehavior.CreateRedirectScript(new EditUser.Info(es.info, user.UserId))))) .ToCollection() .GetControls()); }
/// <summary> /// Call this during LoadData. /// </summary> /// <param name="userId"></param> /// <param name="vl"></param> /// <param name="availableRoles">Pass a restricted list of <see cref="Role"/>s the user may select. Otherwise, Roles available /// in the System Provider are used.</param> /// <param name="validationPredicate">If the function returns true, validation continues.</param> public void LoadData(int?userId, ValidationList vl, List <Role> availableRoles = null, Func <bool> validationPredicate = null) { availableRoles = (availableRoles != null ? availableRoles.OrderBy(r => r.Name) : UserManagementStatics.SystemProvider.GetRoles()).ToList(); user = userId.HasValue ? UserManagementStatics.GetUser(userId.Value, true) : null; if (includePasswordControls() && user != null) { facUser = FormsAuthStatics.GetUser(user.UserId, true); } Func <bool> validationShouldRun = () => validationPredicate == null || validationPredicate(); var b = FormItemBlock.CreateFormItemTable(heading: "Security Information"); b.AddFormItems( FormItem.Create( "Email address", new EwfTextBox(user != null ? user.Email : ""), validationGetter: control => new Validation( (pbv, validator) => { if (validationShouldRun()) { Email = validator.GetEmailAddress(new ValidationErrorHandler("email address"), control.GetPostBackValue(pbv), false); } }, vl))); if (includePasswordControls()) { var group = new RadioButtonGroup(false); var keepPassword = FormItem.Create( "", group.CreateInlineRadioButton(true, label: userId.HasValue ? "Keep the current password" : "Do not create a password"), validationGetter: control => new Validation( (pbv, validator) => { if (!validationShouldRun() || !control.IsCheckedInPostBack(pbv)) { return; } if (user != null) { Salt = facUser.Salt; SaltedPassword = facUser.SaltedPassword; MustChangePassword = facUser.MustChangePassword; } else { genPassword(false); } }, vl)); var generatePassword = FormItem.Create( "", group.CreateInlineRadioButton(false, label: "Generate a " + (userId.HasValue ? "new, " : "") + "random password and email it to the user"), validationGetter: control => new Validation( (pbv, validator) => { if (validationShouldRun() && control.IsCheckedInPostBack(pbv)) { genPassword(true); } }, vl)); var newPassword = new DataValue <string>(); var confirmPassword = new DataValue <string>(); var newPasswordTable = EwfTable.Create(style: EwfTableStyle.StandardExceptLayout); newPasswordTable.AddItem( new EwfTableItem( "Password", FormItem.Create( "", new EwfTextBox("", masksCharacters: true, disableBrowserAutoComplete: true) { Width = Unit.Pixel(200) }, validationGetter: control => new Validation((pbv, v) => newPassword.Value = control.GetPostBackValue(pbv), vl)).ToControl())); newPasswordTable.AddItem( new EwfTableItem( "Password again", FormItem.Create( "", new EwfTextBox("", masksCharacters: true, disableBrowserAutoComplete: true) { Width = Unit.Pixel(200) }, validationGetter: control => new Validation((pbv, v) => confirmPassword.Value = control.GetPostBackValue(pbv), vl)).ToControl())); var providePasswordRadio = group.CreateBlockRadioButton(false, label: "Provide a " + (userId.HasValue ? "new " : "") + "password"); providePasswordRadio.NestedControls.Add(newPasswordTable); var providePassword = FormItem.Create( "", providePasswordRadio, validationGetter: control => new Validation( (pbv, validator) => { if (!validationShouldRun() || !control.IsCheckedInPostBack(pbv)) { return; } FormsAuthStatics.ValidatePassword(validator, newPassword, confirmPassword); var p = new Password(newPassword.Value); Salt = p.Salt; SaltedPassword = p.ComputeSaltedHash(); MustChangePassword = false; }, vl)); b.AddFormItems( FormItem.Create("Password", ControlStack.CreateWithControls(true, keepPassword.ToControl(), generatePassword.ToControl(), providePassword.ToControl()))); } b.AddFormItems( FormItem.Create( "Role", SelectList.CreateDropDown( from i in availableRoles select SelectListItem.Create(i.RoleId as int?, i.Name), user != null ? user.Role.RoleId as int? : null), validationGetter: control => new Validation( (pbv, validator) => { if (validationShouldRun()) { RoleId = control.ValidateAndGetSelectedItemIdInPostBack(pbv, validator) ?? default(int); } }, vl))); Controls.Add(b); }
protected override void loadData() { if (info.User.Any()) { if (!pageViewDataModificationsExecuted) { throw new ApplicationException("Page-view data modifications did not execute."); } ph.AddControlsReturnThis(new Paragraph("Please wait.".ToComponents()).ToCollection().GetControls()); StandardLibrarySessionState.Instance.SetInstantClientSideNavigation(new ExternalResourceInfo(info.ReturnUrl).GetUrl()); return; } BasicPage.Instance.Body.Attributes["class"] = CssElementCreator.SelectUserPageBodyCssClass; ph.AddControlsReturnThis(new PageName().ToCollection().GetControls()); if (ConfigurationStatics.IsLiveInstallation) { ph.AddControlsReturnThis( new Paragraph( new ImportantContent("Warning:".ToComponents()).ToCollection() .Concat( " Do not impersonate a user without permission. Your actions will be attributed to the user you are impersonating, not to you." .ToComponents()) .Materialize()).ToCollection() .GetControls()); } var user = new DataValue <User>(); var pb = PostBack.CreateFull( firstModificationMethod: () => UserImpersonationStatics.BeginImpersonation(user.Value), actionGetter: () => new PostBackAction(new ExternalResourceInfo(info.ReturnUrl.Any() ? info.ReturnUrl : NetTools.HomeUrl))); FormState.ExecuteWithDataModificationsAndDefaultAction( pb.ToCollection(), () => { ph.AddControlsReturnThis( new EmailAddressControl( "", true, validationMethod: (postBackValue, validator) => { if (!postBackValue.Any()) { user.Value = null; return; } user.Value = UserManagementStatics.GetUser(postBackValue); if (user.Value == null) { validator.NoteErrorAndAddMessage("The email address you entered does not match a user."); } }).ToFormItem(label: "User's email address (leave blank for anonymous)".ToComponents()) .ToComponentCollection() .Append( new Paragraph( new EwfButton( new StandardButtonStyle( AppRequestState.Instance.ImpersonatorExists ? "Change User" : "Begin Impersonation", buttonSize: ButtonSize.Large)) .ToCollection())) .GetControls()); }); }
/// <summary> /// Initializes the system. This includes loading application settings from the configuration file. The application name should be scoped within the system. /// For non web applications, this method must be called directly from the main executable assembly and not from a supporting library. /// /// To debug this method, create a folder called C:\AnyoneFullControl and give Everyone full control. A file will appear in that folder explaining how far /// it got in init. /// </summary> /// <param name="globalInitializer">The system's global initializer. Do not pass null.</param> /// <param name="appName"></param> /// <param name="isClientSideApp"></param> /// <param name="assemblyFolderPath">Pass a nonempty string to override the assembly folder path, which is used to locate the installation folder. Use with /// caution.</param> /// <param name="mainDataAccessStateGetter">A method that returns the current main data-access state whenever it is requested, including during this /// InitStatics call. Do not allow multiple threads to use the same state at the same time. If you pass null, the data-access subsystem will not be /// available in the application.</param> /// <param name="useLongDatabaseTimeouts">Pass true if the application is a background process that can tolerate slow database access.</param> public static void InitStatics( SystemInitializer globalInitializer, string appName, bool isClientSideApp, string assemblyFolderPath = "", Func <DataAccessState> mainDataAccessStateGetter = null, bool useLongDatabaseTimeouts = false) { var initializationLog = "Starting init"; try { if (initialized) { throw new ApplicationException("This class can only be initialized once."); } if (globalInitializer == null) { throw new ApplicationException("The system must have a global initializer."); } // Initialize these before the exception handling block below because it's reasonable for the exception handling to depend on them. ConfigurationStatics.Init(assemblyFolderPath, globalInitializer.GetType(), appName, isClientSideApp, ref initializationLog); EmailStatics.Init(); TelemetryStatics.Init(); // Setting the initialized flag to true must be done before executing the secondary init block below so that exception handling works. initialized = true; initializationLog += Environment.NewLine + "Succeeded in primary init."; } catch (Exception e) { initializationLog += Environment.NewLine + e; EwlStatics.EmergencyLog("Initialization log", initializationLog); throw; } try { CultureInfo.DefaultThreadCurrentCulture = Cultures.EnglishUnitedStates; var asposePdfLicensePath = EwlStatics.CombinePaths(ConfigurationStatics.InstallationConfiguration.AsposeLicenseFolderPath, "Aspose.PDF.lic"); if (File.Exists(asposePdfLicensePath)) { new Aspose.Pdf.License().SetLicense(asposePdfLicensePath); } var asposeWordsLicensePath = EwlStatics.CombinePaths(ConfigurationStatics.InstallationConfiguration.AsposeLicenseFolderPath, "Aspose.Words.lic"); if (File.Exists(asposeWordsLicensePath)) { new Aspose.Words.License().SetLicense(asposeWordsLicensePath); } AppMemoryCache.Init(); BlobStorageStatics.Init(); DataAccessStatics.Init(); DataAccessState.Init(mainDataAccessStateGetter, useLongDatabaseTimeouts); EncryptionOps.Init(); HtmlBlockStatics.Init(); UserManagementStatics.Init(); GlobalInitializationOps.globalInitializer = globalInitializer; globalInitializer.InitStatics(); } catch (Exception e) { secondaryInitFailed = true; // Suppress all exceptions since they would prevent apps from knowing that primary initialization succeeded. EWF apps need to know this in order to // automatically restart themselves. Other apps could find this knowledge useful as well. try { TelemetryStatics.ReportError("An exception occurred during application initialization:", e); } catch {} } }
/// <summary> /// Call this during LoadData. /// </summary> /// <param name="userId"></param> /// <param name="availableRoles">Pass a restricted list of <see cref="Role"/>s the user may select. Otherwise, Roles available /// in the System Provider are used.</param> public void LoadData(int?userId, List <Role> availableRoles = null) { availableRoles = (availableRoles?.OrderBy(r => r.Name) ?? UserManagementStatics.SystemProvider.GetRoles()).ToList(); var user = userId.HasValue ? UserManagementStatics.GetUser(userId.Value, true) : null; var facUser = includePasswordControls() && user != null?FormsAuthStatics.GetUser(user.UserId, true) : null; var b = FormItemList.CreateStack(); b.AddFormItems(Email.ToEmailAddressControl(false, value: user != null ? user.Email : "").ToFormItem(label: "Email address".ToComponents())); if (includePasswordControls()) { var group = new RadioButtonGroup(false); var keepPassword = group.CreateRadioButton( true, label: userId.HasValue ? "Keep the current password".ToComponents() : "Do not create a password".ToComponents(), validationMethod: (postBackValue, validator) => { if (!postBackValue.Value) { return; } if (user != null) { Salt.Value = facUser.Salt; SaltedPassword.Value = facUser.SaltedPassword; MustChangePassword.Value = facUser.MustChangePassword; } else { genPassword(false); } }) .ToFormItem(); var generatePassword = group.CreateRadioButton( false, label: "Generate a {0} password and email it to the user".FormatWith(userId.HasValue ? "new, random" : "random").ToComponents(), validationMethod: (postBackValue, validator) => { if (postBackValue.Value) { genPassword(true); } }) .ToFormItem(); var providePasswordSelected = new DataValue <bool>(); var providePassword = group.CreateFlowRadioButton( false, label: "Provide a {0}".FormatWith(userId.HasValue ? "new password" : "password").ToComponents(), setup: FlowRadioButtonSetup.Create( nestedContentGetter: () => { return(FormState.ExecuteWithValidationPredicate( () => providePasswordSelected.Value, () => { var password = new DataValue <string>(); var list = FormItemList.CreateStack( generalSetup: new FormItemListSetup(classes: new ElementClass("newPassword")), items: password.GetPasswordModificationFormItems()); new EwfValidation( validator => { var p = new Password(password.Value); Salt.Value = p.Salt; SaltedPassword.Value = p.ComputeSaltedHash(); MustChangePassword.Value = false; }); return list.ToCollection(); })); }), validationMethod: (postBackValue, validator) => providePasswordSelected.Value = postBackValue.Value) .ToFormItem(); b.AddFormItems( new StackList(keepPassword.ToListItem().ToCollection().Append(generatePassword.ToListItem()).Append(providePassword.ToListItem())).ToFormItem( label: "Password".ToComponents())); } b.AddFormItems( RoleId.ToDropDown( DropDownSetup.Create(from i in availableRoles select SelectListItem.Create(i.RoleId as int?, i.Name)), value: new SpecifiedValue <int?>(user?.Role.RoleId)) .ToFormItem(label: "Role".ToComponents())); this.AddControlsReturnThis(new Section("Security Information", b.ToCollection()).ToCollection().GetControls()); }
/// <summary> /// Call this during LoadData. /// </summary> /// <param name="userId"></param> /// <param name="availableRoles">Pass a restricted list of <see cref="Role"/>s the user may select. Otherwise, Roles available /// in the System Provider are used.</param> /// <param name="validationPredicate">If the function returns true, validation continues.</param> public void LoadData(int?userId, List <Role> availableRoles = null, Func <bool> validationPredicate = null) { availableRoles = (availableRoles != null ? availableRoles.OrderBy(r => r.Name) : UserManagementStatics.SystemProvider.GetRoles()).ToList(); user = userId.HasValue ? UserManagementStatics.GetUser(userId.Value, true) : null; if (includePasswordControls() && user != null) { facUser = FormsAuthStatics.GetUser(user.UserId, true); } Func <bool> validationShouldRun = () => validationPredicate == null || validationPredicate(); var b = FormItemBlock.CreateFormItemTable(heading: "Security Information"); b.AddFormItems( FormItem.Create( "Email address", new EwfTextBox(user != null ? user.Email : ""), validationGetter: control => new EwfValidation( (pbv, validator) => { if (validationShouldRun()) { Email = validator.GetEmailAddress(new ValidationErrorHandler("email address"), control.GetPostBackValue(pbv), false); } }))); if (includePasswordControls()) { var group = new RadioButtonGroup(false); var keepPassword = FormItem.Create( "", group.CreateInlineRadioButton(true, label: userId.HasValue ? "Keep the current password" : "Do not create a password"), validationGetter: control => new EwfValidation( (pbv, validator) => { if (!validationShouldRun() || !control.IsCheckedInPostBack(pbv)) { return; } if (user != null) { Salt = facUser.Salt; SaltedPassword = facUser.SaltedPassword; MustChangePassword = facUser.MustChangePassword; } else { genPassword(false); } })); var generatePassword = FormItem.Create( "", group.CreateInlineRadioButton(false, label: "Generate a " + (userId.HasValue ? "new, " : "") + "random password and email it to the user"), validationGetter: control => new EwfValidation( (pbv, validator) => { if (validationShouldRun() && control.IsCheckedInPostBack(pbv)) { genPassword(true); } })); var providePassword = FormState.ExecuteWithValidationPredicate( validationShouldRun, () => { var providePasswordSelected = new DataValue <bool>(); return(FormItem.Create( "", group.CreateBlockRadioButton( false, (postBackValue, validator) => providePasswordSelected.Value = postBackValue.Value, label: "Provide a {0}".FormatWith(userId.HasValue ? "new password" : "password"), nestedControlListGetter: () => { return FormState.ExecuteWithValidationPredicate( () => providePasswordSelected.Value, () => { var password = new DataValue <string>(); var newPasswordTable = EwfTable.Create(style: EwfTableStyle.StandardExceptLayout); foreach (var i in password.GetPasswordModificationFormItems(textBoxWidth: Unit.Pixel(200))) { newPasswordTable.AddItem(new EwfTableItem(i.Label, i.ToControl(omitLabel: true))); } new EwfValidation( validator => { var p = new Password(password.Value); Salt = p.Salt; SaltedPassword = p.ComputeSaltedHash(); MustChangePassword = false; }); return newPasswordTable.ToCollection(); }); }), validationGetter: control => control.Validation)); }); b.AddFormItems( FormItem.Create("Password", ControlStack.CreateWithControls(true, keepPassword.ToControl(), generatePassword.ToControl(), providePassword.ToControl()))); } b.AddFormItems( FormItem.Create( "Role", SelectList.CreateDropDown( from i in availableRoles select SelectListItem.Create(i.RoleId as int?, i.Name), user != null ? user.Role.RoleId as int? : null), validationGetter: control => new EwfValidation( (pbv, validator) => { if (validationShouldRun()) { RoleId = control.ValidateAndGetSelectedItemIdInPostBack(pbv, validator) ?? default(int); } }))); Controls.Add(b); }