Browse Source

Support creating strongly typed views for ASP.NET MVC.

pull/18/head
Matt Ward 14 years ago
parent
commit
2511b29778
  1. 18
      src/AddIns/BackendBindings/AspNet.Mvc/Project/ItemTemplates/CSharp/CodeTemplates/AddView/AspxCSharp/Empty.tt
  2. 17
      src/AddIns/BackendBindings/AspNet.Mvc/Project/ItemTemplates/CSharp/CodeTemplates/AddView/CSHTML/Empty.tt
  3. 17
      src/AddIns/BackendBindings/AspNet.Mvc/Project/ItemTemplates/VisualBasic/CodeTemplates/AddView/AspxVisualBasic/Empty.tt
  4. 16
      src/AddIns/BackendBindings/AspNet.Mvc/Project/ItemTemplates/VisualBasic/CodeTemplates/AddView/VBHTML/Empty.tt
  5. 6
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/AddMvcViewToProjectView.xaml
  6. 16
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/AddMvcViewToProjectViewModel.cs
  7. 1
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/IMvcTextTemplateHost.cs
  8. 1
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/IMvcViewFileGenerator.cs
  9. 5
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/MvcModelClassViewModel.cs
  10. 8
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/MvcTextTemplateHost.cs
  11. 5
      src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/MvcViewFileGenerator.cs
  12. 6
      src/AddIns/BackendBindings/AspNet.Mvc/Test/Helpers/FakeMvcProject.cs
  13. 1
      src/AddIns/BackendBindings/AspNet.Mvc/Test/Helpers/FakeMvcTextTemplateHost.cs
  14. 1
      src/AddIns/BackendBindings/AspNet.Mvc/Test/Helpers/FakeMvcViewFileGenerator.cs
  15. 78
      src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/AddMvcViewToProjectViewModelTests.cs
  16. 15
      src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/MvcModelClassViewModelTests.cs
  17. 10
      src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/MvcTextTemplateHostTests.cs
  18. 23
      src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/MvcViewFileGeneratorTests.cs

18
src/AddIns/BackendBindings/AspNet.Mvc/Project/ItemTemplates/CSharp/CodeTemplates/AddView/AspxCSharp/Empty.tt

@ -1,12 +1,12 @@ @@ -1,12 +1,12 @@
<#@ template language="C#" HostSpecific="true" #>
<#
MvcTextTemplateHost mvcHost = (MvcTextTemplateHost)Host;
mvcHost = (MvcTextTemplateHost)Host;
#>
<# if (mvcHost.IsPartialView) { #>
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<# } else { #>
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<#= GetViewPageType() #>" %>
<!DOCTYPE html>
<html>
@ -19,4 +19,16 @@ @@ -19,4 +19,16 @@
</div>
</body>
</html>
<# } #>
<# } #>
<#+
MvcTextTemplateHost mvcHost;
string GetViewPageType()
{
string viewDataTypeName = mvcHost.ViewDataTypeName;
if (!String.IsNullOrEmpty(viewDataTypeName)) {
return String.Format("<{0}>", viewDataTypeName);
}
return String.Empty;
}
#>

17
src/AddIns/BackendBindings/AspNet.Mvc/Project/ItemTemplates/CSharp/CodeTemplates/AddView/CSHTML/Empty.tt

@ -1,11 +1,12 @@ @@ -1,11 +1,12 @@
<#@ template language="C#" HostSpecific="true" #>
<#@ output extension=".cshtml" #>
<#
MvcTextTemplateHost mvcHost = (MvcTextTemplateHost)Host;
mvcHost = (MvcTextTemplateHost)Host;
#>
<# if (mvcHost.IsPartialView) { #>
<# } else { #>
<#= GetModelDirective() #>
<!DOCTYPE html>
<html>
@ -18,4 +19,16 @@ @@ -18,4 +19,16 @@
</div>
</body>
</html>
<# } #>
<# } #>
<#+
MvcTextTemplateHost mvcHost;
string GetModelDirective()
{
string viewDataTypeName = mvcHost.ViewDataTypeName;
if (!String.IsNullOrEmpty(viewDataTypeName)) {
return String.Format("@model {0}", viewDataTypeName);
}
return String.Empty;
}
#>

