mirror of https://github.com/abpframework/abp.git
61 changed files with 571 additions and 173 deletions
@ -0,0 +1,43 @@ |
|||||
|
using System; |
||||
|
using Microsoft.AspNetCore.Components; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.WebAssembly |
||||
|
{ |
||||
|
public class AbpWebAssemblyConventionalRegistrar : ConventionalRegistrarBase |
||||
|
{ |
||||
|
public override void AddType(IServiceCollection services, Type type) |
||||
|
{ |
||||
|
if (IsConventionalRegistrationDisabled(type)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!IsComponent(type)) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
var serviceTypes = ExposedServiceExplorer.GetExposedServices(type); |
||||
|
|
||||
|
TriggerServiceExposing(services, type, serviceTypes); |
||||
|
|
||||
|
foreach (var serviceType in serviceTypes) |
||||
|
{ |
||||
|
services.Add( |
||||
|
ServiceDescriptor.Describe( |
||||
|
serviceType, |
||||
|
type, |
||||
|
ServiceLifetime.Transient |
||||
|
) |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static bool IsComponent(Type type) |
||||
|
{ |
||||
|
return typeof(ComponentBase).IsAssignableFrom(type); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using System.Collections.ObjectModel; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Alerts |
||||
|
{ |
||||
|
public class AlertList : ObservableCollection<AlertMessage> |
||||
|
{ |
||||
|
public void Add(AlertType type, string text, string title = null, bool dismissible = true) |
||||
|
{ |
||||
|
Add(new AlertMessage(type, text, title, dismissible)); |
||||
|
} |
||||
|
|
||||
|
public void Info(string text, string title = null, bool dismissible = true) |
||||
|
{ |
||||
|
Add(new AlertMessage(AlertType.Info, text, title, dismissible)); |
||||
|
} |
||||
|
|
||||
|
public void Warning(string text, string title = null, bool dismissible = true) |
||||
|
{ |
||||
|
Add(new AlertMessage(AlertType.Warning, text, title, dismissible)); |
||||
|
} |
||||
|
|
||||
|
public void Danger(string text, string title = null, bool dismissible = true) |
||||
|
{ |
||||
|
Add(new AlertMessage(AlertType.Danger, text, title, dismissible)); |
||||
|
} |
||||
|
|
||||
|
public void Success(string text, string title = null, bool dismissible = true) |
||||
|
{ |
||||
|
Add(new AlertMessage(AlertType.Success, text, title, dismissible)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Alerts |
||||
|
{ |
||||
|
public class AlertManager : IAlertManager, IScopedDependency |
||||
|
{ |
||||
|
public AlertList Alerts { get; } |
||||
|
|
||||
|
public AlertManager() |
||||
|
{ |
||||
|
Alerts = new AlertList(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,30 @@ |
|||||
|
using JetBrains.Annotations; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Alerts |
||||
|
{ |
||||
|
public class AlertMessage |
||||
|
{ |
||||
|
[NotNull] |
||||
|
public string Text |
||||
|
{ |
||||
|
get => _text; |
||||
|
set => _text = Check.NotNullOrWhiteSpace(value, nameof(value)); |
||||
|
} |
||||
|
private string _text; |
||||
|
|
||||
|
public AlertType Type { get; set; } |
||||
|
|
||||
|
[CanBeNull] |
||||
|
public string Title { get; set; } |
||||
|
|
||||
|
public bool Dismissible { get; set; } |
||||
|
|
||||
|
public AlertMessage(AlertType type, [NotNull] string text, string title = null, bool dismissible = true) |
||||
|
{ |
||||
|
Type = type; |
||||
|
Text = Check.NotNullOrWhiteSpace(text, nameof(text)); |
||||
|
Title = title; |
||||
|
Dismissible = dismissible; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Alerts |
||||
|
{ |
||||
|
public enum AlertType |
||||
|
{ |
||||
|
Default, |
||||
|
Primary, |
||||
|
Secondary, |
||||
|
Success, |
||||
|
Danger, |
||||
|
Warning, |
||||
|
Info, |
||||
|
Light, |
||||
|
Dark |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,7 @@ |
|||||
|
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Alerts |
||||
|
{ |
||||
|
public interface IAlertManager |
||||
|
{ |
||||
|
AlertList Alerts { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,32 @@ |
|||||
|
using System; |
||||
|
using Microsoft.AspNetCore.Components; |
||||
|
|
||||
|
namespace Volo.Abp.AspNetCore.Components.WebAssembly |
||||
|
{ |
||||
|
public class ServiceProviderComponentActivator : IComponentActivator |
||||
|
{ |
||||
|
public IServiceProvider ServiceProvider { get; } |
||||
|
|
||||
|
public ServiceProviderComponentActivator(IServiceProvider serviceProvider) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
} |
||||
|
|
||||
|
public IComponent CreateInstance(Type componentType) |
||||
|
{ |
||||
|
var instance = ServiceProvider.GetService(componentType); |
||||
|
|
||||
|
if (instance == null) |
||||
|
{ |
||||
|
instance = Activator.CreateInstance(componentType); |
||||
|
} |
||||
|
|
||||
|
if (!(instance is IComponent component)) |
||||
|
{ |
||||
|
throw new ArgumentException($"The type {componentType.FullName} does not implement {nameof(IComponent)}.", nameof(componentType)); |
||||
|
} |
||||
|
|
||||
|
return component; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,3 +1,3 @@ |
|||||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components |
@using Volo.Abp.Ui.Branding |
||||
@inject IBrandingProvider BrandingProvider |
@inject IBrandingProvider BrandingProvider |
||||
<a class="navbar-brand" href="~/">@BrandingProvider.AppName</a> |
<a class="navbar-brand" href="~/">@BrandingProvider.AppName</a> |
||||
|
|||||
@ -1,13 +0,0 @@ |
|||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components |
|
||||
{ |
|
||||
public class DefaultBrandingProvider : IBrandingProvider, ITransientDependency |
|
||||
{ |
|
||||
public virtual string AppName => "MyApplication"; |
|
||||
|
|
||||
public virtual string LogoUrl => null; |
|
||||
|
|
||||
public virtual string LogoReverseUrl => null; |
|
||||
} |
|
||||
} |
|
||||
@ -1,17 +0,0 @@ |
|||||
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components |
|
||||
{ |
|
||||
public interface IBrandingProvider |
|
||||
{ |
|
||||
string AppName { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Logo on white background
|
|
||||
/// </summary>
|
|
||||
string LogoUrl { get; } |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// Logo on dark background
|
|
||||
/// </summary>
|
|
||||
string LogoReverseUrl { get; } |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,10 @@ |
|||||
|
using Volo.Abp.AspNetCore.Components.WebAssembly.Alerts; |
||||
|
|
||||
|
namespace Volo.Abp.BlazoriseUI.Components |
||||
|
{ |
||||
|
internal class AlertWrapper |
||||
|
{ |
||||
|
public AlertMessage AlertMessage { get; set; } |
||||
|
public bool IsVisible { get; set; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,16 @@ |
|||||
|
@foreach (var alert in Alerts) |
||||
|
{ |
||||
|
<Alert Visible="@alert.IsVisible" Dismisable="@alert.AlertMessage.Dismissible" Color="@GetAlertColor(alert.AlertMessage.Type)"> |
||||
|
@if (!string.IsNullOrEmpty(alert.AlertMessage.Title)) |
||||
|
{ |
||||
|
<Heading Size="HeadingSize.Is4" Class="alert-heading"> |
||||
|
@alert.AlertMessage.Title |
||||
|
@if (alert.AlertMessage.Dismissible) |
||||
|
{ |
||||
|
<CloseButton Clicked="() => alert.IsVisible = false" /> |
||||
|
} |
||||
|
</Heading> |
||||
|
} |
||||
|
<Paragraph>@alert.AlertMessage.Text</Paragraph> |
||||
|
</Alert> |
||||
|
} |
||||
@ -0,0 +1,83 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Collections.Specialized; |
||||
|
using System.Linq; |
||||
|
using Blazorise; |
||||
|
using Microsoft.AspNetCore.Components; |
||||
|
using Microsoft.AspNetCore.Components.Routing; |
||||
|
using Volo.Abp.AspNetCore.Components.WebAssembly.Alerts; |
||||
|
|
||||
|
namespace Volo.Abp.BlazoriseUI.Components |
||||
|
{ |
||||
|
public partial class PageAlert : ComponentBase, IDisposable |
||||
|
{ |
||||
|
private List<AlertWrapper> Alerts = new List<AlertWrapper>(); |
||||
|
|
||||
|
[Inject] |
||||
|
protected IAlertManager AlertManager { get; set; } |
||||
|
|
||||
|
[Inject] |
||||
|
protected NavigationManager NavigationManager { get; set; } |
||||
|
|
||||
|
protected override void OnInitialized() |
||||
|
{ |
||||
|
base.OnInitialized(); |
||||
|
NavigationManager.LocationChanged += NavigationManager_LocationChanged; |
||||
|
AlertManager.Alerts.CollectionChanged += Alerts_CollectionChanged; |
||||
|
|
||||
|
Alerts.AddRange(AlertManager.Alerts.Select(t => new AlertWrapper |
||||
|
{ |
||||
|
AlertMessage = t, |
||||
|
IsVisible = true |
||||
|
})); |
||||
|
} |
||||
|
|
||||
|
//Since Blazor WASM doesn't support scoped dependency, we need to clear alerts on each location changed event.
|
||||
|
private void NavigationManager_LocationChanged(object sender, LocationChangedEventArgs e) |
||||
|
{ |
||||
|
AlertManager.Alerts.Clear(); |
||||
|
Alerts.Clear(); |
||||
|
} |
||||
|
|
||||
|
private void Alerts_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.Action == NotifyCollectionChangedAction.Add) |
||||
|
{ |
||||
|
foreach (var item in e.NewItems) |
||||
|
{ |
||||
|
Alerts.Add(new AlertWrapper |
||||
|
{ |
||||
|
AlertMessage = (AspNetCore.Components.WebAssembly.Alerts.AlertMessage)item, |
||||
|
IsVisible = true |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
StateHasChanged(); |
||||
|
} |
||||
|
|
||||
|
protected virtual Color GetAlertColor(AlertType alertType) |
||||
|
{ |
||||
|
var color = alertType switch |
||||
|
{ |
||||
|
AlertType.Info => Color.Info, |
||||
|
AlertType.Success => Color.Success, |
||||
|
AlertType.Warning => Color.Warning, |
||||
|
AlertType.Danger => Color.Danger, |
||||
|
AlertType.Dark => Color.Dark, |
||||
|
AlertType.Default => Color.None, |
||||
|
AlertType.Light => Color.Light, |
||||
|
AlertType.Primary => Color.Primary, |
||||
|
AlertType.Secondary => Color.Secondary, |
||||
|
_ => Color.None, |
||||
|
}; |
||||
|
|
||||
|
return color; |
||||
|
} |
||||
|
|
||||
|
public void Dispose() |
||||
|
{ |
||||
|
NavigationManager.LocationChanged -= NavigationManager_LocationChanged; |
||||
|
AlertManager.Alerts.CollectionChanged -= Alerts_CollectionChanged; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,9 +1,11 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
namespace Volo.Abp.MultiTenancy |
namespace Volo.Abp.MultiTenancy |
||||
{ |
{ |
||||
public interface ITenantResolveContributor |
public interface ITenantResolveContributor |
||||
{ |
{ |
||||
string Name { get; } |
string Name { get; } |
||||
|
|
||||
void Resolve(ITenantResolveContext context); |
Task ResolveAsync(ITenantResolveContext context); |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -1,10 +1,11 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
namespace Volo.Abp.MultiTenancy |
namespace Volo.Abp.MultiTenancy |
||||
{ |
{ |
||||
public abstract class TenantResolveContributorBase : ITenantResolveContributor |
public abstract class TenantResolveContributorBase : ITenantResolveContributor |
||||
{ |
{ |
||||
public abstract string Name { get; } |
public abstract string Name { get; } |
||||
|
|
||||
//TODO: We can make this async
|
public abstract Task ResolveAsync(ITenantResolveContext context); |
||||
public abstract void Resolve(ITenantResolveContext context); |
|
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,75 @@ |
|||||
|
using System.Linq; |
||||
|
using System.Security.Claims; |
||||
|
using System.Threading.Tasks; |
||||
|
using IdentityModel; |
||||
|
using Microsoft.AspNetCore.Identity; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Identity; |
||||
|
|
||||
|
namespace Volo.Abp.IdentityServer.AspNetIdentity |
||||
|
{ |
||||
|
public class AbpUserClaimsFactory<TUser> : IUserClaimsPrincipalFactory<TUser> |
||||
|
where TUser : class |
||||
|
{ |
||||
|
private readonly IObjectAccessor<IUserClaimsPrincipalFactory<TUser>> _inner; |
||||
|
private readonly UserManager<TUser> _userManager; |
||||
|
|
||||
|
public AbpUserClaimsFactory(IObjectAccessor<IUserClaimsPrincipalFactory<TUser>> inner, |
||||
|
UserManager<TUser> userManager) |
||||
|
{ |
||||
|
_inner = inner; |
||||
|
_userManager = userManager; |
||||
|
} |
||||
|
|
||||
|
public async Task<ClaimsPrincipal> CreateAsync(TUser user) |
||||
|
{ |
||||
|
var principal = await _inner.Value.CreateAsync(user); |
||||
|
var identity = principal.Identities.First(); |
||||
|
|
||||
|
if (!identity.HasClaim(x => x.Type == JwtClaimTypes.Subject)) |
||||
|
{ |
||||
|
var sub = await _userManager.GetUserIdAsync(user); |
||||
|
identity.AddIfNotContains(new Claim(JwtClaimTypes.Subject, sub)); |
||||
|
} |
||||
|
|
||||
|
var username = await _userManager.GetUserNameAsync(user); |
||||
|
var usernameClaim = identity.FindFirst(claim => |
||||
|
claim.Type == _userManager.Options.ClaimsIdentity.UserNameClaimType && claim.Value == username); |
||||
|
if (usernameClaim != null) |
||||
|
{ |
||||
|
identity.RemoveClaim(usernameClaim); |
||||
|
identity.AddIfNotContains(new Claim(JwtClaimTypes.PreferredUserName, username)); |
||||
|
} |
||||
|
|
||||
|
if (!identity.HasClaim(x => x.Type == JwtClaimTypes.Name)) |
||||
|
{ |
||||
|
identity.AddIfNotContains(new Claim(JwtClaimTypes.Name, username)); |
||||
|
} |
||||
|
|
||||
|
if (_userManager.SupportsUserEmail) |
||||
|
{ |
||||
|
var email = await _userManager.GetEmailAsync(user); |
||||
|
if (!string.IsNullOrWhiteSpace(email)) |
||||
|
{ |
||||
|
identity.AddIfNotContains(new Claim(JwtClaimTypes.Email, email)); |
||||
|
identity.AddIfNotContains(new Claim(JwtClaimTypes.EmailVerified, |
||||
|
await _userManager.IsEmailConfirmedAsync(user) ? "true" : "false", ClaimValueTypes.Boolean)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if (_userManager.SupportsUserPhoneNumber) |
||||
|
{ |
||||
|
var phoneNumber = await _userManager.GetPhoneNumberAsync(user); |
||||
|
if (!string.IsNullOrWhiteSpace(phoneNumber)) |
||||
|
{ |
||||
|
identity.AddIfNotContains(new Claim(JwtClaimTypes.PhoneNumber, phoneNumber)); |
||||
|
identity.AddIfNotContains(new Claim(JwtClaimTypes.PhoneNumberVerified, |
||||
|
await _userManager.IsPhoneNumberConfirmedAsync(user) ? "true" : "false", |
||||
|
ClaimValueTypes.Boolean)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return principal; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,18 +1 @@ |
|||||
#blazor-error-ui { |
|
||||
background: lightyellow; |
|
||||
bottom: 0; |
|
||||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); |
|
||||
display: none; |
|
||||
left: 0; |
|
||||
padding: 0.6rem 1.25rem 0.7rem 1.25rem; |
|
||||
position: fixed; |
|
||||
width: 100%; |
|
||||
z-index: 1000; |
|
||||
} |
|
||||
|
|
||||
#blazor-error-ui .dismiss { |
|
||||
cursor: pointer; |
|
||||
position: absolute; |
|
||||
right: 0.75rem; |
|
||||
top: 0.5rem; |
|
||||
} |
|
||||
Loading…
Reference in new issue