Activities of "enisn"

I couldn't reproduce this issue.

Did you update your wwwroot/index.html manually?

It seems you're on dev branch.

Localization logic is changed in v7.0 but npm packages aren't published yet. So, if you run abp install-libs, 6.0 packages will be installed.

You can overcome this issue by replacing abp.js with following file in the dev branch: https://github.com/abpframework/abp/blob/dev/npm/packs/core/src/abp.js

how to prevent a user who has the privilege to manage the users from deleting the Admin user or Sys Role?

You can replace and customize AppService


[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IdentityUserAppService))]
public class MyIdenityUserAppService : IdentityUserAppService
{
    // base ctor here

    public override  async Task DeleteAsync(Guid id)
    {
        var user = await UserManager.FindByIdAsync(id.ToString());
        if(user.UserName == "admin")
        {
            throw new Exception("can not delete admin");
        }
        (await UserManager.DeleteAsync(user)).CheckErrors();
    }
}

Hi, We've investigated your logs and found this:

2022-11-04 10:23:17.696 +02:00 [INF] Content root path: C:\Source\Token Generation API\code\TokenGen\services\administration\src\TokenGen.AdministrationService.HttpApi.Host\
2022-11-04 10:23:17.900 +02:00 [INF] Request starting HTTP/2 GET https://localhost:44367/ - -
2022-11-04 10:23:20.506 +02:00 [INF] Request starting HTTP/1.1 GET https://localhost:44367/api/abp/application-configuration?api-version=1.0 - 0
2022-11-04 10:23:22.153 +02:00 [ERR] An unhandled exception has occurred while executing the request.
Microsoft.AspNetCore.Routing.Matching.AmbiguousMatchException: The request matched multiple endpoints. Matches: 

TokenGen.AdministrationService.Controllers.HomeController.Index (TokenGen.AdministrationService.HttpApi.Host)
TokenGen.StsApiService.Controllers.HomeController.Index (TokenGen.StsApiService.HttpApi.Host)
   at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[] candidateState)
   at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ProcessFinalCandidates(HttpContext httpContext, CandidateState[] candidateState)
   at Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.Select(HttpContext httpContext, CandidateState[] candidateState)
   at Microsoft.AspNetCore.Routing.Matching.DfaMatcher.MatchAsync(HttpContext httpContext)
   at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
   at Volo.Abp.AspNetCore.Security.AbpSecurityHeadersMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.RequestLocalization.AbpRequestLocalizationMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---
   at Volo.Abp.AspNetCore.Tracing.AbpCorrelationIdMiddleware.InvokeAsync(HttpContext context, RequestDelegate next)
   at Microsoft.AspNetCore.Builder.UseMiddlewareExtensions.<>c__DisplayClass6_1.<<UseMiddlewareInterface>b__1>d.MoveNext()
--- End of stack trace from previous location ---

It seems TokenGen.AdministrationService.Controllers.HomeController and TokenGen.StsApiService.Controllers.HomeController conflicts for the same route (/).

Make sure your AdministrationService doesn't have a reference to StsApiService directly. Most probably your StsApiService.HttpApi layer is included in your AdministrationService.HttpApi layer. Can you check if there is a reference?

Yeah sure,

You can use following files to override:

  • /Pages/Identity/Users/EditModal.cshtml
