Skip to content
This repository was archived by the owner on Oct 4, 2021. It is now read-only.

Commit 85e5d82

Browse files
authored
Merge pull request #9208 from mono/fix-1013322
Fix 1013322
2 parents 5abe91a + cfcd350 commit 85e5d82

File tree

13 files changed

+154
-67
lines changed

13 files changed

+154
-67
lines changed

main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.Commands/ScaffoldCommandHandler.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Linq;
3+
using System.Threading;
34
using MonoDevelop.AspNetCore.Scaffolding;
45
using MonoDevelop.Components.Commands;
56
using MonoDevelop.Ide;

main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.Scaffolding/Fields/ComboField.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,20 @@
2424
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2525
// THE SOFTWARE.
2626

27-
using System.Linq;
27+
using System.Collections.Generic;
28+
using System.Threading.Tasks;
2829

2930
namespace MonoDevelop.AspNetCore.Scaffolding
3031
{
3132
class ComboField : ScaffolderField
3233
{
33-
public ComboField (string commandLineName, string displayName, string [] options, bool isEditable = false) : base (commandLineName, displayName)
34+
public ComboField (string commandLineName, string displayName, Task<IEnumerable<string>> options, bool isEditable = false) : base (commandLineName, displayName)
3435
{
3536
Options = options;
3637
IsEditable = isEditable;
3738
}
3839

3940
public bool IsEditable { get; }
40-
public string [] Options { get; }
41+
public Task<IEnumerable<string>> Options { get; }
4142
}
4243
}

main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.Scaffolding/ModelVisitor.cs

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,23 +23,50 @@
2323
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2424
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2525
// THE SOFTWARE.
26+
using System;
2627
using System.Collections.Generic;
28+
using System.Linq;
29+
using System.Runtime.CompilerServices;
2730
using Microsoft.CodeAnalysis;
31+
using MonoDevelop.Ide.TypeSystem;
2832

2933
namespace MonoDevelop.AspNetCore.Scaffolding
3034
{
35+
/// <summary>
36+
/// Return any type that doesn't have one of the filtered base classes, or one of the filtered assembly
37+
/// public keys
38+
/// </summary>
3139
class ModelVisitor : SymbolVisitor
3240
{
41+
static readonly string [] _filteredBaseClasses = new string [] {
42+
"System.Web.WebPages.WebPageExecutingBase", // Base class for Razor views
43+
"System.Web.UI.TemplateControl", // Base class for ASPX views
44+
"System.Web.HttpApplication", // Base class for Global.asax
45+
"System.Web.Mvc.Controller", // Base class for MVC controllers
46+
"System.Web.Http.ApiController" // Base class for API controllers
47+
};
48+
49+
static readonly string [] _filteredPublicKeys = new string [] {
50+
"b77a5c561934e089", // CLR types (mscorlib, System.dll, System.Core.dll, etc.)
51+
"b03f5f7f11d50a3a", // System.Web and friends
52+
"31bf3856ad364e35", // System.ComponentModel.DataAnnotations and friends
53+
"89845dcd8080cc91", // System.Data.SqlServerCE
54+
"30ad4fe6b2a6aeed", // Newtonsoft.Json
55+
"2780ccd10d57b246", // DotNetOpenAuth
56+
};
57+
58+
static readonly Dictionary<AssemblyIdentity, bool> _assemblyKeyFilteredCache = new Dictionary<AssemblyIdentity, bool> ();
59+
3360
public static List<ITypeSymbol> FindModelTypes (IAssemblySymbol assembly)
3461
{
3562
var visitor = new ModelVisitor ();
3663
visitor.Visit (assembly);
3764
return visitor._types;
3865
}
3966

40-
private readonly List<ITypeSymbol> _types;
67+
readonly List<ITypeSymbol> _types;
4168

42-
private ModelVisitor ()
69+
ModelVisitor ()
4370
{
4471
_types = new List<ITypeSymbol> ();
4572
}
@@ -62,7 +89,46 @@ public override void VisitNamespace (INamespaceSymbol symbol)
6289

6390
public override void VisitNamedType (INamedTypeSymbol symbol)
6491
{
65-
_types.Add (symbol);
92+
foreach (var type in symbol.GetTypeMembers ()) {
93+
Visit (type);
94+
}
95+
96+
if (IncludeTypeInAddViewModelClassDropdown (symbol))
97+
_types.Add (symbol);
98+
}
99+
100+
public static bool IncludeTypeInAddViewModelClassDropdown (INamedTypeSymbol symbol)
101+
{
102+
return symbol.DeclaredAccessibility == Accessibility.Public
103+
&& !symbol.IsStatic
104+
&& !symbol.IsGenericType
105+
&& !symbol.IsImplicitClass
106+
&& !symbol.IsAnonymousType
107+
&& !symbol.GetAttributes ().OfType<CompilerGeneratedAttribute> ().Any ()
108+
&& !IsSignedWithFilteredPublicKey (symbol)
109+
&& !IsDerivedFromFilteredBaseClass (symbol);
110+
}
111+
112+
static bool IsDerivedFromFilteredBaseClass (INamedTypeSymbol t)
113+
{
114+
if (_filteredBaseClasses.Any (baseClass => t.GetFullMetadataName ().Equals (baseClass, StringComparison.Ordinal))) {
115+
return true;
116+
}
117+
if (t.BaseType != null) {
118+
return IsDerivedFromFilteredBaseClass (t.BaseType);
119+
}
120+
return false;
121+
}
122+
123+
static bool IsSignedWithFilteredPublicKey (INamedTypeSymbol t)
124+
{
125+
var assembly = t.ContainingAssembly;
126+
if (!_assemblyKeyFilteredCache.TryGetValue (assembly.Identity, out var isFilteredKey)) {
127+
string publicKeyToken = BitConverter.ToString (assembly.Identity.PublicKeyToken.ToArray ()).Replace ("-", string.Empty);
128+
isFilteredKey = _filteredPublicKeys.Any (key => publicKeyToken.Equals (key, StringComparison.OrdinalIgnoreCase));
129+
_assemblyKeyFilteredCache [assembly.Identity] = isFilteredKey;
130+
}
131+
return isFilteredKey;
66132
}
67133
}
68134
}