17
src/AddIns/BackendBindings/AspNet.Mvc/Project/ItemTemplates/VisualBasic/CodeTemplates/AddView/AspxVisualBasic/Empty.tt

@ -1,12 +1,12 @@ @@ -1,12 +1,12 @@
<#@ template language="VB" HostSpecific="true" #>
<#
Dim mvcHost As MvcTextTemplateHost = DirectCast(Host, MvcTextTemplateHost)
mvcHost = DirectCast(Host, MvcTextTemplateHost)
#>
<# If mvcHost.IsPartialView Then #>
<%@ Control Language="VB" Inherits="System.Web.Mvc.ViewUserControl" %>
<# Else #>
<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage" %>
<%@ Page Language="VB" Inherits="System.Web.Mvc.ViewPage<#= GetViewPageType() #>" %>
<!DOCTYPE html>
<html>
@ -19,4 +19,15 @@ @@ -19,4 +19,15 @@
</div>
</body>
</html>
<# End If #>
<# End If #>
<#+
Private mvcHost As MvcTextTemplateHost
Function GetViewPageType() As String
Dim viewDataTypeName As String = mvcHost.ViewDataTypeName
If Not String.IsNullOrEmpty(viewDataTypeName) Then
Return String.Format("(Of {0})", viewDataTypeName)
End If
Return String.Empty
End Function
#>

16
src/AddIns/BackendBindings/AspNet.Mvc/Project/ItemTemplates/VisualBasic/CodeTemplates/AddView/VBHTML/Empty.tt

@ -1,11 +1,12 @@ @@ -1,11 +1,12 @@
<#@ template language="VB" HostSpecific="true" #>
<#@ output extension=".vbhtml" #>
<#
Dim mvcHost As MvcTextTemplateHost = DirectCast(Host, MvcTextTemplateHost)
mvcHost = DirectCast(Host, MvcTextTemplateHost)
#>
<# If mvcHost.IsPartialView Then #>
<# Else #>
<#= GetModelDirective() #>
<!DOCTYPE html>
<html>
@ -18,4 +19,15 @@ @@ -18,4 +19,15 @@
</div>
</body>
</html>
<# End If #>
<# End If #>
<#+
Private mvcHost As MvcTextTemplateHost
Function GetModelDirective() As String
Dim viewDataTypeName As String = mvcHost.ViewDataTypeName
If Not String.IsNullOrEmpty(viewDataTypeName) Then
Return String.Format("@ModelType {0}", viewDataTypeName)
End If
Return String.Empty
End Function
#>

6
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/AddMvcViewToProjectView.xaml

@ -18,10 +18,6 @@ @@ -18,10 +18,6 @@
<DataTemplate x:Key="ViewEngineTemplate">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate x:Key="ModelClassTemplate">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</Window.Resources>
<Grid>
@ -90,7 +86,7 @@ @@ -90,7 +86,7 @@
IsEditable="True"
IsEnabled="{Binding Path=IsStronglyTypedView}"
ItemsSource="{Binding Path=ModelClasses}"
ItemTemplate="{StaticResource ModelClassTemplate}"
Text="{Binding Path=ModelClassName, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding Path=SelectedModelClass}"/>
<StackPanel

16
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/AddMvcViewToProjectViewModel.cs

@ -34,6 +34,7 @@ namespace ICSharpCode.AspNet.Mvc @@ -34,6 +34,7 @@ namespace ICSharpCode.AspNet.Mvc
this.selectedViewFolder = selectedViewFolder;
this.viewGenerator = viewGenerator;
this.viewFileName.Folder = selectedViewFolder.Path;
this.ModelClassName = String.Empty;
CreateModelClassesForSelectedFolder();
CreateCommands();
@ -128,11 +129,23 @@ namespace ICSharpCode.AspNet.Mvc @@ -128,11 +129,23 @@ namespace ICSharpCode.AspNet.Mvc
void ConfigureMvcViewGenerator()
{
viewGenerator.ModelClassName = GetModelClassName();
viewGenerator.Project = selectedViewFolder.Project;
viewGenerator.TemplateLanguage = GetTemplateLanguage();
viewGenerator.TemplateType = selectedViewEngine.TemplateType;
}
string GetModelClassName()
{
if (IsStronglyTypedView) {
if (SelectedModelClass != null) {
return SelectedModelClass.FullyQualifiedName;
}
return ModelClassName.Trim();
}
return String.Empty;
}
MvcTextTemplateLanguage GetTemplateLanguage()
{
return selectedViewFolder.GetTemplateLanguage();
@ -165,7 +178,8 @@ namespace ICSharpCode.AspNet.Mvc @@ -165,7 +178,8 @@ namespace ICSharpCode.AspNet.Mvc
get { return modelClassesForSelectedFolder.ModelClasses; }
}
public string SelectedModelClass { get; set; }
public MvcModelClassViewModel SelectedModelClass { get; set; }
public string ModelClassName { get; set; }
}
}