@page
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@using Volo.Abp.Data
@using Volo.Abp.Identity.Localization
@using Volo.Abp.Identity.Web.Pages.Identity.Users
@using Volo.Abp.Localization
@using Volo.Abp.ObjectExtending
@model EditModalModel
@inject IHtmlLocalizer<IdentityResource> L
@inject IStringLocalizerFactory StringLocalizerFactory
@{
    Layout = null;
}
<form method="post" asp-page="/Identity/Users/EditModal">
    <abp-modal>
        <abp-modal-header title="@L["Edit"].Value"></abp-modal-header>
        <abp-modal-body>
            <abp-tabs name="create-user-modal-tabs">
                <abp-tab title="@L["UserInformation"].Value">
                    <input asp-for="UserInfo.Id" />
                    <input asp-for="UserInfo.ConcurrencyStamp" />
                    <abp-input asp-for="UserInfo.UserName" />
                    <abp-input asp-for="UserInfo.Name" />
                    <abp-input asp-for="UserInfo.Surname" />
                    <abp-input asp-for="UserInfo.Email" label="@(L["EmailAddress"].Value + " * ")" />
                    @foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties<EditModalModel.UserInfoViewModel>())
                    {
                        if (!propertyInfo.Name.EndsWith("_Text"))
                        {
                            if (propertyInfo.Type.IsEnum || !propertyInfo.Lookup.Url.IsNullOrEmpty())
                            {
                                if (propertyInfo.Type.IsEnum)
                                {
                                    Model.UserInfo.ExtraProperties.ToEnum(propertyInfo.Name, propertyInfo.Type);
                                }
                                <abp-select asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                            label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                            autocomplete-api-url="@propertyInfo.Lookup.Url"
                                            autocomplete-selected-item-name="@Model.UserInfo.GetProperty(propertyInfo.Name+"_Text")"
                                            autocomplete-selected-item-value="@Model.UserInfo.GetProperty(propertyInfo.Name)"
                                            autocomplete-filter-param-name="@propertyInfo.Lookup.FilterParamName"
                                            autocomplete-items-property-name="@propertyInfo.Lookup.ResultListPropertyName"
                                            autocomplete-display-property-name="@propertyInfo.Lookup.DisplayPropertyName"
                                            autocomplete-value-property-name="@propertyInfo.Lookup.ValuePropertyName"></abp-select>
                            }
                            else
                            {
                                <abp-input type="@propertyInfo.GetInputType()"
                                           asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                           label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                           asp-format="@propertyInfo.GetInputFormatOrNull()"
                                           value="@propertyInfo.GetInputValueOrNull(Model.UserInfo.GetProperty(propertyInfo.Name))" />
                            }
                        }
                    }
                    <abp-input asp-for="UserInfo.PhoneNumber" />
                    <abp-input asp-for="UserInfo.IsActive" />
                    <abp-input asp-for="UserInfo.LockoutEnabled" />
                </abp-tab>
                @if (Model.Roles.Any())
                {
                    <abp-tab name="Roles" title="@L.GetString("Roles{0}", Model.Roles.Count(r => r.IsAssigned))">
                        @for (var i = 0; i < Model.Roles.Length; i++)
                        {
                            var role = Model.Roles[i];
                            <abp-input asp-for="@role.IsAssigned"
                                       abp-id-name="@Model.Roles[i].IsAssigned"
                                       label="@role.GetShownName(HtmlEncoder, L.GetString("OU"))"
                                       disabled="@role.IsInheritedFromOu" />
                            <input asp-for="@role.Name" abp-id-name="@Model.Roles[i].Name" />
                        }
                    </abp-tab>
                }

                @if (Model.OrganizationUnits.Any())
                {
                    <abp-tab name="OrganizationUnits" title="@L.GetString("OrganizationUnits{0}", Model.OrganizationUnits.Count(r => r.IsAssigned))">

                        <div id="JsTreeCheckable" class="tree jstree jstree-2 jstree-default jstree-checkbox-no-clicked jstree-checkbox-selection" role="tree" aria-multiselectable="true" tabindex="0" aria-activedescendant="j2_1" aria-busy="false" aria-selected="false">
                            <ul class="jstree-container-ul jstree-children" role="group">
                                @for (int i = 0; i < Model.OrganizationUnitTreeRootNode.Children.Count; i++)
                                {
                                    @await Html.PartialAsync("OrganizationUnitTreeNode", new OrganizationUnitTreeNodeModel
                                    {
                                        Depth = 0,
                                        Node = Model.OrganizationUnitTreeRootNode.Children[i],
                                        OrganizationUnits = Model.OrganizationUnits
                                    })
                                }
                            </ul>
                        </div>
                        @for (var i = 0; i < Model.OrganizationUnits.Length; i++)
                        {
                            var organizationUnits = Model.OrganizationUnits[i];
                            <input asp-for="@organizationUnits.IsAssigned" abp-id-name="@Model.OrganizationUnits[i].IsAssigned" />
                            <input asp-for="@organizationUnits.DisplayName" abp-id-name="@Model.OrganizationUnits[i].DisplayName" />
                            <input asp-for="@organizationUnits.Id" abp-id-name="@Model.OrganizationUnits[i].Id" />
                        }
                    </abp-tab>
                }
            </abp-tabs>
        </abp-modal-body>
        <abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer>
    </abp-modal>
</form>
<input hidden id="RolesCount" value="@Model.Roles.Count(r => r.IsAssigned)" />

For the models, you can just inherit from IdentityUserModalPageModel, IdentityUserModalPageModel and add your custom logic instead of writing all the model again.


using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.Identity.Web.Pages.Identity.Users;

[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(CreateModalModel))]
public class MyCreateModalModel : CreateModalModel
{
    public MyCreateModalModel(IIdentityUserAppService identityUserAppService) : base(identityUserAppService)
    {
    }

