Skip to content

Commit

Permalink
Merge pull request #1780 from riganti/repro-extension-methods-load-bug
Browse files Browse the repository at this point in the history
Test to diagnose extension method load instability
  • Loading branch information
exyi committed Apr 27, 2024
2 parents 29d9df2 + e0fd59d commit 712bb09
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 161 deletions.
13 changes: 12 additions & 1 deletion src/Samples/AspNetCore/Startup.cs
Expand Up @@ -94,6 +94,17 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF
}

private string GetApplicationPath(IWebHostEnvironment env)
=> Path.Combine(Path.GetDirectoryName(env.ContentRootPath), "Common");
{
var common = Path.Combine(Path.GetDirectoryName(env.ContentRootPath), "Common");
if (Directory.Exists(common))
{
return common;
}
if (File.Exists(Path.Combine(env.ContentRootPath, "Views/Default.dothtml")))
{
return env.ContentRootPath;
}
throw new DirectoryNotFoundException("Cannot find the 'Common' directory nor the 'Views' directory in the application root.");
}
}
}
13 changes: 12 additions & 1 deletion src/Samples/AspNetCoreLatest/Startup.cs
Expand Up @@ -105,6 +105,17 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerF
}

private string GetApplicationPath(IWebHostEnvironment env)
=> Path.Combine(Path.GetDirectoryName(env.ContentRootPath), "Common");
{
if (File.Exists(Path.Combine(env.ContentRootPath, "Views/Default.dothtml")))
{
return env.ContentRootPath;
}
var common = Path.Combine(Path.GetDirectoryName(env.ContentRootPath), "Common");
if (File.Exists(Path.Combine(common, "Views/Default.dothtml")))
{
return common;
}
throw new DirectoryNotFoundException("Cannot find the 'Common' directory nor the 'Views' directory in the application root.");
}
}
}
158 changes: 1 addition & 157 deletions src/Samples/Common/DotVVM.Samples.Common.csproj
Expand Up @@ -19,167 +19,11 @@
<None Remove="node_modules\**" />
<None Remove="script\**" />
</ItemGroup>
<ItemGroup>
<Content Remove="Views\FeatureSamples\EmbeddedResourceControls\EmbeddedResourceMasterPage.dotmaster" />
<Content Remove="Views\FeatureSamples\ViewModules\ModuleControl.dotcontrol" />
</ItemGroup>
<ItemGroup>
<None Remove="sampleConfig.json" />
<None Remove="tsconfig.react.json" />
<None Remove="Scripts\ControlSamples_NamedCommand_ParameterStaticCommand.js" />
<None Remove="Views\ComplexSamples\NestedComboBox\InnerWrapper.dotcontrol" />
<None Remove="Views\ComplexSamples\NestedComboBox\OuterWrapper.dotcontrol" />
<None Remove="Views\ComplexSamples\SPAErrorReporting\default.dothtml" />
<None Remove="Views\ComplexSamples\SPAErrorReporting\site.dotmaster" />
<None Remove="Views\ComplexSamples\SPAErrorReporting\test.dothtml" />
<None Remove="Views\ComplexSamples\ViewModelPopulate\ViewModelPopulate.dothtml" />
<None Remove="Views\ControlSamples\CheckBox\CheckBox_Objects.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\BindingCTValidation_StringToEnum.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\HeavilyNested.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_Complex_Error.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_Enum.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_Number.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_SelectedValue_ComplexToInt_Error.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_SelectedValue_StringToInt_Error.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_String.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\ItemBinding_ItemValueBinding_StringToObject.dothtml" />
<None Remove="Views\ControlSamples\ComboBox\Nullable.dothtml" />
<None Remove="Views\ControlSamples\GridView\GridViewCellDecorators.dothtml" />
<None Remove="Views\ControlSamples\HierarchyRepeater\Basic.dothtml" />
<None Remove="Views\ControlSamples\HierarchyRepeater\NodeControl.dotcontrol" />
<None Remove="Views\ControlSamples\HierarchyRepeater\WithMarkupControl.dothtml" />
<None Remove="Views\ControlSamples\Literal\Literal_NumberBinding.dothtml" />
<None Remove="Views\ControlSamples\MultiSelect\binded.dothtml" />
<None Remove="Views\ControlSamples\MultiSelect\hardcoded.dothtml" />
<None Remove="Views\ControlSamples\NamedCommand\ParameterStaticCommandService.dothtml" />
<None Remove="Views\ControlSamples\RadioButton\Nullable.dothtml" />
<None Remove="Views\ControlSamples\RadioButton\RadioButton_Objects.dothtml" />
<None Remove="Views\ControlSamples\Repeater\IndexInNestedRepeater.dothtml" />
<None Remove="Views\ControlSamples\Repeater\NamedTemplate.dothtml" />
<None Remove="Views\ControlSamples\RouteLink\RouteLinkQueryParameters.dothtml" />
<None Remove="Views\ControlSamples\TemplateHost\Basic.dothtml" />
<None Remove="Views\ControlSamples\TemplateHost\TemplatedListControl.dotcontrol" />
<None Remove="Views\ControlSamples\TemplateHost\TemplatedMarkupControl.dotcontrol" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressQueues.dothtml" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirect.dotmaster" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirect1.dothtml" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirect2.dothtml" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirectSPA.dotmaster" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirectSPA1.dothtml" />
<None Remove="Views\ControlSamples\UpdateProgress\UpdateProgressRedirectSPA2.dothtml" />
<None Remove="Views\ControlSamples\ValidationSummary\MessagesRendering.dothtml" />
<None Remove="Views\ControlSamples\ValidationSummary\Performance.dothtml" />
<None Remove="Views\Errors\CorruptedContentBetweenContentControls.dothtml" />
<None Remove="Views\Errors\ExceptionInLifecycle.dothtml" />
<None Remove="Views\Errors\ExceptionInRender.dothtml" />
<None Remove="Views\Errors\InvalidServiceDirective.dothtml" />
<None Remove="Views\Errors\InvalidLocationFallback.dothtml" />
<None Remove="Views\Errors\MarkupControlInvalidViewModel.dothtml" />
<None Remove="Views\Errors\MarkupControlPropertiesSameName.dotcontrol" />
<None Remove="Views\Errors\MarkupControlPropertiesSameNameWithBase.dotcontrol" />
<None Remove="Views\Errors\MarkupControlPropertiesSameNameWithBase.dothtml" />
<None Remove="Views\Errors\ResourceCircularDependency.dothtml" />
<None Remove="Views\FeatureSamples\Api\ApiInSpa_Master.dotmaster" />
<None Remove="Views\FeatureSamples\Api\ApiInSpa_PageA.dothtml" />
<None Remove="Views\FeatureSamples\Api\ApiInSpa_PageB.dothtml" />
<None Remove="Views\FeatureSamples\Api\ApiRefresh.dothtml" />
<None Remove="Views\FeatureSamples\Api\CollectionOddEvenWithRestApi.dothtml" />
<None Remove="Views\FeatureSamples\Api\IncludedInPage.dothtml" />
<None Remove="Views\FeatureSamples\Api\IsLoading.dothtml" />
<None Remove="Views\FeatureSamples\Attribute\ToStringConversion.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\AutoEditor.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\AutoForm.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\AutoGridViewColumns.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\BootstrapForm3.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\BootstrapForm4.dothtml" />
<None Remove="Views\FeatureSamples\AutoUI\BootstrapForm5.dothtml" />
<None Remove="Views\FeatureSamples\BindingVariables\StaticCommandVariablesWithService_Complex.dothtml" />
<None Remove="Views\FeatureSamples\BindingVariables\StaticCommandVariablesWithService_Complex2.dothtml" />
<None Remove="Views\FeatureSamples\BindingVariables\StaticCommandVariablesWithService_Simple.dothtml" />
<None Remove="Views\FeatureSamples\Caching\CachedValues.dothtml" />
<None Remove="Views\FeatureSamples\CompositeControls\ControlPropertyNamingConflict.dothtml" />
<None Remove="Views\FeatureSamples\CommandActionFilter\CommandActionFilter.dothtml" />
<None Remove="Views\FeatureSamples\CustomPrimitiveTypes\Basic.dothtml" />
<None Remove="Views\FeatureSamples\CustomPrimitiveTypes\RouteLink.dothtml" />
<None Remove="Views\FeatureSamples\CustomPrimitiveTypes\TextBox.dothtml" />
<None Remove="Views\FeatureSamples\CustomPrimitiveTypes\UsedInControls.dothtml" />
<None Remove="Views\FeatureSamples\EmbeddedResourceControls\EmbeddedResourceMasterPage.dotmaster" />
<None Remove="Views\FeatureSamples\EmbeddedResourceControls\PageWithEmbeddedResourceMasterPage.dothtml" />
<None Remove="Views\FeatureSamples\Formatting\AutoResourceInclusion.dothtml" />
<None Remove="Views\FeatureSamples\Formatting\AutoResourceInclusionMaster.dotmaster" />
<None Remove="Views\FeatureSamples\Formatting\ToStringGlobalFunctionBug.dothtml" />
<None Remove="Views\FeatureSamples\HotReload\ViewChanges.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\ArrayTranslation.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\DateTimeTranslations.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\DictionaryIndexerTranslation.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\GenericMethodTranslation.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\ListIndexerTranslation.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\ListMethodTranslations.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\WebUtilityTranslations.dothtml" />
<None Remove="Views\FeatureSamples\JavascriptTranslation\StringMethodTranslations.dothtml" />
<None Remove="Views\FeatureSamples\JsComponentIntegration\ReactComponentIntegration.dothtml" />
<None Remove="Views\FeatureSamples\JsDirectives\BasicSample.dothtml" />
<None Remove="Views\FeatureSamples\LambdaExpressions\ClientSideFiltering.dothtml" />
<None Remove="Views\FeatureSamples\LambdaExpressions\LambdaExpressions.dothtml" />
<None Remove="Views\FeatureSamples\Localization\Globalize.dothtml" />
<None Remove="Views\FeatureSamples\MarkupControl\MarkupDefinedProperties.dothtml" />
<None Remove="Views\FeatureSamples\MarkupControl\MarkupDefinedPropertiesControl.dotcontrol" />
<None Remove="Views\FeatureSamples\MarkupControl\ServiceDependency\ServiceDependencyControl.dotcontrol" />
<None Remove="Views\FeatureSamples\PostbackAbortSignal\LoadAbortViewModel.dothtml" />
<None Remove="Views\FeatureSamples\RenderSettingsModeServer\RepeaterCollectionSetToNull.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\ByteArray.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\DateOnlyTimeOnly.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\TimeSpan.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\EnumSerializationCoercion.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\SerializationDateTimeOffset.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\StaticCommand_Validation.dothtml" />
<None Remove="Views\FeatureSamples\StringInterpolation\StringInterpolation.dothtml" />
<None Remove="Views\FeatureSamples\Validation\RangeClientSideValidation.dothtml" />
<None Remove="Views\FeatureSamples\Validation\ValidationTargetIsCollection.dothtml" />
<None Remove="Views\FeatureSamples\Validation\ValidatorValueComplexExpressions.dothtml" />
<None Remove="Views\FeatureSamples\ViewModelDeserialization\PropertyNullAssignment.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\Incrementer.dotcontrol" />
<None Remove="Views\FeatureSamples\ViewModules\IncrementerInRepeater.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\InnerModuleControl.dotcontrol" />
<None Remove="Views\FeatureSamples\ViewModules\LinkModuleControl.dotcontrol" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleControl.dotcontrol" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInMarkupControl.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInMarkupControlTwice.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInPage.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInPageCommandAmbiguous.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInPageMasterPage.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInPageSpaMasterPage.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleInPageSpaMasterPage2.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleMasterPage.dotmaster" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleRegistrationPropagation.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\ModuleSpaMasterPage.dotmaster" />
<None Remove="Views\FeatureSamples\MarkupControl\CommandPropertiesInMarkupControl.dothtml" />
<None Remove="Views\FeatureSamples\MarkupControl\Device.dotcontrol" />
<None Remove="Views\FeatureSamples\MarkupControl\Dialog.dotcontrol" />
<None Remove="Views\FeatureSamples\MarkupControl\StaticCommandInMarkupControl.dothtml" />
<None Remove="Views\FeatureSamples\MarkupControl\StaticCommandInMarkupControlCallingRegularCommand.dothtml" />
<None Remove="Views\FeatureSamples\PostbackConcurrency\RedirectPostbackQueue.dothtml" />
<None Remove="Views\FeatureSamples\PostbackConcurrency\StressTest.dothtml" />
<None Remove="Views\FeatureSamples\PostBack\RecursiveTextRepeater.dotcontrol" />
<None Remove="Views\FeatureSamples\PostBack\RecursiveTextRepeater2.dotcontrol" />
<None Remove="Views\FeatureSamples\PostBack\UniqueIdGenerationOnPostbackUpdate.dothtml" />
<None Remove="Views\FeatureSamples\Redirect\Redirect_StaticCommand.dothtml" />
<None Remove="Views\FeatureSamples\Resources\LocationFallback.dothtml" />
<None Remove="Views\FeatureSamples\Resources\RequiredOnPostback.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\DeserializationVirtualElements.dothtml" />
<None Remove="Views\FeatureSamples\CustomResponseProperties\SimpleExceptionFilter.dothtml" />
<None Remove="Views\FeatureSamples\Serialization\Dictionary.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\CustomAwaitable.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\StaticCommand_ArrayAssigment.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\StaticCommand_LoadComplexDataFromService.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\StaticCommand_NullAssignment.dothtml" />
<None Remove="Views\FeatureSamples\StaticCommand\StaticCommand_TaskSequence.dothtml" />
<None Remove="Views\FeatureSamples\UsageValidation\OverrideValidation.dothtml" />
<None Remove="Views\FeatureSamples\Validation\EnforceClientSideValidationDisabled.dothtml" />
<None Remove="Views\FeatureSamples\Validation\InvalidCssClassNotDuplicated.dothtml" />
<None Remove="Views\FeatureSamples\Validation\ValidationPropertyPathResolving.dothtml" />
<None Remove="Views\FeatureSamples\ViewModelCache\ViewModelCache_Miss.dothtml" />
<None Remove="Views\FeatureSamples\ViewModules\OuterModuleControl.dotcontrol" />
<None Remove="**/*.dotmaster;**/*.dotcontrol;**/*.dothtml" />
</ItemGroup>
<ItemGroup>
<Content Include="sampleConfig.json">
Expand Down
3 changes: 3 additions & 0 deletions src/Samples/Common/DotvvmStartup.cs
Expand Up @@ -31,6 +31,7 @@
using DotVVM.Samples.Common.ViewModels.FeatureSamples.BindingVariables;
using DotVVM.Samples.Common.Views.ControlSamples.TemplateHost;
using DotVVM.Framework.ResourceManagement;
using DotVVM.Samples.Common.Presenters;
using DotVVM.Samples.Common.ViewModels.FeatureSamples.CustomPrimitiveTypes;