1
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/IMvcTextTemplateHost.cs

@ -14,6 +14,7 @@ namespace ICSharpCode.AspNet.Mvc @@ -14,6 +14,7 @@ namespace ICSharpCode.AspNet.Mvc
// Add View properties.
string ViewName { get; set; }
bool IsPartialView { get; set; }
string ViewDataTypeName { get; set; }
// Add Controller properties.
string ControllerName { get; set; }

1
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/IMvcViewFileGenerator.cs

@ -11,6 +11,7 @@ namespace ICSharpCode.AspNet.Mvc @@ -11,6 +11,7 @@ namespace ICSharpCode.AspNet.Mvc
MvcTextTemplateLanguage TemplateLanguage { get; set; }
MvcTextTemplateType TemplateType { get; set; }
IMvcProject Project { get; set; }
string ModelClassName { get; set; }
void GenerateFile(MvcViewFileName fileName);
}

5
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/MvcModelClassViewModel.cs

@ -30,6 +30,9 @@ namespace ICSharpCode.AspNet.Mvc @@ -30,6 +30,9 @@ namespace ICSharpCode.AspNet.Mvc
{
return Name;
}
public string FullyQualifiedName {
get { return mvcClass.FullyQualifiedName; }
}
}
}

8
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/MvcTextTemplateHost.cs