    public override async Task OnGetAsync()
    {
        await base.OnGetAsync(); // Keep base operations.

        // your own logic here
    }

    public override async Task<NoContentResult> OnPostAsync()
    {
        var result = await base.OnPostAsync();

        // your own logic here
		
        return result;
    }
}

We solved that problem and it'll be released in the next version of LeptonX.

You can use the following footer override in your application to fix it until the next release.

  • Create a razor file in your blazor project. Let's say it's MyFooter.razor

  • Content of this file should be as following:

@using Volo.Abp.DependencyInjection
@using Microsoft.Extensions.DependencyInjection
@using Volo.Abp.AspNetCore.Components.Web.LeptonXTheme.Components.ApplicationLayout.TopMenu
@inherits Footer

@attribute [ExposeServices(typeof(Footer))]
@attribute [Dependency(ReplaceServices = true)]

<div class="lpx-footer">
    <div class="d-flex justify-content-between px-4 py-3">
        <div>
            <span>2022©</span>
            <a href="#"> LeptonX Theme</a>
        </div>
        <div>
            <a href="#">About</a>
            <a href="#">Contact</a>
        </div>
    </div>
</div> 

You can override the existing cshtml file of the modal via following this documentation: https://docs.abp.io/en/abp/latest/UI/AspNetCore/Customization-User-Interface#overriding-a-razor-page-cshtml

To achieve that, create a file in this path:

  • /Pages/Identity/Users/CreateModal.cshtml

  • And content of this newly created file should be:

@page
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Localization
@using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Modal
@using Volo.Abp.Data
@using Volo.Abp.Identity
@using Volo.Abp.Identity.Localization
@using Volo.Abp.Identity.Settings
@using Volo.Abp.Identity.Web.Pages.Identity.Users
@using Volo.Abp.Localization
@using Volo.Abp.ObjectExtending
@using Volo.Abp.Settings
@model Volo.Abp.Identity.Web.Pages.Identity.Users.CreateModalModel
@inject ISettingProvider SettingProvider
@inject IHtmlLocalizer<IdentityResource> L
@inject IStringLocalizerFactory StringLocalizerFactory
@{
    Layout = null;
}
<form method="post" asp-page="/Identity/Users/CreateModal">
    <abp-modal>
        <abp-modal-header title="@L["NewUser"].Value"></abp-modal-header>
        <abp-modal-body>
            <abp-tabs name="create-user-modal-tabs">
                <abp-tab title="@L["UserInformations"].Value">
                    <abp-input asp-for="UserInfo.UserName" />
                    <abp-input asp-for="UserInfo.Name" />
                    <abp-input asp-for="UserInfo.Surname" />
                    <div class="mb-3">
                        <label asp-for="UserInfo.Password" class="form-label">@L["Password"] *</label>
                        <div class="input-group">
                            <input type="password" class="form-control" maxlength="@IdentityUserConsts.MaxPasswordLength" asp-for="UserInfo.Password" />
                            <button class="btn btn-secondary" type="button" id="PasswordVisibilityButton"><i class="fa fa-eye-slash" aria-hidden="true"></i></button>
                        </div>
                        <span asp-validation-for="UserInfo.Password"></span>
                    </div>
                    <abp-input asp-for="UserInfo.Email" label="@(L["EmailAddress"].Value + " * ")" />
                    @foreach (var propertyInfo in ObjectExtensionManager.Instance.GetProperties<CreateModalModel.UserInfoViewModel>())
                    {
                        if (!propertyInfo.Name.EndsWith("_Text"))
                        {
                            if (propertyInfo.Type.IsEnum || !propertyInfo.Lookup.Url.IsNullOrEmpty())
                            {
                                if (propertyInfo.Type.IsEnum)
                                {
                                    Model.UserInfo.ExtraProperties.ToEnum(propertyInfo.Name, propertyInfo.Type);
                                }
                                <abp-select asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                            label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                            autocomplete-api-url="@propertyInfo.Lookup.Url"
                                            autocomplete-selected-item-name="@Model.UserInfo.GetProperty(propertyInfo.Name+"_Text")"
                                            autocomplete-selected-item-value="@Model.UserInfo.GetProperty(propertyInfo.Name)"
                                            autocomplete-filter-param-name="@propertyInfo.Lookup.FilterParamName"
                                            autocomplete-items-property-name="@propertyInfo.Lookup.ResultListPropertyName"
                                            autocomplete-display-property-name="@propertyInfo.Lookup.DisplayPropertyName"
                                            autocomplete-value-property-name="@propertyInfo.Lookup.ValuePropertyName"></abp-select>
                            }
                            else
                            {
                                <abp-input type="@propertyInfo.GetInputType()"
                                           asp-for="UserInfo.ExtraProperties[propertyInfo.Name]"
                                           label="@propertyInfo.GetLocalizedDisplayName(StringLocalizerFactory)"
                                           asp-format="@propertyInfo.GetInputFormatOrNull()"
                                           value="@propertyInfo.GetInputValueOrNull(Model.UserInfo.GetProperty(propertyInfo.Name))" />
                            }
                        }
                    }
                    <abp-input asp-for="UserInfo.PhoneNumber" />
                    <abp-input asp-for="UserInfo.IsActive" />
                    <abp-input asp-for="UserInfo.LockoutEnabled" />
                    @if (await SettingProvider.IsTrueAsync(IdentitySettingNames.SignIn.RequireConfirmedEmail))
                    {
                        <abp-input asp-for="UserInfo.SendConfirmationEmail" />
                    }
                </abp-tab>
                <abp-tab name="Roles" title="@L.GetString("Roles{0}", Model.Roles.Count(r => r.IsAssigned))">
                    @for (var i = 0; i < Model.Roles.Length; i++)
                    {
                        var role = Model.Roles[i];
                        if (role.IsDefault)
                        {

                            <abp-input asp-for="@role.IsAssigned" abp-id-name="@Model.Roles[i].IsAssigned" label="@HtmlEncoder.Encode(role.Name)" checked="checked" />
                        }
                        else
                        {
                            <abp-input asp-for="@role.IsAssigned" abp-id-name="@Model.Roles[i].IsAssigned" label="@HtmlEncoder.Encode(role.Name)" />
                        }

                        <input asp-for="@role.Name" abp-id-name="@Model.Roles[i].Name" />
                    }
                </abp-tab>
                @if (Model.OrganizationUnits.Any())
                {
                    <abp-tab name="OrganizationUnits" title="@L.GetString("OrganizationUnits{0}", Model.OrganizationUnits.Count(r => r.IsAssigned))">
                        <div id="JsTreeCheckable" class="tree jstree jstree-2 jstree-default jstree-checkbox-no-clicked jstree-checkbox-selection" role="tree" aria-multiselectable="true" tabindex="0" aria-activedescendant="j2_1" aria-busy="false" aria-selected="false">
                            <ul class="jstree-container-ul jstree-children" role="group">
                                @for (int i = 0; i < Model.OrganizationUnitTreeRootNode.Children.Count; i++)
                                {
                                    @await Html.PartialAsync("OrganizationUnitTreeNode", new OrganizationUnitTreeNodeModel
                                    {
                                        Depth = 0,
                                        Node = Model.OrganizationUnitTreeRootNode.Children[i],
                                        OrganizationUnits = Model.OrganizationUnits
                                    })
                                }
                            </ul>
                        </div>
                        @for (var i = 0; i < Model.OrganizationUnits.Length; i++)
                        {
                            var organizationUnits = Model.OrganizationUnits[i];
                            <input asp-for="@organizationUnits.IsAssigned" abp-id-name="@Model.OrganizationUnits[i].IsAssigned" />
                            <input asp-for="@organizationUnits.DisplayName" abp-id-name="@Model.OrganizationUnits[i].DisplayName" />
                            <input asp-for="@organizationUnits.Id" abp-id-name="@Model.OrganizationUnits[i].Id" />
                        }
                    </abp-tab>
                }
                
                <abp-tab name="your-custom-tab" title="Your Custom Tab">
                    YOUR TAB CONTENT HERE 👈
                </abp-tab>
            </abp-tabs>
        </abp-modal-body>
        <abp-modal-footer buttons="@(AbpModalButtons.Cancel | AbpModalButtons.Save)"></abp-modal-footer>
    </abp-modal>
</form>
<input hidden id="RolesCount" value="@Model.Roles.Count(r => r.IsAssigned)" />

Have you checked Tenant-Edition Subscription? Before doing that, you have to configure Payment Configuration properly.

You can use Edition Features to turn on/off tenant features according to the subscription.

Also you can check this out: https://support.abp.io/QA/Questions/3726/Questions-Regarding-Recurring-Stripe-Payment--Retrieval#answer-f874d726-d096-90e6-d993-3a0671092939

Hi christophe.baille

That search feature is written as a plain script in javascript. It shouldn't be dependent on redis. Can you provide Browser Console log if there is an error?

We're still investigating this issue. Since this is a kind of bug, your ticket has been refunded.

Showing 41 to 50 of 381 entries
Made with ❤️ on ABP v9.1.0-rc.1. Updated on January 17, 2025, 14:13