Skip to content

Commit afbcd6b

Browse files
authored
Merge pull request #1924 from riganti/fix/control-compilation-race-condition
Fix of race condition in compilation of markup controls with property directives
2 parents 344bda6 + 28b96b8 commit afbcd6b

File tree

4 files changed

+31
-17
lines changed

4 files changed

+31
-17
lines changed

src/Framework/Framework/Compilation/Directives/PropertyDeclarationDirectiveCompiler.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,10 @@ ImmutableList<IAbstractPropertyDeclarationDirective> propertyDirectives
159159
baseType.FullName + "||" + string.Join("|", imports) + "||" + string.Join("|", properties)
160160
)
161161
);
162-
var hash = Convert.ToBase64String(hashBytes, 0, 16);
163-
162+
var hash = Convert.ToBase64String(hashBytes, 0, 16)
163+
.Replace('+', '_')
164+
.Replace('/', '_')
165+
.TrimEnd('=');
164166
var typeName = "DotvvmMarkupControl-" + hash;
165167

166168
return GetOrCreateDynamicType(baseType, typeName, propertyDirectives);

src/Framework/Framework/Compilation/Directives/ResolvedPropertyDeclarationDirectiveCompiler.cs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ namespace DotVVM.Framework.Compilation.Directives
1212
public class ResolvedPropertyDeclarationDirectiveCompiler : PropertyDeclarationDirectiveCompiler
1313
{
1414
private static readonly Lazy<ModuleBuilder> DynamicMarkupControlAssembly = new(CreateDynamicMarkupControlAssembly);
15+
private static readonly object locker = new();
1516

1617
public ResolvedPropertyDeclarationDirectiveCompiler(
1718
ImmutableDictionary<string, ImmutableList<DothtmlDirectiveNode>> directiveNodesByName,
@@ -45,18 +46,29 @@ protected override IPropertyDescriptor TryCreateDotvvmPropertyFromDirective(IAbs
4546
string typeName,
4647
ImmutableList<IAbstractPropertyDeclarationDirective> propertyDirectives)
4748
{
48-
if (DynamicMarkupControlAssembly.Value.GetType(typeName) is { } type)
49+
// this must be done in the lock, otherwise the DynamicMarkupControlAssembly can return TypeBuilder instead of fully-built System.Type
50+
lock (locker)
4951
{
50-
return new ResolvedTypeDescriptor(type);
51-
}
52+
if (DynamicMarkupControlAssembly.Value.GetType(typeName) is { } type)
53+
{
54+
return new ResolvedTypeDescriptor(type);
55+
}
5256

53-
var declaringTypeBuilder =
54-
DynamicMarkupControlAssembly.Value.DefineType(typeName, TypeAttributes.Public, ResolvedTypeDescriptor.ToSystemType(baseType));
55-
var createdTypeInfo = declaringTypeBuilder.CreateTypeInfo()?.AsType();
57+
try
58+
{
59+
var declaringTypeBuilder =
60+
DynamicMarkupControlAssembly.Value.DefineType(typeName, TypeAttributes.Public, ResolvedTypeDescriptor.ToSystemType(baseType));
61+
var createdTypeInfo = declaringTypeBuilder.CreateTypeInfo()?.AsType();
5662

57-
return createdTypeInfo is not null
58-
? new ResolvedTypeDescriptor(createdTypeInfo)
59-
: null;
63+
return createdTypeInfo is not null
64+
? new ResolvedTypeDescriptor(createdTypeInfo)
65+
: null;
66+
}
67+
catch (Exception ex)
68+
{
69+
throw new InvalidOperationException($"Failed to create dynamic type '{typeName}'", ex);
70+
}
71+
}
6072
}
6173

6274
private static ModuleBuilder CreateDynamicMarkupControlAssembly()

src/Tests/ControlTests/testoutputs/HierarchyRepeaterTests.CommandInMarkupControl-client.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<!-- Resource c7-item of type TemplateResource. -->
88
<template id=c7-item><!-- ko with: $item -->
99
<!-- ko with: $rawData --><div>
10-
<input type=button onclick='dotvvm.postBack(this,["HItems/[$indexPath]","$parent"],"RR93KduwUKJIXxFp","c7"+&#39;_&#39;+(ko.contextFor(this).$parentContext.$indexPath.map(ko.unwrap).join("_")+"L")+&#39;_&#39;+"c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' data-bind="value: Label" /></div><!-- /ko -->
10+
<input type=button onclick='dotvvm.postBack(this,["HItems/[$indexPath]","$parent"],"bu4IebQeKpjPj6ST","c7"+&#39;_&#39;+(ko.contextFor(this).$parentContext.$indexPath.map(ko.unwrap).join("_")+"L")+&#39;_&#39;+"c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' data-bind="value: Label" /></div><!-- /ko -->
1111
<!-- /ko --><!-- ko template: { foreach: $item().Children, name: "c7-item", hierarchyRole: "Child" } --><!-- ko if: Children()?.length --><!-- /ko --><!-- /ko --></template>
1212

1313
</body>

src/Tests/ControlTests/testoutputs/HierarchyRepeaterTests.CommandInMarkupControl-server.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44

55
<div><!-- ko dotvvm-SSR-foreach: { data: HItems } --><!-- ko dotvvm-SSR-item: 0 -->
66
<!-- ko with: $rawData --><div>
7-
<input type=button value=A onclick='dotvvm.postBack(this,["HItems/[0]","$parent"],"RR93KduwUKJIXxFp","c7_0L_c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' /></div><!-- /ko -->
7+
<input type=button value=A onclick='dotvvm.postBack(this,["HItems/[0]","$parent"],"bu4IebQeKpjPj6ST","c7_0L_c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' /></div><!-- /ko -->
88
<!-- /ko --><!-- ko dotvvm-SSR-foreach: { data: ko.unwrap($foreachCollectionSymbol)[0]().Children } --><!-- ko dotvvm-SSR-item: 0 -->
99
<!-- ko with: $rawData --><div>
10-
<input type=button value=A_1 onclick='dotvvm.postBack(this,["HItems/[0]/[0]","$parent"],"RR93KduwUKJIXxFp","c7_0_0L_c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' /></div><!-- /ko -->
10+
<input type=button value=A_1 onclick='dotvvm.postBack(this,["HItems/[0]/[0]","$parent"],"bu4IebQeKpjPj6ST","c7_0_0L_c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' /></div><!-- /ko -->
1111
<!-- /ko --><!-- ko dotvvm-SSR-foreach: { data: ko.unwrap($foreachCollectionSymbol)[0]().Children } --><!-- ko dotvvm-SSR-item: 0 -->
1212
<!-- ko with: $rawData --><div>
13-
<input type=button value=A_1_1 onclick='dotvvm.postBack(this,["HItems/[0]/[0]/[0]","$parent"],"RR93KduwUKJIXxFp","c7_0_0_0L_c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' /></div><!-- /ko -->
13+
<input type=button value=A_1_1 onclick='dotvvm.postBack(this,["HItems/[0]/[0]/[0]","$parent"],"bu4IebQeKpjPj6ST","c7_0_0_0L_c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' /></div><!-- /ko -->
1414
<!-- /ko --><!-- ko dotvvm-SSR-item: 1 -->
1515
<!-- ko with: $rawData --><div>
16-
<input type=button value=A_1_2 onclick='dotvvm.postBack(this,["HItems/[0]/[0]/[1]","$parent"],"RR93KduwUKJIXxFp","c7_0_0_1L_c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' /></div><!-- /ko -->
16+
<input type=button value=A_1_2 onclick='dotvvm.postBack(this,["HItems/[0]/[0]/[1]","$parent"],"bu4IebQeKpjPj6ST","c7_0_0_1L_c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' /></div><!-- /ko -->
1717
<!-- /ko --><!-- /ko --><!-- /ko --><!-- ko dotvvm-SSR-item: 1 -->
1818
<!-- ko with: $rawData --><div>
19-
<input type=button value=B onclick='dotvvm.postBack(this,["HItems/[1]","$parent"],"RR93KduwUKJIXxFp","c7_1L_c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' /></div><!-- /ko -->
19+
<input type=button value=B onclick='dotvvm.postBack(this,["HItems/[1]","$parent"],"bu4IebQeKpjPj6ST","c7_1L_c9",null,[],[],undefined).catch(dotvvm.log.logPostBackScriptError);event.stopPropagation();return false;' /></div><!-- /ko -->
2020
<!-- /ko --><!-- /ko --></div>
2121

2222

0 commit comments

Comments
 (0)