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,
viewbag.title
value to custom._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;
}
}