@ -9,8 +9,9 @@ namespace ICSharpCode.AspNet.Mvc @@ -9,8 +9,9 @@ namespace ICSharpCode.AspNet.Mvc
public class MvcTextTemplateHost : TextTemplatingHost, IMvcTextTemplateHost
{
string viewName = String.Empty;
MvcControllerName controllerName = new MvcControllerName();
string viewDataTypeName = String.Empty;
string @namespace = String.Empty;
MvcControllerName controllerName = new MvcControllerName();
public MvcTextTemplateHost(
ITextTemplatingAppDomainFactory appDomainFactory,
@ -46,6 +47,11 @@ namespace ICSharpCode.AspNet.Mvc @@ -46,6 +47,11 @@ namespace ICSharpCode.AspNet.Mvc
return String.Empty;
}
public string ViewDataTypeName {
get { return viewDataTypeName; }
set { viewDataTypeName = UseEmptyStringIfNull(value); }
}
public string ControllerName {
get { return controllerName.Name; }
set { controllerName.Name = value; }

5
src/AddIns/BackendBindings/AspNet.Mvc/Project/Src/MvcViewFileGenerator.cs

@ -23,9 +23,11 @@ namespace ICSharpCode.AspNet.Mvc @@ -23,9 +23,11 @@ namespace ICSharpCode.AspNet.Mvc
: base(hostFactory)
{
this.textTemplateRepository = textTemplateRepository;
ModelClassName = String.Empty;
}
public MvcTextTemplateType TemplateType { get; set; }
public string ModelClassName { get; set; }
public void GenerateFile(MvcViewFileName fileName)
{
@ -35,8 +37,9 @@ namespace ICSharpCode.AspNet.Mvc @@ -35,8 +37,9 @@ namespace ICSharpCode.AspNet.Mvc
protected override void ConfigureHost(IMvcTextTemplateHost host, MvcFileName fileName)
{
var viewFileName = fileName as MvcViewFileName;
host.ViewName = viewFileName.ViewName;
host.IsPartialView = viewFileName.IsPartialView;
host.ViewDataTypeName = ModelClassName;
host.ViewName = viewFileName.ViewName;
}
protected override string GetTextTemplateFileName()

6
src/AddIns/BackendBindings/AspNet.Mvc/Test/Helpers/FakeMvcProject.cs

@ -50,6 +50,12 @@ namespace AspNet.Mvc.Tests.Helpers @@ -50,6 +50,12 @@ namespace AspNet.Mvc.Tests.Helpers
ModelClasses.Add(fakeClass);
}
public void AddModelClassToProject(string fullyQualifiedName)
{
var fakeClass = new FakeMvcClass(fullyQualifiedName);
ModelClasses.Add(fakeClass);
}
public int GetModelClassesCallCount;
public IEnumerable<IMvcClass> GetModelClasses()

1
src/AddIns/BackendBindings/AspNet.Mvc/Test/Helpers/FakeMvcTextTemplateHost.cs

@ -38,6 +38,7 @@ namespace AspNet.Mvc.Tests.Helpers @@ -38,6 +38,7 @@ namespace AspNet.Mvc.Tests.Helpers
public string Namespace { get; set; }
public bool AddActionMethods { get; set; }
public bool IsPartialView { get; set; }
public string ViewDataTypeName { get; set; }
public CompilerErrorCollection Errors { get; set; }
}

1
src/AddIns/BackendBindings/AspNet.Mvc/Test/Helpers/FakeMvcViewFileGenerator.cs

@ -12,6 +12,7 @@ namespace AspNet.Mvc.Tests.Helpers @@ -12,6 +12,7 @@ namespace AspNet.Mvc.Tests.Helpers
public MvcTextTemplateLanguage TemplateLanguage { get; set; }
public MvcTextTemplateType TemplateType { get; set; }
public IMvcProject Project { get; set; }
public string ModelClassName { get; set; }
public bool IsGenerateFileCalled;
public MvcViewFileName FileNamePassedToGenerateFile;

78
src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/AddMvcViewToProjectViewModelTests.cs

@ -80,6 +80,11 @@ namespace AspNet.Mvc.Tests @@ -80,6 +80,11 @@ namespace AspNet.Mvc.Tests
fakeProject.AddModelClassToProject(ns, name);
}
void AddModelClassToProject(string fullyQualifiedClassName)
{
fakeProject.AddModelClassToProject(fullyQualifiedClassName);
}
[Test]
public void AddMvcViewCommand_ExecutedWhenViewNameSpecified_MvcViewIsGenerated()
{
@ -435,5 +440,78 @@ namespace AspNet.Mvc.Tests @@ -435,5 +440,78 @@ namespace AspNet.Mvc.Tests
bool contains = propertyChangedEvents.Contains("IsStronglyTypedView");
Assert.IsTrue(contains);
}
[Test]
public void AddMvcView_ModelClassSelected_ModelClassNameSetInGenerator()
{
CreateViewModel();
CSharpProjectSelected();
AddModelClassToProject("ICSharpCode.MyProject.MyModel");
viewModel.IsStronglyTypedView = true;
viewModel.SelectedModelClass = viewModel.ModelClasses.First();
viewModel.AddMvcView();
string modelClassName = fakeViewGenerator.ModelClassName;
Assert.AreEqual("ICSharpCode.MyProject.MyModel", modelClassName);
}
[Test]
public void AddMvcView_ModelClassSelectedThenIsStronglyTypedIsSetToFalse_ModelClassNameIsInGeneratorIsEmptyString()
{
CreateViewModel();
CSharpProjectSelected();
AddModelClassToProject("ICSharpCode.MyProject.MyModel");
viewModel.IsStronglyTypedView = true;
viewModel.SelectedModelClass = viewModel.ModelClasses.First();
viewModel.IsStronglyTypedView = false;
viewModel.AddMvcView();
string modelClassName = fakeViewGenerator.ModelClassName;
Assert.AreEqual(String.Empty, modelClassName);
}
[Test]
public void AddMvcView_ModelClassNameTypedInByUser_ModelClassNameIsUsedInGenerator()
{
CreateViewModel();
CSharpProjectSelected();
AddModelClassToProject("ICSharpCode.MyProject.MyModel");
viewModel.IsStronglyTypedView = true;
viewModel.SelectedModelClass = null;
viewModel.ModelClassName = "MyNamespace.MyClass";
viewModel.AddMvcView();
string modelClassName = fakeViewGenerator.ModelClassName;
Assert.AreEqual("MyNamespace.MyClass", modelClassName);
}
[Test]
public void ModelClassName_NewViewModelInstanceCreated_ReturnsEmptyStringByDefault()
{
CreateViewModel();
string modelClassName = viewModel.ModelClassName;
Assert.AreEqual(String.Empty, modelClassName);
}
[Test]
public void AddMvcView_ModelClassNameTypedInByUserHasSpacesAtStartAndEnd_ModelClassNameWithoutSpacesIsUsedInGenerator()
{
CreateViewModel();
CSharpProjectSelected();
AddModelClassToProject("ICSharpCode.MyProject.MyModel");
viewModel.IsStronglyTypedView = true;
viewModel.SelectedModelClass = null;
viewModel.ModelClassName = " MyNamespace.MyClass ";
viewModel.AddMvcView();
string modelClassName = fakeViewGenerator.ModelClassName;
Assert.AreEqual("MyNamespace.MyClass", modelClassName);
}
}
}