main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.Scaffolding/ScaffolderArgs.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2424
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2525
// THE SOFTWARE.
26-
using System.Collections.ObjectModel;
27-
using System.ComponentModel;
28-
using System.Reflection;
29-
using MonoDevelop.Components;
26+
using System.Threading;
3027
using MonoDevelop.Core;
3128
using MonoDevelop.Projects;
3229

@@ -43,5 +40,6 @@ public override int GetHashCode ()
4340

4441
public DotNetProject Project { get; internal set; }
4542
public FilePath ParentFolder { get; internal set; }
43+
public CancellationToken CancellationToken { get; internal set; }
4644
}
4745
}

main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.Scaffolding/ScaffolderDialogController.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ class ScaffolderDialogController : WizardDialogControllerBase
4040
readonly ScaffolderArgs args;
4141

4242
readonly IWizardDialogPage firstPage;
43-
44-
Dictionary<ScaffolderArgs, ScaffolderTemplateConfigurePage> cachedPages
43+
readonly Dictionary<ScaffolderArgs, ScaffolderTemplateConfigurePage> cachedPages
4544
= new Dictionary<ScaffolderArgs, ScaffolderTemplateConfigurePage> ();
4645

4746
public override bool CanGoBack {
@@ -61,13 +60,13 @@ public ScaffolderDialogController (string title, Image icon, IWizardDialogPage f
6160
this.args = args;
6261
}
6362

64-
ScaffolderTemplateConfigurePage GetConfigurePage (ScaffolderArgs args)
63+
ScaffolderTemplateConfigurePage GetConfigurePage (ScaffolderArgs args, CancellationToken token)
6564
{
6665
// we want to return the same instance for the same args
6766
if (cachedPages.ContainsKey (args)) {
6867
return cachedPages [args];
6968
} else {
70-
var page = new ScaffolderTemplateConfigurePage (args);
69+
var page = new ScaffolderTemplateConfigurePage (args, token);
7170
cachedPages.Add (args, page);
7271
return page;
7372
}
@@ -77,7 +76,7 @@ protected override Task<IWizardDialogPage> OnGoNext (CancellationToken token)
7776
{
7877
switch (CurrentPage) {
7978
case ScaffolderTemplateSelectPage _:
80-
IWizardDialogPage configPage = GetConfigurePage (args);
79+
IWizardDialogPage configPage = GetConfigurePage (args, token);
8180
return Task.FromResult (configPage);
8281
}
8382
return Task.FromException<IWizardDialogPage> (new InvalidOperationException ());

main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.Scaffolding/ScaffolderTemplateConfigurePage.cs

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,22 @@
2424
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2525
// THE SOFTWARE.
2626
using System.Linq;
27+
using System.Threading;
28+
using System.Threading.Tasks;
29+
using MonoDevelop.Core;
2730
using Xwt;
2831

2932
namespace MonoDevelop.AspNetCore.Scaffolding
3033
{
3134
class ScaffolderTemplateConfigurePage : ScaffolderWizardPageBase
3235
{
33-
ScaffolderBase scaffolder;
36+
readonly ScaffolderBase scaffolder;
3437

35-
public ScaffolderTemplateConfigurePage (ScaffolderArgs args) : base (args)
38+
public ScaffolderTemplateConfigurePage (ScaffolderArgs args, CancellationToken token) : base (args)
3639
{
3740
scaffolder = args.Scaffolder;
38-
this.SubSubTitle = scaffolder.Name;
41+
SubSubTitle = scaffolder.Name;
42+
args.CancellationToken = token;
3943
}
4044

4145
protected override Widget GetMainControl ()
@@ -45,16 +49,16 @@ protected override Widget GetMainControl ()
4549

4650
var rowCount = fields.Count ();
4751
int rowAdditionCount = 0;
48-
for(int fieldIndex = 0; fieldIndex < rowCount; fieldIndex++) {
52+
for (int fieldIndex = 0; fieldIndex < rowCount; fieldIndex++) {
4953
int rowIndex = fieldIndex + rowAdditionCount;
50-
var field = fields[fieldIndex];
54+
var field = fields [fieldIndex];
5155
var label = new Label ();
5256

5357
switch (field) {
5458
case StringField s:
5559
var input = new TextEntry ();
5660
label.Text = s.DisplayName;
57-
table.Add (label, 0, rowIndex, hpos:WidgetPlacement.End);
61+
table.Add (label, 0, rowIndex, hpos: WidgetPlacement.End);
5862
table.Add (input, 1, rowIndex);
5963
input.Changed += (sender, args) => s.SelectedValue = input.Text;
6064
input.SetFocus ();
@@ -65,38 +69,50 @@ protected override Widget GetMainControl ()
6569
var comboBoxEntry = new ComboBoxEntry ();
6670
comboBoxEntry.TextEntry.Changed += (sender, args) => comboField.SelectedValue = comboBoxEntry.TextEntry.Text;
6771
comboBox = comboBoxEntry;
68-
} else {
72+
} else {
6973
comboBox = new ComboBox ();
70-
}
71-
72-
foreach (var option in comboField.Options) {
73-
comboBox.Items.Add (option);
7474
}
7575

76+
Task.Run (async () => {
77+
var options = await comboField.Options;
78+
await Runtime.RunInMainThread (() => {
79+
if (Args.CancellationToken.IsCancellationRequested) {
80+
return;
81+
}
82+
Xwt.Toolkit.NativeEngine.Invoke (() => {
83+
foreach (var option in options) {
84+
comboBox.Items.Add (option);
85+
}
86+
comboField.SelectedValue = options.FirstOrDefault ();
87+
if (comboBox.Items.Count > 0)
88+
comboBox.SelectedIndex = 0;
89+
});
90+
91+
});
92+
}, Args.CancellationToken);
93+
7694
label.Text = comboField.DisplayName;
7795

78-
table.Add (label, 0, rowIndex, hpos:WidgetPlacement.End);
96+
table.Add (label, 0, rowIndex, hpos: WidgetPlacement.End);
7997
table.Add (comboBox, 1, rowIndex);
80-
comboField.SelectedValue = comboField.Options.FirstOrDefault ();
8198
comboBox.TextInput += (sender, args) => comboField.SelectedValue = comboBox.SelectedText;
8299

83100
comboBox.SelectionChanged += (sender, args) => comboField.SelectedValue = comboBox.SelectedText;
84101

85-
if (comboBox.Items.Count > 0)
86-
comboBox.SelectedIndex = 0;
87102
break;
88103
case BoolFieldList boolFieldList:
89104
label.Text = boolFieldList.DisplayName;
90-
table.Add (label, 0, rowIndex, hpos:WidgetPlacement.End, vpos:WidgetPlacement.Start);
105+
table.Add (label, 0, rowIndex, hpos: WidgetPlacement.End, vpos: WidgetPlacement.Start);
91106
var vbox = new VBox ();
92-
for(int i = 0; i < boolFieldList.Options.Count; i++) {
107+
for (int i = 0; i < boolFieldList.Options.Count; i++) {
93108
var boolField = boolFieldList.Options [i];
94-
var checkbox = new CheckBox (boolField.DisplayName);
95-
checkbox.Active = boolField.Selected;
96-
checkbox.Sensitive = boolField.Enabled;
109+
var checkbox = new CheckBox (boolField.DisplayName) {
110+
Active = boolField.Selected,
111+
Sensitive = boolField.Enabled
112+
};
97113
checkbox.Toggled += (sender, args) => boolField.Selected = checkbox.Active;
98114
vbox.PackStart (checkbox);
99-
}
115+
}
100116
table.Add (vbox, 1, rowIndex);
101117
break;
102118
case FileField fileField:
@@ -105,15 +121,15 @@ protected override Widget GetMainControl ()
105121
// This doesn't work with native toolkit!
106122
var filter = new FileDialogFilter (fileField.FilterWildcard, fileField.FilterWildcard);
107123
fileSelector.Filters.Add (filter);
108-
}
109-
table.Add (fileSelector, 0, rowIndex, colspan:2);
124+
}
125+
table.Add (fileSelector, 0, rowIndex, colspan: 2);
110126
label.Text = fileField.DisplayName;
111-
table.Add (label, 0, rowIndex + 1, colspan:2);
127+
table.Add (label, 0, rowIndex + 1, colspan: 2);
112128
rowAdditionCount++;
113129
fileSelector.FileChanged += (sender, args) => fileField.SelectedValue = fileSelector.FileName;
114130
break;
115131
}
116-
132+
117133
}
118134
return table;
119135
}

main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.Scaffolding/ScaffolderTemplateSelectPage.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2525
// THE SOFTWARE.
2626
using System;
27+
using System.Threading;
2728
using Xwt;
2829
using Xwt.Drawing;
2930

main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.Scaffolding/ScaffolderWizard.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//
1+
//
22
// Scaffolder.cs
33
//
44
// Author:
@@ -26,6 +26,7 @@
2626
using System;
2727
using System.Collections.Generic;
2828
using System.Linq;
29+
using System.Threading;
2930
using System.Threading.Tasks;
3031
using MonoDevelop.Components;
3132
using MonoDevelop.Core;
@@ -153,7 +154,7 @@ internal string GetArguments (ScaffolderArgs args)
153154
argBuilder.AddQuoted (project.FileName);
154155
argBuilder.Add (args.Scaffolder.CommandLineName);
155156

156-
foreach(var field in args.Scaffolder.Fields) {
157+
foreach (var field in args.Scaffolder.Fields) {
157158
argBuilder.Add (field.CommandLineName);
158159
argBuilder.Add (field.SelectedValue);
159160
}

main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.Scaffolding/ScaffolderWizardPageBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public string SubSubTitle {
4444
protected set => subSubTitle = value;
4545
}
4646

47-
public ScaffolderArgs Args { get; }
47+
protected ScaffolderArgs Args { get; }
4848

4949
protected override Control CreateControl ()
5050
{

main/src/addins/MonoDevelop.AspNetCore/MonoDevelop.AspNetCore.Scaffolding/Scaffolders/ApiControllerEntityFrameworkScaffolder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ public ApiControllerEntityFrameworkScaffolder (ScaffolderArgs args) : base (args
4444
IEnumerable<ScaffolderField> GetFields ()
4545
{
4646
fields = new ScaffolderField [] {
47-
GetModelField(args.Project),
48-
GetDbContextField(args.Project),
47+
GetModelField(args),
48+
GetDbContextField(args),
4949
new StringField ("-name", "Controller name:"),
5050

5151
};

0 commit comments

Comments
 (0)