[Identity] Move to use static web assets support. (#11029)
* Moves Identity UI to use Static Web Assets * Removes the static files as embedded content. * Stops plugging the static assets through the embedded file provider. * Selects the UI framework at build time instead of runtime.
This commit is contained in:
parent
7a496ec162
commit
143c101693
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"solution": {
|
||||
"path": "Identity.sln",
|
||||
"projects": [
|
||||
"ApiAuthorization.IdentityServer\\samples\\ApiAuthSample\\ApiAuthSample.csproj",
|
||||
"ApiAuthorization.IdentityServer\\src\\Microsoft.AspNetCore.ApiAuthorization.IdentityServer.csproj",
|
||||
"ApiAuthorization.IdentityServer\\test\\Microsoft.AspNetCore.ApiAuthorization.IdentityServer.Tests.csproj",
|
||||
"Core\\src\\Microsoft.AspNetCore.Identity.csproj",
|
||||
"EntityFrameworkCore\\src\\Microsoft.AspNetCore.Identity.EntityFrameworkCore.csproj",
|
||||
"EntityFrameworkCore\\test\\EF.InMemory.Test\\Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test.csproj",
|
||||
"EntityFrameworkCore\\test\\EF.Test\\Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test.csproj",
|
||||
"Extensions.Core\\src\\Microsoft.Extensions.Identity.Core.csproj",
|
||||
"Extensions.Stores\\src\\Microsoft.Extensions.Identity.Stores.csproj",
|
||||
"Specification.Tests\\src\\Microsoft.AspNetCore.Identity.Specification.Tests.csproj",
|
||||
"UI\\src\\Microsoft.AspNetCore.Identity.UI.csproj",
|
||||
"samples\\IdentitySample.DefaultUI\\IdentitySample.DefaultUI.csproj",
|
||||
"samples\\IdentitySample.Mvc\\IdentitySample.Mvc.csproj",
|
||||
"test\\Identity.FunctionalTests\\Microsoft.AspNetCore.Identity.FunctionalTests.csproj",
|
||||
"test\\Identity.Test\\Microsoft.AspNetCore.Identity.Test.csproj",
|
||||
"test\\InMemory.Test\\Microsoft.AspNetCore.Identity.InMemory.Test.csproj",
|
||||
"testassets\\Identity.DefaultUI.WebSite\\Identity.DefaultUI.WebSite.csproj"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -6,20 +6,15 @@ namespace Microsoft.AspNetCore.Identity
|
|||
public static partial class IdentityBuilderUIExtensions
|
||||
{
|
||||
public static Microsoft.AspNetCore.Identity.IdentityBuilder AddDefaultUI(this Microsoft.AspNetCore.Identity.IdentityBuilder builder) { throw null; }
|
||||
public static Microsoft.AspNetCore.Identity.IdentityBuilder AddDefaultUI(this Microsoft.AspNetCore.Identity.IdentityBuilder builder, Microsoft.AspNetCore.Identity.UI.UIFramework framework) { throw null; }
|
||||
}
|
||||
}
|
||||
namespace Microsoft.AspNetCore.Identity.UI
|
||||
{
|
||||
public partial class DefaultUIOptions
|
||||
[System.AttributeUsageAttribute(System.AttributeTargets.Assembly, Inherited=false, AllowMultiple=false)]
|
||||
public sealed partial class UIFrameworkAttribute : System.Attribute
|
||||
{
|
||||
public DefaultUIOptions() { }
|
||||
public Microsoft.AspNetCore.Identity.UI.UIFramework UIFramework { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } [System.Runtime.CompilerServices.CompilerGeneratedAttribute]set { } }
|
||||
}
|
||||
public enum UIFramework
|
||||
{
|
||||
Bootstrap3 = 0,
|
||||
Bootstrap4 = 1,
|
||||
public UIFrameworkAttribute(string uiFramework) { }
|
||||
public string UIFramework { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
}
|
||||
}
|
||||
namespace Microsoft.AspNetCore.Identity.UI.Services
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Options for the default Identity UI
|
||||
/// </summary>
|
||||
public class DefaultUIOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="UIFramework"/> to use with the default UI.
|
||||
/// </summary>
|
||||
public UIFramework UIFramework { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity.UI;
|
||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationModels;
|
||||
|
|
@ -30,35 +31,16 @@ namespace Microsoft.AspNetCore.Identity
|
|||
/// </remarks>
|
||||
/// <param name="builder">The <see cref="IdentityBuilder"/>.</param>
|
||||
/// <returns>The <see cref="IdentityBuilder"/>.</returns>
|
||||
public static IdentityBuilder AddDefaultUI(this IdentityBuilder builder) => builder.AddDefaultUI(UIFramework.Bootstrap4);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds a default, self-contained UI for Identity to the application using
|
||||
/// Razor Pages in an area named Identity.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// In order to use the default UI, the application must be using <see cref="Microsoft.AspNetCore.Mvc"/>,
|
||||
/// <see cref="Microsoft.AspNetCore.StaticFiles"/> and contain a <c>_LoginPartial</c> partial view that
|
||||
/// can be found by the application.
|
||||
/// </remarks>
|
||||
/// <param name="builder">The <see cref="IdentityBuilder"/>.</param>
|
||||
/// <param name="framework">The <see cref="UIFramework"/>.</param>
|
||||
/// <returns>The <see cref="IdentityBuilder"/>.</returns>
|
||||
public static IdentityBuilder AddDefaultUI(
|
||||
this IdentityBuilder builder,
|
||||
UIFramework framework)
|
||||
public static IdentityBuilder AddDefaultUI(this IdentityBuilder builder)
|
||||
{
|
||||
builder.AddSignInManager();
|
||||
AddRelatedParts(builder, framework);
|
||||
AddRelatedParts(builder);
|
||||
|
||||
builder.Services.ConfigureOptions(
|
||||
typeof(IdentityDefaultUIConfigureOptions<>)
|
||||
.MakeGenericType(builder.UserType));
|
||||
builder.Services.TryAddTransient<IEmailSender, EmailSender>();
|
||||
|
||||
builder.Services.Configure<DefaultUIOptions>(o => o.UIFramework = framework);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
|
@ -69,8 +51,20 @@ namespace Microsoft.AspNetCore.Identity
|
|||
[UIFramework.Bootstrap4] = "Microsoft.AspNetCore.Identity.UI.Views.V4",
|
||||
};
|
||||
|
||||
private static void AddRelatedParts(IdentityBuilder builder, UIFramework framework)
|
||||
private static void AddRelatedParts(IdentityBuilder builder)
|
||||
{
|
||||
// We try to resolve the UI framework that was used by looking at the entry assembly.
|
||||
// When an app runs, the entry assembly will point to the built app. In some rare cases
|
||||
// (functional testing) the app assembly will be different, and we'll try to locate it through
|
||||
// the same mechanism that MVC uses today.
|
||||
// Finally, if for some reason we aren't able to find the assembly, we'll use our default value
|
||||
// (Bootstrap4)
|
||||
if (!TryResolveUIFramework(Assembly.GetEntryAssembly(), out var framework) ||
|
||||
!TryResolveUIFramework(GetApplicationAssembly(builder), out framework))
|
||||
{
|
||||
framework = default;
|
||||
}
|
||||
|
||||
var mvcBuilder = builder.Services
|
||||
.AddMvc()
|
||||
.ConfigureApplicationPartManager(partManager =>
|
||||
|
|
@ -131,5 +125,38 @@ namespace Microsoft.AspNetCore.Identity
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static Assembly GetApplicationAssembly(IdentityBuilder builder)
|
||||
{
|
||||
// Whis is the same logic that MVC follows to find the application assembly.
|
||||
var environment = builder.Services.Where(d => d.ServiceType == typeof(IWebHostEnvironment)).ToArray();
|
||||
var applicationName = ((IWebHostEnvironment)environment.LastOrDefault()?.ImplementationInstance)
|
||||
.ApplicationName;
|
||||
|
||||
var appAssembly = Assembly.Load(applicationName);
|
||||
return appAssembly;
|
||||
}
|
||||
|
||||
private static bool TryResolveUIFramework(Assembly assembly, out UIFramework uiFramework)
|
||||
{
|
||||
uiFramework = default;
|
||||
|
||||
var metadata = assembly.GetCustomAttributes<UIFrameworkAttribute>()
|
||||
.SingleOrDefault()?.UIFramework; // Bootstrap4 is the default
|
||||
if (metadata == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// If we find the metadata there must be a valid framework here.
|
||||
if (!Enum.TryParse<UIFramework>(metadata, ignoreCase: true, out var uIFramework))
|
||||
{
|
||||
var enumValues = string.Join(", ", Enum.GetNames(typeof(UIFramework)).Select(v => $"'{v}'"));
|
||||
throw new InvalidOperationException(
|
||||
$"Found an invalid value for the 'IdentityUIFrameworkVersion'. Valid values are {enumValues}");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,34 +3,26 @@
|
|||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Identity.UI.Areas.Identity.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.StaticFiles;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI
|
||||
{
|
||||
internal class IdentityDefaultUIConfigureOptions<TUser> :
|
||||
IPostConfigureOptions<RazorPagesOptions>,
|
||||
IPostConfigureOptions<StaticFileOptions>,
|
||||
IConfigureNamedOptions<CookieAuthenticationOptions> where TUser : class
|
||||
{
|
||||
private const string IdentityUIDefaultAreaName = "Identity";
|
||||
|
||||
public IdentityDefaultUIConfigureOptions(
|
||||
IWebHostEnvironment environment,
|
||||
IOptions<DefaultUIOptions> uiOptions)
|
||||
{
|
||||
IWebHostEnvironment environment) {
|
||||
Environment = environment;
|
||||
UiOptions = uiOptions;
|
||||
}
|
||||
|
||||
public IWebHostEnvironment Environment { get; }
|
||||
public IOptions<DefaultUIOptions> UiOptions { get; }
|
||||
|
||||
public void PostConfigure(string name, RazorPagesOptions options)
|
||||
{
|
||||
|
|
@ -50,30 +42,10 @@ namespace Microsoft.AspNetCore.Identity.UI
|
|||
pam => pam.Filters.Add(new ExternalLoginsPageFilter<TUser>()));
|
||||
}
|
||||
|
||||
public void PostConfigure(string name, StaticFileOptions options)
|
||||
{
|
||||
name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
options = options ?? throw new ArgumentNullException(nameof(options));
|
||||
|
||||
// Basic initialization in case the options weren't initialized by any other component
|
||||
options.ContentTypeProvider = options.ContentTypeProvider ?? new FileExtensionContentTypeProvider();
|
||||
if (options.FileProvider == null && Environment.WebRootFileProvider == null)
|
||||
{
|
||||
throw new InvalidOperationException("Missing FileProvider.");
|
||||
}
|
||||
|
||||
options.FileProvider = options.FileProvider ?? Environment.WebRootFileProvider;
|
||||
|
||||
var basePath = UiOptions.Value.UIFramework == UIFramework.Bootstrap3 ? "wwwroot/V3" :
|
||||
"wwwroot/V4";
|
||||
|
||||
// Add our provider
|
||||
var filesProvider = new ManifestEmbeddedFileProvider(GetType().Assembly, basePath);
|
||||
options.FileProvider = new CompositeFileProvider(options.FileProvider, filesProvider);
|
||||
public void Configure(CookieAuthenticationOptions options) {
|
||||
// Nothing to do here as Configure(string name, CookieAuthenticationOptions options) is hte one setting things up.
|
||||
}
|
||||
|
||||
public void Configure(CookieAuthenticationOptions options) { }
|
||||
|
||||
public void Configure(string name, CookieAuthenticationOptions options)
|
||||
{
|
||||
name = name ?? throw new ArgumentNullException(nameof(name));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Razor">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>ASP.NET Core Identity UI is the default Razor Pages built-in UI for the ASP.NET Core Identity framework.</Description>
|
||||
|
|
@ -7,23 +7,30 @@
|
|||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
<PackageTags>aspnetcore;identity;membership;razorpages</PackageTags>
|
||||
<IsShippingPackage>true</IsShippingPackage>
|
||||
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
|
||||
<ProvideApplicationPartFactoryAttributeTypeName>Microsoft.AspNetCore.Mvc.ApplicationParts.NullApplicationPartFactory, Microsoft.AspNetCore.Mvc.Core</ProvideApplicationPartFactoryAttributeTypeName>
|
||||
<RazorCompileOnBuild>false</RazorCompileOnBuild>
|
||||
<RazorCompileOnPublish>false</RazorCompileOnPublish>
|
||||
<EnableDefaultRazorGenerateItems>false</EnableDefaultRazorGenerateItems>
|
||||
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
|
||||
<AddRazorSupportForMvc>true</AddRazorSupportForMvc>
|
||||
|
||||
<DisableStaticWebAssetsBuildPropsFileGeneration>true</DisableStaticWebAssetsBuildPropsFileGeneration>
|
||||
<StaticWebAssetsDisableProjectBuildPropsFileGeneration>true</StaticWebAssetsDisableProjectBuildPropsFileGeneration>
|
||||
|
||||
<GetCurrentProjectStaticWebAssetsDependsOn>
|
||||
$(GetCurrentProjectStaticWebAssetsDependsOn);
|
||||
_UpdatedIdentityUIStaticWebAssets
|
||||
</GetCurrentProjectStaticWebAssetsDependsOn>
|
||||
|
||||
<IdentityUIFrameworkVersion Condition="'$(IdentityUIFrameworkVersion)' == ''">Bootstrap4</IdentityUIFrameworkVersion>
|
||||
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="wwwroot/**/*" />
|
||||
<EmbeddedResource Remove="wwwroot/**/LICENSE*" />
|
||||
<None Remove="wwwroot/**/LICENSE*" />
|
||||
<Content Remove="@(Content)" />
|
||||
<Content Include="wwwroot\**\*" Pack="true" />
|
||||
<None Include="build\*" Pack="true" PackagePath="build\" />
|
||||
<None Include="THIRD-PARTY-NOTICES.txt" Pack="true" PackagePath="/THIRD-PARTY-NOTICES.txt" />
|
||||
|
||||
<Content Update="wwwroot/**/*" Pack="false" />
|
||||
<Content Update="**\*.cshtml" Pack="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -40,6 +47,10 @@
|
|||
<UIFrameworkVersionMoniker Include="V4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="build\" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Source build doesn't build this package -->
|
||||
<Target Name="BuildRazorViews" DependsOnTargets="Compile" BeforeTargets="Build" Condition="'$(DotNetBuildFromSource)' != 'true'">
|
||||
<Message Text="Building razor views assemblies" Importance="High" />
|
||||
|
|
@ -63,6 +74,7 @@
|
|||
|
||||
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||
<Output TaskParameter="DestinationFiles" ItemName="_RazorAssembly"/>
|
||||
|
||||
</Copy>
|
||||
|
||||
<Copy
|
||||
|
|
@ -75,12 +87,10 @@
|
|||
UseHardlinksIfPossible="$(CreateHardLinksForCopyFilesToOutputDirectoryIfPossible)"
|
||||
UseSymboliclinksIfPossible="$(CreateSymbolicLinksForCopyFilesToOutputDirectoryIfPossible)">
|
||||
|
||||
<Output TaskParameter="DestinationFiles" ItemName="FileWrites"/>
|
||||
<Output TaskParameter="DestinationFiles" ItemName="FileWrites" />
|
||||
</Copy>
|
||||
|
||||
<Message
|
||||
Importance="High"
|
||||
Text="$(MSBuildProjectName) -> %(_RazorAssembly.FullPath)" />
|
||||
<Message Importance="High" Text="$(MSBuildProjectName) -> %(_RazorAssembly.FullPath)" />
|
||||
|
||||
</Target>
|
||||
|
||||
|
|
@ -90,19 +100,15 @@
|
|||
|
||||
<Target Name="SetupRazorInputs">
|
||||
<ItemGroup>
|
||||
<_RazorGenerate
|
||||
Include="Areas\Identity\Pages\$(UIFrameworkVersion)\**\*.cshtml" />
|
||||
<_RazorGenerate Include="Areas\Identity\Pages\$(UIFrameworkVersion)\**\*.cshtml" />
|
||||
|
||||
<RazorGenerate
|
||||
Include="@(_RazorGenerate)"
|
||||
Link="Areas\Identity\Pages\%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
<RazorGenerate Include="@(_RazorGenerate)" Link="Areas\Identity\Pages\%(RecursiveDir)%(Filename)%(Extension)" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="BuildForUI" DependsOnTargets="SetupRazorInputs;RazorCompile" />
|
||||
|
||||
<Target
|
||||
Name="_GetRazorDlls" BeforeTargets="GetCopyToOutputDirectoryItems">
|
||||
<Target Name="_GetRazorDlls" BeforeTargets="GetCopyToOutputDirectoryItems">
|
||||
|
||||
<ItemGroup>
|
||||
<_GeneratedRazorViews Include="$(TargetDir)$(TargetName).Views.%(UIFrameworkVersionMoniker.Identity).dll" />
|
||||
|
|
@ -117,15 +123,13 @@
|
|||
|
||||
<Target Name="_AddRazorDlls" BeforeTargets="BuiltProjectOutputGroup">
|
||||
<ItemGroup>
|
||||
<BuiltProjectOutputGroupOutput
|
||||
Include="$(IntermediateOutputPath)%(UIFrameworkVersionMoniker.Identity)\$(TargetName).Views.%(UIFrameworkVersionMoniker.Identity).dll" />
|
||||
<BuiltProjectOutputGroupOutput Include="$(IntermediateOutputPath)%(UIFrameworkVersionMoniker.Identity)\$(TargetName).Views.%(UIFrameworkVersionMoniker.Identity).dll" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="_AddRazorPdbs" BeforeTargets="DebugSymbolsProjectOutputGroup">
|
||||
<ItemGroup>
|
||||
<DebugSymbolsProjectOutputGroupOutput
|
||||
Include="$(IntermediateOutputPath)%(UIFrameworkVersionMoniker.Identity)\$(TargetName).Views.%(UIFrameworkVersionMoniker.Identity).pdb" />
|
||||
<DebugSymbolsProjectOutputGroupOutput Include="$(IntermediateOutputPath)%(UIFrameworkVersionMoniker.Identity)\$(TargetName).Views.%(UIFrameworkVersionMoniker.Identity).pdb" />
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
|
|
@ -136,8 +140,34 @@
|
|||
<ExpectedOutputFile Include="$(TargetDir)Microsoft.AspNetCore.Identity.UI.Views.V4.dll" />
|
||||
</ItemGroup>
|
||||
|
||||
<Error Text="Unable to find precompiled view file %(ExpectedOutputFile.Identity)"
|
||||
Condition="!Exists('%(ExpectedOutputFile.Identity)')" />
|
||||
<Error Text="Unable to find precompiled view file %(ExpectedOutputFile.Identity)" Condition="!Exists('%(ExpectedOutputFile.Identity)')" />
|
||||
</Target>
|
||||
|
||||
<Target Name="_UpdatedIdentityUIStaticWebAssets">
|
||||
|
||||
<ItemGroup>
|
||||
<StaticWebAsset Remove="@(StaticWebAsset)" />
|
||||
|
||||
<_V3Content Include="wwwroot\V3\**" />
|
||||
<_V4Content Include="wwwroot\V4\**" />
|
||||
|
||||
<StaticWebAsset Include="@(_V3Content->'%(FullPath)')" Condition="'$(IdentityUIFrameworkVersion)' == 'Bootstrap3'">
|
||||
<SourceType></SourceType>
|
||||
<SourceId>Microsoft.AspNetCore.Identity.UI</SourceId>
|
||||
<ContentRoot>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)wwwroot/V3'))</ContentRoot>
|
||||
<BasePath>/Identity</BasePath>
|
||||
<RelativePath>%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
|
||||
</StaticWebAsset>
|
||||
|
||||
<StaticWebAsset Include="@(_V4Content->'%(FullPath)')" Condition="'$(IdentityUIFrameworkVersion)' == 'Bootstrap4'">
|
||||
<SourceType></SourceType>
|
||||
<SourceId>Microsoft.AspNetCore.Identity.UI</SourceId>
|
||||
<ContentRoot>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)wwwroot/V4'))</ContentRoot>
|
||||
<BasePath>/Identity</BasePath>
|
||||
<RelativePath>%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
|
||||
</StaticWebAsset>
|
||||
</ItemGroup>
|
||||
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,21 +1,13 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of supported presentation frameworks for the default UI
|
||||
/// </summary>
|
||||
public enum UIFramework
|
||||
internal enum UIFramework
|
||||
{
|
||||
/// <summary>
|
||||
/// Bootstrap 3
|
||||
/// </summary>
|
||||
Bootstrap3 = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Bootstrap 4
|
||||
/// </summary>
|
||||
Bootstrap4 = 1
|
||||
// The default framework for a given release must be 0.
|
||||
// So this needs to be updated in the future if we include more frameworks.
|
||||
Bootstrap4 = 0,
|
||||
Bootstrap3 = 1,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,29 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// The UIFramework Identity UI will use on the application.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Assembly, Inherited = false, AllowMultiple = false)]
|
||||
public sealed class UIFrameworkAttribute : Attribute
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of <see cref="UIFrameworkAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="uiFramework"></param>
|
||||
public UIFrameworkAttribute(string uiFramework)
|
||||
{
|
||||
UIFramework = uiFramework;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The UI Framework Identity UI will use.
|
||||
/// </summary>
|
||||
public string UIFramework { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<Project>
|
||||
<PropertyGroup>
|
||||
<IdentityUIFrameworkVersion Condition="'$(IdentityUIFrameworkVersion)' == ''">Bootstrap4</IdentityUIFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="Microsoft.AspNetCore.Identity.UI.UIFrameworkAttribute">
|
||||
<_Parameter1>$(IdentityUIFrameworkVersion)</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(IdentityUIFrameworkVersion)' == 'Bootstrap3'">
|
||||
<StaticWebAsset Include="$(MSBuildThisFileDirectory)..\staticwebassets\V3\**">
|
||||
<SourceType>Package</SourceType>
|
||||
<SourceId>Microsoft.AspNetCore.Identity.UI</SourceId>
|
||||
<ContentRoot>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\staticwebassets\V3'))</ContentRoot>
|
||||
<BasePath>/Identity</BasePath>
|
||||
<RelativePath>%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
|
||||
</StaticWebAsset>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition="'$(IdentityUIFrameworkVersion)' == 'Bootstrap4'">
|
||||
<StaticWebAsset Include="$(MSBuildThisFileDirectory)..\staticwebassets\V4\**">
|
||||
<SourceType>Package</SourceType>
|
||||
<SourceId>Microsoft.AspNetCore.Identity.UI</SourceId>
|
||||
<ContentRoot>$([MSBuild]::NormalizePath('$(MSBuildThisFileDirectory)..\staticwebassets\V4'))</ContentRoot>
|
||||
<BasePath>/Identity</BasePath>
|
||||
<RelativePath>%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
|
||||
</StaticWebAsset>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
|
|
@ -1,3 +0,0 @@
|
|||
@{
|
||||
Layout = "/Views/Shared/_Layout.cshtml";
|
||||
}
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<Description>Identity sample MVC application on ASP.NET Core using the default UI</Description>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<UserSecretsId>aspnetcore-2ff9bc27-5e8c-4484-90ca-e3aace89b72a</UserSecretsId>
|
||||
<IdentityUIFrameworkVersion>Bootstrap4</IdentityUIFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.AspNetCore" />
|
||||
<Reference Include="Microsoft.AspNetCore.Authentication.Facebook" />
|
||||
<Reference Include="Microsoft.AspNetCore.Authentication.Google" />
|
||||
<Reference Include="Microsoft.AspNetCore.Authentication.Twitter" />
|
||||
|
|
@ -26,6 +28,7 @@
|
|||
<Reference Include="Microsoft.EntityFrameworkCore.Tools" PrivateAssets="All" />
|
||||
<Reference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
|
||||
<Reference Include="Microsoft.Extensions.Configuration.UserSecrets" />
|
||||
<Reference Include="Microsoft.Extensions.Hosting" />
|
||||
<Reference Include="Microsoft.Extensions.Logging.Console" />
|
||||
<Reference Include="Microsoft.Extensions.Logging.Debug" />
|
||||
</ItemGroup>
|
||||
|
|
@ -34,4 +37,23 @@
|
|||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
|
||||
<!-- Include an assembly attribute into the built application assembly to indicate which flavor of the UI framework to use -->
|
||||
<ItemGroup>
|
||||
<AssemblyAttribute Include="Microsoft.AspNetCore.Identity.UI.UIFrameworkAttribute">
|
||||
<_Parameter1>$(IdentityUIFrameworkVersion)</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ResolveStaticWebAssetsInputsDependsOn>_SetBootstrapFrameworkVersion</ResolveStaticWebAssetsInputsDependsOn>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="_SetBootstrapFrameworkVersion">
|
||||
<ItemGroup>
|
||||
<_StaticWebAssetsProjectReference Condition="'%(FileName)' == 'Microsoft.AspNetCore.identity.UI'">
|
||||
<AdditionalProperties>IdentityUIFrameworkVersion=$(IdentityUIFrameworkVersion)</AdditionalProperties>
|
||||
</_StaticWebAssetsProjectReference>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.IO;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace IdentitySample.DefaultUI
|
||||
{
|
||||
|
|
@ -7,17 +8,19 @@ namespace IdentitySample.DefaultUI
|
|||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var host = CreateWebHostBuilder(args)
|
||||
.Build();
|
||||
|
||||
host.Run();
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
new WebHostBuilder()
|
||||
.UseKestrel()
|
||||
.UseContentRoot(Directory.GetCurrentDirectory())
|
||||
.UseIISIntegration()
|
||||
.UseStartup<Startup>();
|
||||
public static bool UseStartup { get; set; } = true;
|
||||
|
||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
if (UseStartup)
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Identity.DefaultUI.WebSite;
|
||||
|
|
@ -6,10 +6,11 @@ using Identity.DefaultUI.WebSite.Data;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.IdentityUserTests
|
||||
{
|
||||
public class Bootstrap3AuthorizationTests : AuthorizationTests<Bootstrap3Startup, ApplicationDbContext>
|
||||
public class Bootstrap3AuthorizationTests : AuthorizationTests<ApplicationUserStartup, ApplicationDbContext>
|
||||
{
|
||||
public Bootstrap3AuthorizationTests(ServerFactory<Bootstrap3Startup, ApplicationDbContext> serverFactory) : base(serverFactory)
|
||||
public Bootstrap3AuthorizationTests(ServerFactory<ApplicationUserStartup, ApplicationDbContext> serverFactory) : base(serverFactory)
|
||||
{
|
||||
serverFactory.BootstrapFrameworkVersion = "V3";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Identity.DefaultUI.WebSite;
|
||||
|
|
@ -6,10 +6,11 @@ using Identity.DefaultUI.WebSite.Data;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Bootstrap3Tests
|
||||
{
|
||||
public class Bootstrap3ManagementTests : ManagementTests<Bootstrap3Startup, ApplicationDbContext>
|
||||
public class Bootstrap3ManagementTests : ManagementTests<ApplicationUserStartup, ApplicationDbContext>
|
||||
{
|
||||
public Bootstrap3ManagementTests(ServerFactory<Bootstrap3Startup, ApplicationDbContext> serverFactory) : base(serverFactory)
|
||||
public Bootstrap3ManagementTests(ServerFactory<ApplicationUserStartup, ApplicationDbContext> serverFactory) : base(serverFactory)
|
||||
{
|
||||
serverFactory.BootstrapFrameworkVersion = "V3";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Identity.DefaultUI.WebSite;
|
||||
|
|
@ -6,10 +6,11 @@ using Identity.DefaultUI.WebSite.Data;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Bootstrap3Tests
|
||||
{
|
||||
public class Bootstrap3RegistrationTests : RegistrationTests<Bootstrap3Startup, ApplicationDbContext>
|
||||
public class Bootstrap3RegistrationTests : RegistrationTests<ApplicationUserStartup, ApplicationDbContext>
|
||||
{
|
||||
public Bootstrap3RegistrationTests(ServerFactory<Bootstrap3Startup, ApplicationDbContext> serverFactory) : base(serverFactory)
|
||||
public Bootstrap3RegistrationTests(ServerFactory<ApplicationUserStartup, ApplicationDbContext> serverFactory) : base(serverFactory)
|
||||
{
|
||||
serverFactory.BootstrapFrameworkVersion = "V3";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Identity.DefaultUI.WebSite;
|
||||
|
|
@ -6,10 +6,11 @@ using Identity.DefaultUI.WebSite.Data;
|
|||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests.Bootstrap3Tests
|
||||
{
|
||||
public class Bootstrap3LoginTests : LoginTests<Bootstrap3Startup, ApplicationDbContext>
|
||||
public class Bootstrap3LoginTests : LoginTests<ApplicationUserStartup, ApplicationDbContext>
|
||||
{
|
||||
public Bootstrap3LoginTests(ServerFactory<Bootstrap3Startup, ApplicationDbContext> serverFactory) : base(serverFactory)
|
||||
public Bootstrap3LoginTests(ServerFactory<ApplicationUserStartup, ApplicationDbContext> serverFactory) : base(serverFactory)
|
||||
{
|
||||
serverFactory.BootstrapFrameworkVersion = "V3";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,19 +2,26 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Identity.DefaultUI.WebSite;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Hosting.StaticWebAssets;
|
||||
using Microsoft.AspNetCore.Identity.UI;
|
||||
using Microsoft.AspNetCore.Mvc.ApplicationParts;
|
||||
using Microsoft.AspNetCore.Mvc.Testing;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Data.Sqlite;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
||||
{
|
||||
public class ServerFactory<TStartup,TContext>: WebApplicationFactory<TStartup>
|
||||
public class ServerFactory<TStartup, TContext> : WebApplicationFactory<TStartup>
|
||||
where TStartup : class
|
||||
where TContext : DbContext
|
||||
{
|
||||
|
|
@ -29,6 +36,10 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
ClientOptions.BaseAddress = new Uri("https://localhost");
|
||||
}
|
||||
|
||||
public string BootstrapFrameworkVersion { get; set; } = "V4";
|
||||
private bool IsHelixCI => typeof(ServerFactory<,>).Assembly.GetCustomAttributes<AssemblyMetadataAttribute>()
|
||||
.Any(a => a.Key == "Microsoft.AspNetCore.Testing.IsHelixCI");
|
||||
|
||||
protected override IHostBuilder CreateHostBuilder()
|
||||
{
|
||||
Program.UseStartup = false;
|
||||
|
|
@ -48,6 +59,70 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
// several places to pass important data in post-redirect-get flows.
|
||||
.AddCookieTempDataProvider(o => o.Cookie.IsEssential = true);
|
||||
});
|
||||
|
||||
UpdateStaticAssets(builder);
|
||||
UpdateApplicationParts(builder);
|
||||
}
|
||||
|
||||
private void UpdateApplicationParts(IWebHostBuilder builder) =>
|
||||
builder.ConfigureServices(services => AddRelatedParts(services, BootstrapFrameworkVersion));
|
||||
|
||||
private void UpdateStaticAssets(IWebHostBuilder builder)
|
||||
{
|
||||
var manifestPath = Path.GetDirectoryName(new Uri(typeof(ServerFactory<,>).Assembly.CodeBase).LocalPath);
|
||||
builder.ConfigureAppConfiguration((ctx, cb) =>
|
||||
{
|
||||
if (ctx.HostingEnvironment.WebRootFileProvider is CompositeFileProvider composite)
|
||||
{
|
||||
var originalWebRoot = composite.FileProviders.First();
|
||||
ctx.HostingEnvironment.WebRootFileProvider = originalWebRoot;
|
||||
}
|
||||
});
|
||||
|
||||
string versionedPath = Path.Combine(manifestPath, $"Testing.DefaultWebSite.StaticWebAssets.{BootstrapFrameworkVersion}.xml");
|
||||
UpdateManifest(versionedPath);
|
||||
|
||||
builder.ConfigureAppConfiguration((context, configBuilder) =>
|
||||
{
|
||||
using (var manifest = File.OpenRead(versionedPath))
|
||||
{
|
||||
typeof(StaticWebAssetsLoader)
|
||||
.GetMethod("UseStaticWebAssetsCore", BindingFlags.NonPublic | BindingFlags.Static)
|
||||
.Invoke(null, new object[] { context.HostingEnvironment, manifest });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void UpdateManifest(string versionedPath)
|
||||
{
|
||||
var content = File.ReadAllText(versionedPath);
|
||||
var path = typeof(ServerFactory<,>).Assembly.GetCustomAttributes<AssemblyMetadataAttribute>()
|
||||
.Single(a => a.Key == "Microsoft.AspNetCore.Testing.IdentityUIProjectPath").Value;
|
||||
|
||||
path = Directory.Exists(path) ? Path.Combine(path, "wwwroot") : Path.Combine(FindHelixSlnFileDirectory(), "UI", "wwwroot");
|
||||
|
||||
var updatedContent = content.Replace("{TEST_PLACEHOLDER}", path);
|
||||
|
||||
File.WriteAllText(versionedPath, updatedContent);
|
||||
}
|
||||
|
||||
private string FindHelixSlnFileDirectory()
|
||||
{
|
||||
var applicationPath = Path.GetDirectoryName(typeof(ServerFactory<,>).Assembly.Location);
|
||||
var directoryInfo = new DirectoryInfo(applicationPath);
|
||||
do
|
||||
{
|
||||
var solutionPath = Directory.EnumerateFiles(directoryInfo.FullName, "*.sln").FirstOrDefault();
|
||||
if (solutionPath != null)
|
||||
{
|
||||
return directoryInfo.FullName;
|
||||
}
|
||||
|
||||
directoryInfo = directoryInfo.Parent;
|
||||
}
|
||||
while (directoryInfo.Parent != null);
|
||||
|
||||
throw new InvalidOperationException($"Solution root could not be located using application root {applicationPath}.");
|
||||
}
|
||||
|
||||
protected override IHost CreateHost(IHostBuilder builder)
|
||||
|
|
@ -78,5 +153,76 @@ namespace Microsoft.AspNetCore.Identity.FunctionalTests
|
|||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private static void AddRelatedParts(IServiceCollection services, string framework)
|
||||
{
|
||||
var _assemblyMap =
|
||||
new Dictionary<UIFramework, string>()
|
||||
{
|
||||
[UIFramework.Bootstrap3] = "Microsoft.AspNetCore.Identity.UI.Views.V3",
|
||||
[UIFramework.Bootstrap4] = "Microsoft.AspNetCore.Identity.UI.Views.V4",
|
||||
};
|
||||
|
||||
var mvcBuilder = services
|
||||
.AddMvc()
|
||||
.ConfigureApplicationPartManager(partManager =>
|
||||
{
|
||||
var thisAssembly = typeof(IdentityBuilderUIExtensions).Assembly;
|
||||
var relatedAssemblies = RelatedAssemblyAttribute.GetRelatedAssemblies(thisAssembly, throwOnError: true);
|
||||
var relatedParts = relatedAssemblies.ToDictionary(
|
||||
ra => ra,
|
||||
CompiledRazorAssemblyApplicationPartFactory.GetDefaultApplicationParts);
|
||||
|
||||
var selectedFrameworkAssembly = _assemblyMap[framework == "V3" ? UIFramework.Bootstrap3 : UIFramework.Bootstrap4];
|
||||
|
||||
foreach (var kvp in relatedParts)
|
||||
{
|
||||
var assemblyName = kvp.Key.GetName().Name;
|
||||
if (!IsAssemblyForFramework(selectedFrameworkAssembly, assemblyName))
|
||||
{
|
||||
RemoveParts(partManager, kvp.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddParts(partManager, kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsAssemblyForFramework(string frameworkAssembly, string assemblyName) =>
|
||||
string.Equals(assemblyName, frameworkAssembly, StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
void RemoveParts(
|
||||
ApplicationPartManager manager,
|
||||
IEnumerable<ApplicationPart> partsToRemove)
|
||||
{
|
||||
for (var i = 0; i < manager.ApplicationParts.Count; i++)
|
||||
{
|
||||
var part = manager.ApplicationParts[i];
|
||||
if (partsToRemove.Any(p => string.Equals(
|
||||
p.Name,
|
||||
part.Name,
|
||||
StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
manager.ApplicationParts.Remove(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddParts(
|
||||
ApplicationPartManager manager,
|
||||
IEnumerable<ApplicationPart> partsToAdd)
|
||||
{
|
||||
foreach (var part in partsToAdd)
|
||||
{
|
||||
if (!manager.ApplicationParts.Any(p => p.GetType() == part.GetType() &&
|
||||
string.Equals(p.Name, part.Name, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
manager.ApplicationParts.Add(part);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,9 +7,10 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
|
||||
<Compile Include="..\..\Extensions.Core\src\Base32.cs" Link="Infrastructure\Base32.cs" />
|
||||
<Compile Include="..\..\Extensions.Core\src\Rfc6238AuthenticationService.cs" Link="Infrastructure\Rfc6238AuthenticationService.cs" />
|
||||
<Compile Include="..\..\UI\src\UIFramework.cs" Link="Infrastructure\UIFramework.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -27,6 +28,39 @@
|
|||
<Reference Include="AngleSharp" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Testing.DefaultWebSite.StaticWebAssets.V4.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Testing.DefaultWebSite.StaticWebAssets.V4.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Testing.DefaultWebSite.StaticWebAssets.V3.xml">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="AddProjectReferenceAssemblyInfo" BeforeTargets="GetAssemblyAttributes" DependsOnTargets="ResolveAssemblyReferences">
|
||||
<ItemGroup>
|
||||
<_IdentitUIDefaultWebSite Include="@(ReferencePath)" Condition="'%(ReferencePath.FileName)' == 'Identity.DefaultUI.WebSite'" />
|
||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||
<_Parameter1>Microsoft.AspNetCore.Testing.DefaultWebSiteProjectPath</_Parameter1>
|
||||
<_Parameter2>$([System.IO.Path]::GetDirectoryName('%(_IdentitUIDefaultWebSite.MSBuildSourceProjectFile)'))</_Parameter2>
|
||||
</AssemblyAttribute>
|
||||
|
||||
<_IdentitUIProjectPath Include="@(ReferencePath)" Condition="'%(ReferencePath.FileName)' == 'Microsoft.AspNetCore.Identity.UI'" />
|
||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||
<_Parameter1>Microsoft.AspNetCore.Testing.IdentityUIProjectPath</_Parameter1>
|
||||
<_Parameter2>$([System.IO.Path]::GetDirectoryName('%(_IdentitUIProjectPath.MSBuildSourceProjectFile)'))</_Parameter2>
|
||||
</AssemblyAttribute>
|
||||
|
||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute" Condition="'$(HelixType)' == 'ci'">
|
||||
<_Parameter1>Microsoft.AspNetCore.Testing.IsHelixCI</_Parameter1>
|
||||
<_Parameter2>true</_Parameter2>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishAssets" AfterTargets="Publish">
|
||||
<ItemGroup>
|
||||
<_PublishFiles Include="$(ArtifactsBinDir)Microsoft.AspNetCore.Identity.UI\$(Configuration)\netcoreapp3.0\Microsoft.AspNetCore.Identity.UI.Views.*.dll" />
|
||||
|
|
@ -34,22 +68,16 @@
|
|||
<_PublishFiles Include="$(ArtifactsBinDir)Identity.DefaultUI.WebSite\$(Configuration)\netcoreapp3.0\Identity.DefaultUI.WebSite.deps.json" />
|
||||
<_wwwrootFiles Include="$(MSBuildThisFileDirectory)..\..\testassets\Identity.DefaultUI.WebSite\wwwroot\**\*.*" />
|
||||
<_PagesFiles Include="$(MSBuildThisFileDirectory)..\..\testassets\Identity.DefaultUI.WebSite\Pages\**\*.*" />
|
||||
<_IdentityUIContent Include="$(MSBuildThisFileDirectory)..\..\UI\src\wwwroot\**\*" />
|
||||
<_IdentityUIPages Include="$(MSBuildThisFileDirectory)..\..\UI\src\Areas\Identity\Pages\**\*" />
|
||||
</ItemGroup>
|
||||
<Copy
|
||||
SourceFiles="@(_PublishFiles)"
|
||||
DestinationFolder="$(PublishDir)" />
|
||||
<Copy
|
||||
SourceFiles="@(_PagesFiles)"
|
||||
DestinationFolder="$(PublishDir)\Identity.DefaultUI.WebSite\Pages" />
|
||||
<Copy
|
||||
SourceFiles="@(_wwwrootFiles)"
|
||||
DestinationFolder="$(PublishDir)\Identity.DefaultUI.WebSite\wwwroot" />
|
||||
<Copy SourceFiles="@(_PublishFiles)" DestinationFolder="$(PublishDir)" />
|
||||
<Copy SourceFiles="@(_PagesFiles)" DestinationFolder="$(PublishDir)\Identity.DefaultUI.WebSite\Pages" />
|
||||
<Copy SourceFiles="@(_wwwrootFiles)" DestinationFolder="$(PublishDir)\Identity.DefaultUI.WebSite\wwwroot" />
|
||||
<Copy SourceFiles="@(_IdentityUIContent)" DestinationFiles="$(PublishDir)\UI\wwwroot\%(_IdentityUIContent.RecursiveDir)\%(_IdentityUIContent.FileName)%(_IdentityUIContent.Extension)" />
|
||||
<Copy SourceFiles="@(_IdentityUIPages)" DestinationFiles="$(PublishDir)UI\Areas\Identity\Pages\%(_IdentityUIPages.RecursiveDir)\%(_IdentityUIPages.FileName)%(_IdentityUIPages.Extension)" />
|
||||
<!-- Drop a dummy sln to specify content root location -->
|
||||
<WriteLinesToFile
|
||||
File="$(PublishDir)\contentroot.sln"
|
||||
Lines="Ignored"
|
||||
Overwrite="true"
|
||||
Encoding="Unicode" />
|
||||
<WriteLinesToFile File="$(PublishDir)\contentroot.sln" Lines="Ignored" Overwrite="true" Encoding="Unicode" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
<StaticWebAssets Version="1.0">
|
||||
<ContentRoot BasePath="/Identity" Path="{TEST_PLACEHOLDER}/V3" />
|
||||
</StaticWebAssets>
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<StaticWebAssets Version="1.0">
|
||||
<ContentRoot BasePath="/Identity" Path="{TEST_PLACEHOLDER}/V4" />
|
||||
</StaticWebAssets>
|
||||
|
|
@ -15,6 +15,7 @@ using Microsoft.AspNetCore.Testing;
|
|||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Identity.Test
|
||||
{
|
||||
|
|
@ -83,11 +84,11 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
[Flaky("https://github.com/aspnet/AspNetCore-Internal/issues/2267", FlakyOn.AzP.macOS)]
|
||||
public async Task IdentityUI_ScriptTags_FallbackSourceContent_Matches_CDNContent(ScriptTag scriptTag)
|
||||
{
|
||||
var wwwrootDir = Path.Combine(AppContext.BaseDirectory, "UI", "src", "wwwroot", scriptTag.Version);
|
||||
var wwwrootDir = Path.Combine(GetProjectBasePath(), "wwwroot", scriptTag.Version);
|
||||
|
||||
var cdnContent = await _httpClient.GetStringAsync(scriptTag.Src);
|
||||
var fallbackSrcContent = File.ReadAllText(
|
||||
Path.Combine(wwwrootDir, scriptTag.FallbackSrc.TrimStart('~').TrimStart('/')));
|
||||
Path.Combine(wwwrootDir, scriptTag.FallbackSrc.Replace("Identity", "").TrimStart('~').TrimStart('/')));
|
||||
|
||||
Assert.Equal(RemoveLineEndings(cdnContent), RemoveLineEndings(fallbackSrcContent));
|
||||
}
|
||||
|
|
@ -108,8 +109,8 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
|
||||
private static List<ScriptTag> GetScriptTags()
|
||||
{
|
||||
var uiDirV3 = Path.Combine(AppContext.BaseDirectory, "UI", "src", "Areas", "Identity", "Pages", "V3");
|
||||
var uiDirV4 = Path.Combine(AppContext.BaseDirectory, "UI", "src", "Areas", "Identity", "Pages", "V4");
|
||||
var uiDirV3 = Path.Combine(GetProjectBasePath(), "Areas", "Identity", "Pages", "V3");
|
||||
var uiDirV4 = Path.Combine(GetProjectBasePath(), "Areas", "Identity", "Pages", "V4");
|
||||
var cshtmlFiles = GetRazorFiles(uiDirV3).Concat(GetRazorFiles(uiDirV4));
|
||||
|
||||
var scriptTags = new List<ScriptTag>();
|
||||
|
|
@ -163,6 +164,32 @@ namespace Microsoft.AspNetCore.Identity.Test
|
|||
_httpClient.Dispose();
|
||||
}
|
||||
|
||||
private static string GetProjectBasePath()
|
||||
{
|
||||
var projectPath = typeof(IdentityUIScriptsTest).Assembly.GetCustomAttributes<AssemblyMetadataAttribute>()
|
||||
.Single(a => a.Key == "Microsoft.AspNetCore.Testing.DefaultUIProjectPath").Value;
|
||||
return Directory.Exists(projectPath) ? projectPath : Path.Combine(FindHelixSlnFileDirectory(), "UI");
|
||||
}
|
||||
|
||||
private static string FindHelixSlnFileDirectory()
|
||||
{
|
||||
var applicationPath = Path.GetDirectoryName(typeof(IdentityUIScriptsTest).Assembly.Location);
|
||||
var directoryInfo = new DirectoryInfo(applicationPath);
|
||||
do
|
||||
{
|
||||
var solutionPath = Directory.EnumerateFiles(directoryInfo.FullName, "*.sln").FirstOrDefault();
|
||||
if (solutionPath != null)
|
||||
{
|
||||
return directoryInfo.FullName;
|
||||
}
|
||||
|
||||
directoryInfo = directoryInfo.Parent;
|
||||
}
|
||||
while (directoryInfo.Parent != null);
|
||||
|
||||
throw new InvalidOperationException($"Solution root could not be located using application root {applicationPath}.");
|
||||
}
|
||||
|
||||
class RetryHandler : DelegatingHandler
|
||||
{
|
||||
public RetryHandler(HttpMessageHandler innerHandler) : base(innerHandler) { }
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="$(IdentityTestSharedSourceRoot)**\*.cs" />
|
||||
<Compile Include="$(SharedSourceRoot)test\SkipOnHelixAttribute.cs" />
|
||||
<Content Include="..\..\UI\src\Areas\Identity\Pages\**\*.*" LinkBase="UI\src\Areas\Identity\Pages" />
|
||||
<Content Include="..\..\UI\src\wwwroot\**\*.*" LinkBase="UI\src\wwwroot" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -17,8 +15,31 @@
|
|||
<Reference Include="Microsoft.AspNetCore.Http" />
|
||||
<Reference Include="Microsoft.AspNetCore.Identity.Specification.Tests" />
|
||||
<Reference Include="Microsoft.AspNetCore.Identity" />
|
||||
<Reference Include="Microsoft.AspNetCore.Identity.UI" />
|
||||
<Reference Include="Microsoft.Extensions.Configuration" />
|
||||
<Reference Include="Microsoft.Extensions.Options.ConfigurationExtensions" />
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="AddProjectReferenceAssemblyInfo" BeforeTargets="GetAssemblyAttributes" DependsOnTargets="ResolveAssemblyReferences">
|
||||
<ItemGroup>
|
||||
<_IdentitUIDefaultUI Include="@(ReferencePath)" Condition="'%(ReferencePath.FileName)' == 'Microsoft.AspNetCore.Identity.UI'" />
|
||||
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
|
||||
<_Parameter1>Microsoft.AspNetCore.Testing.DefaultUIProjectPath</_Parameter1>
|
||||
<_Parameter2>$([System.IO.Path]::GetDirectoryName('%(_IdentitUIDefaultUI.MSBuildSourceProjectFile)'))</_Parameter2>
|
||||
</AssemblyAttribute>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
|
||||
<Target Name="PublishAssets" AfterTargets="Publish">
|
||||
<ItemGroup>
|
||||
<_IdentityUIContent Include="$(MSBuildThisFileDirectory)..\..\UI\src\wwwroot\**\*" />
|
||||
<_IdentityUIPages Include="$(MSBuildThisFileDirectory)..\..\UI\src\Areas\Identity\Pages\**\*" />
|
||||
</ItemGroup>
|
||||
<Copy SourceFiles="@(_IdentityUIContent)" DestinationFiles="$(PublishDir)\UI\wwwroot\%(_IdentityUIContent.RecursiveDir)\%(_IdentityUIContent.FileName)%(_IdentityUIContent.Extension)" />
|
||||
<Copy SourceFiles="@(_IdentityUIPages)" DestinationFiles="$(PublishDir)UI\Areas\Identity\Pages\%(_IdentityUIPages.RecursiveDir)\%(_IdentityUIPages.FileName)%(_IdentityUIPages.Extension)" />
|
||||
<!-- Drop a dummy sln to specify content root location -->
|
||||
<WriteLinesToFile File="$(PublishDir)\contentroot.sln" Lines="Ignored" Overwrite="true" Encoding="Unicode" />
|
||||
</Target>
|
||||
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.UI;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Identity.DefaultUI.WebSite
|
||||
{
|
||||
public class Bootstrap3Startup : ApplicationUserStartup
|
||||
{
|
||||
public Bootstrap3Startup(IConfiguration configuration) : base(configuration)
|
||||
{
|
||||
}
|
||||
|
||||
public override UIFramework Framework => UIFramework.Bootstrap3;
|
||||
}
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
<UserSecretsId>aspnet-Identity.DefaultUI.WebSite-80C658D8-CED7-467F-9B47-75DA3BC1A16D</UserSecretsId>
|
||||
<IdentityDefaultUIFramework>Bootstrap3</IdentityDefaultUIFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -43,4 +44,15 @@
|
|||
<Reference Include="Microsoft.Extensions.Logging.Debug" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ResolveStaticWebAssetsInputsDependsOn>_SetBootstrapFrameworkVersion</ResolveStaticWebAssetsInputsDependsOn>
|
||||
</PropertyGroup>
|
||||
|
||||
<Target Name="_SetBootstrapFrameworkVersion">
|
||||
<ItemGroup>
|
||||
<_StaticWebAssetsProjectReference Condition="'%(FileName)' == 'Microsoft.AspNetCore.Identity.UI'">
|
||||
<AdditionalProperties>IdentityDefaultUIFramework=$(IdentityDefaultUIFramework)</AdditionalProperties>
|
||||
</_StaticWebAssetsProjectReference>
|
||||
</ItemGroup>
|
||||
</Target>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ namespace Identity.DefaultUI.WebSite
|
|||
});
|
||||
|
||||
services.AddDefaultIdentity<Microsoft.AspNetCore.Identity.Test.PocoUser>()
|
||||
.AddDefaultUI(UIFramework.Bootstrap4)
|
||||
.AddUserManager<UserManager<Microsoft.AspNetCore.Identity.Test.PocoUser>>();
|
||||
services.AddSingleton<IUserStore<Microsoft.AspNetCore.Identity.Test.PocoUser>, InMemoryUserStore<Microsoft.AspNetCore.Identity.Test.PocoUser>>();
|
||||
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@ namespace Identity.DefaultUI.WebSite
|
|||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
public virtual UIFramework Framework { get; } = UIFramework.Bootstrap4;
|
||||
|
||||
// This method gets called by the runtime. Use this method to add services to the container.
|
||||
public virtual void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
|
|
@ -49,7 +47,6 @@ namespace Identity.DefaultUI.WebSite
|
|||
.UseSqlite("DataSource=:memory:"));
|
||||
|
||||
services.AddDefaultIdentity<TUser>()
|
||||
.AddDefaultUI(Framework)
|
||||
.AddRoles<IdentityRole>()
|
||||
.AddEntityFrameworkStores<TContext>();
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
|
@ -41,11 +42,19 @@ namespace Templates.Test.Helpers
|
|||
public ITestOutputHelper Output { get; set; }
|
||||
public IMessageSink DiagnosticsMessageSink { get; set; }
|
||||
|
||||
internal async Task<ProcessEx> RunDotNetNewAsync(string templateName, string auth = null, string language = null, bool useLocalDB = false, bool noHttps = false, string[] args = null)
|
||||
internal async Task<ProcessEx> RunDotNetNewAsync(
|
||||
string templateName,
|
||||
string auth = null,
|
||||
string language = null,
|
||||
bool useLocalDB = false,
|
||||
bool noHttps = false,
|
||||
string[] args = null,
|
||||
// Used to set special options in MSBuild
|
||||
IDictionary<string, string> environmentVariables = null)
|
||||
{
|
||||
var hiveArg = $"--debug:custom-hive \"{TemplatePackageInstaller.CustomHivePath}\"";
|
||||
var argString = $"new {templateName} {hiveArg}";
|
||||
|
||||
environmentVariables ??= new Dictionary<string, string>();
|
||||
if (!string.IsNullOrEmpty(auth))
|
||||
{
|
||||
argString += $" --auth {auth}";
|
||||
|
|
@ -86,7 +95,7 @@ namespace Templates.Test.Helpers
|
|||
await DotNetNewLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
var execution = ProcessEx.Run(Output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), argString);
|
||||
var execution = ProcessEx.Run(Output, AppContext.BaseDirectory, DotNetMuxer.MuxerPathOrDefault(), argString, environmentVariables);
|
||||
await execution.Exited;
|
||||
return execution;
|
||||
}
|
||||
|
|
@ -96,7 +105,7 @@ namespace Templates.Test.Helpers
|
|||
}
|
||||
}
|
||||
|
||||
internal async Task<ProcessEx> RunDotNetPublishAsync(bool takeNodeLock = false)
|
||||
internal async Task<ProcessEx> RunDotNetPublishAsync(bool takeNodeLock = false, IDictionary<string,string> packageOptions = null)
|
||||
{
|
||||
Output.WriteLine("Publishing ASP.NET application...");
|
||||
|
||||
|
|
@ -112,7 +121,7 @@ namespace Templates.Test.Helpers
|
|||
await effectiveLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish -c Release {extraArgs}");
|
||||
var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), $"publish -c Release {extraArgs}", packageOptions);
|
||||
await result.Exited;
|
||||
return result;
|
||||
}
|
||||
|
|
@ -122,7 +131,7 @@ namespace Templates.Test.Helpers
|
|||
}
|
||||
}
|
||||
|
||||
internal async Task<ProcessEx> RunDotNetBuildAsync(bool takeNodeLock = false)
|
||||
internal async Task<ProcessEx> RunDotNetBuildAsync(bool takeNodeLock = false, IDictionary<string,string> packageOptions = null)
|
||||
{
|
||||
Output.WriteLine("Building ASP.NET application...");
|
||||
|
||||
|
|
@ -133,7 +142,7 @@ namespace Templates.Test.Helpers
|
|||
await effectiveLock.WaitAsync();
|
||||
try
|
||||
{
|
||||
var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), "build -c Debug");
|
||||
var result = ProcessEx.Run(Output, TemplateOutputDir, DotNetMuxer.MuxerPathOrDefault(), "build -c Debug", packageOptions);
|
||||
await result.Exited;
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,190 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Templates.Test.Helpers;
|
||||
using Xunit;
|
||||
using Xunit.Abstractions;
|
||||
|
||||
namespace Templates.Test
|
||||
{
|
||||
public class IdentityUIPackageTest
|
||||
{
|
||||
public IdentityUIPackageTest(ProjectFactoryFixture projectFactory, ITestOutputHelper output)
|
||||
{
|
||||
ProjectFactory = projectFactory;
|
||||
Output = output;
|
||||
}
|
||||
|
||||
public Project Project { get; set; }
|
||||
|
||||
public ProjectFactoryFixture ProjectFactory { get; set; }
|
||||
|
||||
public ITestOutputHelper Output { get; }
|
||||
|
||||
public static TheoryData<IDictionary<string, string>, string, string[]> MSBuildIdentityUIPackageOptions
|
||||
{
|
||||
get
|
||||
{
|
||||
var data = new TheoryData<IDictionary<string, string>, string, string[]>();
|
||||
|
||||
data.Add(new Dictionary<string, string>
|
||||
{
|
||||
["IdentityUIFrameworkVersion"] = "Bootstrap3"
|
||||
},
|
||||
"Bootstrap v3.4.1",
|
||||
Bootstrap3ContentFiles);
|
||||
|
||||
data.Add(new Dictionary<string, string>(), "Bootstrap v4.3.1", Bootstrap4ContentFiles);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
public static string[] Bootstrap3ContentFiles { get; } = new string[]
|
||||
{
|
||||
"Identity/css/site.css",
|
||||
"Identity/js/site.js",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-theme.css",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-theme.css.map",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-theme.min.css",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-theme.min.css.map",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap.css",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap.css.map",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap.min.css",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap.min.css.map",
|
||||
"Identity/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.eot",
|
||||
"Identity/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.svg",
|
||||
"Identity/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.ttf",
|
||||
"Identity/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff",
|
||||
"Identity/lib/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2",
|
||||
"Identity/lib/bootstrap/dist/js/bootstrap.js",
|
||||
"Identity/lib/bootstrap/dist/js/bootstrap.min.js",
|
||||
"Identity/lib/bootstrap/dist/js/npm.js",
|
||||
"Identity/lib/jquery/LICENSE.txt",
|
||||
"Identity/lib/jquery/dist/jquery.js",
|
||||
"Identity/lib/jquery/dist/jquery.min.js",
|
||||
"Identity/lib/jquery/dist/jquery.min.map",
|
||||
"Identity/lib/jquery-validation/LICENSE.md",
|
||||
"Identity/lib/jquery-validation/dist/additional-methods.js",
|
||||
"Identity/lib/jquery-validation/dist/additional-methods.min.js",
|
||||
"Identity/lib/jquery-validation/dist/jquery.validate.js",
|
||||
"Identity/lib/jquery-validation/dist/jquery.validate.min.js",
|
||||
"Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js",
|
||||
"Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js",
|
||||
"Identity/lib/jquery-validation-unobtrusive/LICENSE.txt",
|
||||
};
|
||||
|
||||
public static string[] Bootstrap4ContentFiles { get; } = new string[]
|
||||
{
|
||||
"Identity/favicon.ico",
|
||||
"Identity/css/site.css",
|
||||
"Identity/js/site.js",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-grid.css",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-grid.css.map",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-grid.min.css",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-grid.min.css.map",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-reboot.css",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-reboot.css.map",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-reboot.min.css",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap-reboot.min.css.map",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap.css",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap.css.map",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap.min.css",
|
||||
"Identity/lib/bootstrap/dist/css/bootstrap.min.css.map",
|
||||
"Identity/lib/bootstrap/dist/js/bootstrap.bundle.js",
|
||||
"Identity/lib/bootstrap/dist/js/bootstrap.bundle.js.map",
|
||||
"Identity/lib/bootstrap/dist/js/bootstrap.bundle.min.js",
|
||||
"Identity/lib/bootstrap/dist/js/bootstrap.bundle.min.js.map",
|
||||
"Identity/lib/bootstrap/dist/js/bootstrap.js",
|
||||
"Identity/lib/bootstrap/dist/js/bootstrap.js.map",
|
||||
"Identity/lib/bootstrap/dist/js/bootstrap.min.js",
|
||||
"Identity/lib/bootstrap/dist/js/bootstrap.min.js.map",
|
||||
"Identity/lib/jquery/LICENSE.txt",
|
||||
"Identity/lib/jquery/dist/jquery.js",
|
||||
"Identity/lib/jquery/dist/jquery.min.js",
|
||||
"Identity/lib/jquery/dist/jquery.min.map",
|
||||
"Identity/lib/jquery-validation/LICENSE.md",
|
||||
"Identity/lib/jquery-validation/dist/additional-methods.js",
|
||||
"Identity/lib/jquery-validation/dist/additional-methods.min.js",
|
||||
"Identity/lib/jquery-validation/dist/jquery.validate.js",
|
||||
"Identity/lib/jquery-validation/dist/jquery.validate.min.js",
|
||||
"Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js",
|
||||
"Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js",
|
||||
"Identity/lib/jquery-validation-unobtrusive/LICENSE.txt",
|
||||
};
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(MSBuildIdentityUIPackageOptions))]
|
||||
public async Task IdentityUIPackage_WorksWithDifferentOptions(IDictionary<string, string> packageOptions, string versionValidator, string[] expectedFiles)
|
||||
{
|
||||
Project = await ProjectFactory.GetOrCreateProject("identityuipackage" + string.Concat(packageOptions.Values), Output);
|
||||
var useLocalDB = false;
|
||||
|
||||
var createResult = await Project.RunDotNetNewAsync("razor", auth: "Individual", useLocalDB: useLocalDB, environmentVariables: packageOptions);
|
||||
Assert.True(0 == createResult.ExitCode, ErrorMessages.GetFailedProcessMessage("create/restore", Project, createResult));
|
||||
|
||||
var projectFileContents = ReadFile(Project.TemplateOutputDir, $"{Project.ProjectName}.csproj");
|
||||
Assert.Contains(".db", projectFileContents);
|
||||
|
||||
var publishResult = await Project.RunDotNetPublishAsync(packageOptions: packageOptions);
|
||||
Assert.True(0 == publishResult.ExitCode, ErrorMessages.GetFailedProcessMessage("publish", Project, publishResult));
|
||||
|
||||
// Run dotnet build after publish. The reason is that one uses Config = Debug and the other uses Config = Release
|
||||
// The output from publish will go into bin/Release/netcoreapp3.0/publish and won't be affected by calling build
|
||||
// later, while the opposite is not true.
|
||||
|
||||
var buildResult = await Project.RunDotNetBuildAsync(packageOptions: packageOptions);
|
||||
Assert.True(0 == buildResult.ExitCode, ErrorMessages.GetFailedProcessMessage("build", Project, buildResult));
|
||||
|
||||
var migrationsResult = await Project.RunDotNetEfCreateMigrationAsync("razorpages");
|
||||
Assert.True(0 == migrationsResult.ExitCode, ErrorMessages.GetFailedProcessMessage("run EF migrations", Project, migrationsResult));
|
||||
Project.AssertEmptyMigration("razorpages");
|
||||
|
||||
using (var aspNetProcess = Project.StartBuiltProjectAsync())
|
||||
{
|
||||
Assert.False(
|
||||
aspNetProcess.Process.HasExited,
|
||||
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
|
||||
|
||||
var response = await aspNetProcess.SendRequest("/Identity/lib/bootstrap/dist/css/bootstrap.css");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Contains(versionValidator, await response.Content.ReadAsStringAsync());
|
||||
await ValidatePublishedFiles(aspNetProcess, expectedFiles);
|
||||
}
|
||||
|
||||
using (var aspNetProcess = Project.StartPublishedProjectAsync())
|
||||
{
|
||||
Assert.False(
|
||||
aspNetProcess.Process.HasExited,
|
||||
ErrorMessages.GetFailedProcessMessageOrEmpty("Run built project", Project, aspNetProcess.Process));
|
||||
|
||||
var response = await aspNetProcess.SendRequest("/Identity/lib/bootstrap/dist/css/bootstrap.css");
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Contains(versionValidator, await response.Content.ReadAsStringAsync());
|
||||
await ValidatePublishedFiles(aspNetProcess, expectedFiles);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ValidatePublishedFiles(AspNetProcess aspNetProcess, string[] expectedContentFiles)
|
||||
{
|
||||
foreach (var file in expectedContentFiles)
|
||||
{
|
||||
var response = await aspNetProcess.SendRequest(file);
|
||||
Assert.True(response?.StatusCode == HttpStatusCode.OK, $"Couldn't find file '{file}'");
|
||||
}
|
||||
}
|
||||
|
||||
private string ReadFile(string basePath, string path)
|
||||
{
|
||||
var fullPath = Path.Combine(basePath, path);
|
||||
var doesExist = File.Exists(fullPath);
|
||||
|
||||
Assert.True(doesExist, $"Expected file to exist, but it doesn't: {path}");
|
||||
return File.ReadAllText(Path.Combine(basePath, path));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue