Activities of "liangshiwei"

Hi,

I think you can create an interface, like:

public interface IMyOrganizationRepository : IOrganizationUnitRepository
{
    public Task GetCustomerAsync();
}

[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IOrganizationUnitRepository), typeof(IMyOrganizationRepository))]
public class EfCoreAppOrganizationUnitRepository : EfCoreOrganizationUnitRepository, IMyOrganizationRepository
{
    public EfCoreAppOrganizationUnitRepository(IDbContextProvider<IIdentityDbContext> dbContextProvider) : base(
        dbContextProvider)
    {
    }

    public Task GetCustomerAsync()
    {
        return Task.CompletedTask;
    }
}

public class OrganizationUnitsAppService : OrganizationUnitAppService
{
    public OrganizationUnitsAppService(
        IOrganizationUnitRepository organizationUnitRepository)
        : base(organizationUnitRepository)
    {
    }

    public Task GetMember()
    {
        return ((IMyOrganizationRepository)OrganizationUnitRepository).GetCustomerAsync();
    }
}

Hi,

It has replaced the default tenant resolver and full compatible, If it is not CustomerDbContext it will fall back to the default resolver. If you use the repository infrastructure provided by abp, it should work seamlessly.

Hi,

This is just a simple example,

Identifying how to login a user via the mobile app using the ABP login API without prior knowledge of what tenant that user belongs to

It is not possible to log in to the application without knowing the tenant, because the user may be under any one of the tenants and may have the same user name. You need to determine the tenant when logging in.

You must have some rules for determining the tenant at login.

Hi, here is a simple example;

[ConnectionStringName("CustomerDbContext")]
public class CustomerDbContext : AbpDbContext<CustomerDbContext>
{
    ......
}
[Dependency(ReplaceServices = true)]
public class CustomConnectionStringResolver : MultiTenantConnectionStringResolver
{
    private readonly ICurrentUser _currentUser;

    private readonly IDistributedCache _distributedCache;
    public CustomConnectionStringResolver
        (IOptionsSnapshot<AbpDbConnectionOptions> options,
        ICurrentTenant currentTenant, IServiceProvider serviceProvider,
        ICurrentUser currentUser, IDistributedCache distributedCache) :
        base(options, currentTenant, serviceProvider)
    {
        _currentUser = currentUser;
        _distributedCache = distributedCache;
    }

    public override string Resolve(string connectionStringName = null)
    {
        if (connectionStringName != null && connectionStringName == "CustomerDbContext")
        {
            var connectionString = ResolveCustomConnectionString();
            if (!connectionString.IsNullOrWhiteSpace())
            {
                return connectionString;
            }
        }
        return base.Resolve(connectionStringName);
    }

    private string ResolveCustomConnectionString()
    {
        //query the custom connection string
        return _distributedCache.GetString(nameof(CustomConnectionStringResolver) + _currentUser.Name);
    }
}

Can you explain the case in details

May https://github.com/abpframework/abp-samples/tree/master/DocumentationSamples/CustomApplicationModules can help you.

Hi, here is a simple example:

public class EmailTenantResolveContributor : HttpTenantResolveContributorBase
{
    public override string Name => "Email";

    protected override string GetTenantIdOrNameFromHttpContextOrNull(ITenantResolveContext context,
        HttpContext httpContext)
    {
        if (httpContext.Request.HasFormContentType &&
            httpContext.Request.Path.Value.Contains("Account/Login", StringComparison.InvariantCultureIgnoreCase))
        {
            var email = (string) httpContext.Request.Form["LoginInput.UserNameOrEmailAddress"];
            if (email == null || !email.Contains("@"))
            {
                return null;
            }

            return email.Substring(email.IndexOf('@') + 1).Replace(".com", "");
        }

        return null;
    }
}

Add to your module class:

Configure<AbpTenantResolveOptions>(options =>
{
    options.TenantResolvers.Insert(0, new EmailTenantResolveContributor());
});