15
src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/MvcModelClassViewModelTests.cs

@ -20,6 +20,12 @@ namespace AspNet.Mvc.Tests @@ -20,6 +20,12 @@ namespace AspNet.Mvc.Tests
viewModel = new MvcModelClassViewModel(fakeClass);
}
void CreateViewModel(string fullyQualifiedClassName)
{
fakeClass = new FakeMvcClass(fullyQualifiedClassName);
viewModel = new MvcModelClassViewModel(fakeClass);
}
[Test]
public void Name_ClassHasNamespaceAndName_ReturnsClassNameFollowedByNamespace()
{
@ -37,5 +43,14 @@ namespace AspNet.Mvc.Tests @@ -37,5 +43,14 @@ namespace AspNet.Mvc.Tests
Assert.AreEqual("MyClass (ICSharpCode.Tests)", text);
}
[Test]
public void FullyQualifiedName_ClassHasNamespaceAndName_ReturnsFullyQualifiedClassName()
{
CreateViewModel("ICSharpCode.Tests.MyClass");
string name = viewModel.FullyQualifiedName;
Assert.AreEqual("ICSharpCode.Tests.MyClass", name);
}
}
}

10
src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/MvcTextTemplateHostTests.cs

@ -86,5 +86,15 @@ namespace AspNet.Mvc.Tests @@ -86,5 +86,15 @@ namespace AspNet.Mvc.Tests
Assert.AreEqual("Home", controllerRootName);
}
[Test]
public void ViewDataTypeName_SetToNull_ReturnsEmptyString()
{
CreateHost();
host.ViewDataTypeName = null;
string typeName = host.ViewDataTypeName;
Assert.AreEqual(String.Empty, typeName);
}
}
}

23
src/AddIns/BackendBindings/AspNet.Mvc/Test/Src/MvcViewFileGeneratorTests.cs

@ -215,5 +215,28 @@ namespace AspNet.Mvc.Tests @@ -215,5 +215,28 @@ namespace AspNet.Mvc.Tests
Assert.AreEqual(expectedOutputFileGenerated, outputFileGenerated);
}
[Test]
public void GenerateFile_ModelClassNameIsSet_MvcTextTemplateHostHasViewDataTypeNameIsSetToModelClassName()
{
CreateGenerator();
ProjectPassedToGeneratorIsCSharpProject();
SelectAspxTemplate();
generator.ModelClassName = "MyNamespace.MyModel";
GenerateFile();
string viewDataTypeName = fakeHost.ViewDataTypeName;
Assert.AreEqual("MyNamespace.MyModel", viewDataTypeName);
}
[Test]
public void ModelClassName_DefaultValue_ReturnsEmptyString()
{
CreateGenerator();
string modelClassName = generator.ModelClassName;
Assert.AreEqual(String.Empty, modelClassName);
}
}
}

Loading…
Cancel
Save