namespace DotVVM.Samples.BasicSamples
Expand Down Expand Up @@ -251,6 +252,8 @@ private static void AddRoutes(DotvvmConfiguration config)
config.RouteTable.Add("FeatureSamples_PostBack_PostBackHandlers_Localized", "FeatureSamples/PostBack/PostBackHandlers_Localized", "Views/FeatureSamples/PostBack/ConfirmPostBackHandler.dothtml", presenterFactory: LocalizablePresenter.BasedOnQuery("lang"));

config.RouteTable.Add("Errors_UndefinedRouteLinkParameters-PageDetail", "Erros/UndefinedRouteLinkParameters/{Id}", "Views/Errors/UndefinedRouteLinkParameters.dothtml", new { Id = 0 });

config.RouteTable.Add("DumpExtensionsMethods", "dump-extension-methods", _ => new DumpExtensionMethodsPresenter());
}

private static void AddControls(DotvvmConfiguration config)
Expand Down
45 changes: 45 additions & 0 deletions src/Samples/Common/Presenters/DumpExtensionMethodsPresenter.cs
@@ -0,0 +1,45 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using DotVVM.Framework.Compilation;
using DotVVM.Framework.Hosting;
using DotVVM.Framework.Utils;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;

namespace DotVVM.Samples.Common.Presenters
{
public class DumpExtensionMethodsPresenter : IDotvvmPresenter
{
public async Task ProcessRequest(IDotvvmRequestContext context)
{
var cache = context.Configuration.ServiceProvider.GetService<ExtensionMethodsCache>();

var contents = typeof(ExtensionMethodsCache)
.GetField("methodsCache", BindingFlags.Instance | BindingFlags.NonPublic)!
.GetValue(cache) as ConcurrentDictionary<string, ImmutableArray<MethodInfo>>;

var dump = contents.SelectMany(p => p.Value.Select(m => new {
Namespace = p.Key,
m.Name,
m.DeclaringType!.FullName,
Params = m.GetParameters().Select(p => new {
p.Name,
Type = p.ParameterType!.FullName
}),
m.IsGenericMethodDefinition,
GenericParameters = m.IsGenericMethodDefinition ? m.GetGenericArguments().Select(a => new {
a.Name
}) : null
}))
.OrderBy(m => m.Namespace).ThenBy(m => m.Name);

await context.HttpContext.Response.WriteAsync("ExtensionMethodsCache dump: " + JsonConvert.SerializeObject(dump, Formatting.Indented));
}
}
}
29 changes: 27 additions & 2 deletions src/Samples/Tests/Tests/Feature/StaticCommandTests.cs
@@ -1,6 +1,10 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using DotVVM.Samples.Tests.Base;
using DotVVM.Testing.Abstractions;
using OpenQA.Selenium;
Expand Down Expand Up @@ -814,7 +818,7 @@ public void Feature_List_Translation_Remove_Range()
Assert.Equal(new List<string> { "1", "2", "8", "9", "10" }, column);
});
}