Hi,

  1. You can replace the favicon file in your wwwroot/iamges/favicon folder

  1. You can set the viewbag.title value to custom.

  1. You can replace the logo file in your wwwroot/logo folder.

  1. You need add the _ViewImports.cshtml file in your pages folder.
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bootstrap
@addTagHelper *, Volo.Abp.AspNetCore.Mvc.UI.Bundling

Here is login.cshtml content

@page
@using Microsoft.AspNetCore.Mvc.Localization
@using Volo.Abp.Account.Localization
@model Volo.Abp.Account.Public.Web.Pages.Account.LoginModel
@inject IHtmlLocalizer<AccountResource> L
@inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout
@{
    PageLayout.Content.Title = L["Login"].Value;
}

<div class="account-module-form">
    @if (Model.EnableLocalLogin)
    {
        <form method="post">
            <input asp-for="ReturnUrl"/>
            <input asp-for="ReturnUrlHash"/>
            <abp-input asp-for="LoginInput.UserNameOrEmailAddress" required-symbol="false"/>
            <abp-input asp-for="LoginInput.Password" required-symbol="false"/>
            <abp-row>
                <abp-column>
                    <abp-input asp-for="LoginInput.RememberMe" class="mb-4"/>
                </abp-column>
                <abp-column class="text-right">
                    <a href="@Url.Page("./ForgotPassword", new { returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash })">@L["ForgotPassword"]</a>
                </abp-column>
            </abp-row>
            <abp-button button-type="Primary" size="Block" type="submit" class="mt-2 mb-3" name="Action" value="Login">@L["Login"]</abp-button>
            @if (Model.ShowCancelButton)
            {
                <abp-button button-type="Secondary" size="Block" type="submit" formnovalidate="formnovalidate" class="mt-2 mb-3" name="Action" value="Cancel">@L["Cancel"]</abp-button>
            }
        </form>
        @if (Model.IsSelfRegistrationEnabled)
        {
            @L["NotAMemberYet"]
            <a href="@Url.Page("./Register", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})">@L["Register"]</a>
        }
    }

    @if (Model.VisibleExternalProviders.Any())
    {
        <hr/>
        @L["OrSignInWith"]<br/>
        <form asp-page="./Login" asp-page-handler="ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" asp-route-returnUrlHash="@Model.ReturnUrlHash" method="post">
            <input asp-for="ReturnUrl"/>
            <input asp-for="ReturnUrlHash"/>
            @foreach (var provider in Model.VisibleExternalProviders)
            {
                <button
                    type="submit"
                    class="mt-2 mr-2 btn btn-outline-primary btn-sm"
                    name="provider"
                    value="@provider.AuthenticationScheme"
                    data-busy-text="@L["ProcessingWithThreeDot"]">
                    @if (provider.Icon != null)
                    {
                        <i class="@provider.Icon"></i>
                    }
                    <span>@provider.DisplayName</span>
                </button>
            }
        </form>
    }

    @if (!Model.EnableLocalLogin && !Model.VisibleExternalProviders.Any())
    {
        <div class="alert alert-warning">
            <strong>Invalid login request</strong>
            There are no login schemes configured for this client.
        </div>
    }
</div>

Hi,

We are solving this problem, see https://github.com/abpframework/abp/issues/5215.

Hi,

Try:

[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(IIdentityUserAppService))]
public class MyIdentityUserAppService : IdentityUserAppService
{
    public MyIdentityUserAppService(IdentityUserManager userManager, IIdentityUserRepository userRepository, IIdentityRoleRepository roleRepository) : base(userManager, userRepository, roleRepository)
    {
    }

    [AllowAnonymous]
    public override async Task<IdentityUserDto> CreateAsync(IdentityUserCreateDto input)
    {
        var result = await base.CreateAsync(input);

        return result;
    }
}
Showing 2031 to 2040 of 2428 entries
Made with ❤️ on ABP v9.2.0-preview. Updated on January 24, 2025, 10:25