[Fact]
public void Feature_List_Translation_Remove_Reverse()
{
Expand All @@ -828,6 +832,27 @@ public void Feature_List_Translation_Remove_Reverse()
});
}

[Fact]
public async Task Feature_ExtensionMethodsNotResolvedOnStartup()
{
var client = new HttpClient();

// try to visit the page
var pageResponse = await client.GetAsync(TestSuiteRunner.Configuration.BaseUrls[0].TrimEnd('/') + "/" + SamplesRouteUrls.FeatureSamples_JavascriptTranslation_ListMethodTranslations);
TestOutput.WriteLine($"Page response: {(int)pageResponse.StatusCode}");
var wasError = pageResponse.StatusCode != HttpStatusCode.OK;

// dump extension methods on the output
var json = await client.GetStringAsync(TestSuiteRunner.Configuration.BaseUrls[0].TrimEnd('/') + "/dump-extension-methods");
TestOutput.WriteLine(json);

if (wasError)
{
// fail the test on error
throw new Exception("Extension methods were not resolved on application startup.");
}
}

protected IElementWrapperCollection<IElementWrapper, IBrowserWrapper> GetSortedRow(IBrowserWrapper browser, string btn)
{
var orderByBtn = browser.First($"//input[@value='{btn}']", By.XPath);
Expand Down

0 comments on commit 712bb09

Please sign in to comment.