[Fixes #3624] MVC functional test cleanup (part 2)

This commit is contained in:
Kiran Challa 2015-11-24 10:27:43 -08:00
parent 3a7c9c73ed
commit 57b88baad0
72 changed files with 1133 additions and 1390 deletions

View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24711.0
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject
@ -85,6 +85,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TestDi
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSandbox", "samples\MvcSandbox\MvcSandbox.xproj", "{14ED4476-9F24-4776-8417-EA6927F6C9C9}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UrlHelperSample.Web", "samples\UrlHelperSample.Web\UrlHelperSample.Web.xproj", "{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -493,6 +495,18 @@ Global
{14ED4476-9F24-4776-8417-EA6927F6C9C9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{14ED4476-9F24-4776-8417-EA6927F6C9C9}.Release|x86.ActiveCfg = Release|Any CPU
{14ED4476-9F24-4776-8417-EA6927F6C9C9}.Release|x86.Build.0 = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|x86.ActiveCfg = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|x86.Build.0 = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|Any CPU.Build.0 = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|x86.ActiveCfg = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -533,5 +547,6 @@ Global
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{9879B5D5-2325-4A81-B4DF-F279FE8FEEB4} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{14ED4476-9F24-4776-8417-EA6927F6C9C9} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
EndGlobalSection
EndGlobal

60
Mvc.sln
View File

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.24711.0
VisualStudioVersion = 14.0.24720.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
EndProject
@ -54,8 +54,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ContentNegotiationWebSite",
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FiltersWebSite", "test\WebSites\FiltersWebSite\FiltersWebSite.xproj", "{1976AC4A-FEA4-4587-A158-D9F79736D2B6}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UrlHelperWebSite", "test\WebSites\UrlHelperWebSite\UrlHelperWebSite.xproj", "{A192E504-2881-41DC-90D1-B7F1DD1134E8}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ApiExplorerWebSite", "test\WebSites\ApiExplorerWebSite\ApiExplorerWebSite.xproj", "{61061528-071E-424E-965A-07BCC2F02672}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "VersioningWebSite", "test\WebSites\VersioningWebSite\VersioningWebSite.xproj", "{C6304029-78C8-4604-99BE-2078DCA1DD36}"
@ -98,12 +96,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ActionConstraintsWebSite",
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CustomRouteWebSite", "test\WebSites\CustomRouteWebSite\CustomRouteWebSite.xproj", "{364EC3C6-C9DB-45E0-A0F2-1EE61E4B429B}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ResponseCacheWebSite", "test\WebSites\ResponseCacheWebSite\ResponseCacheWebSite.xproj", "{BDEEBE09-C0C4-433C-B0B8-8478C9776996}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "XmlFormattersWebSite", "test\WebSites\XmlFormattersWebSite\XmlFormattersWebSite.xproj", "{C3123A70-41C4-4122-AD1C-D35DF8958DD7}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ValidationWebSite", "test\WebSites\ValidationWebSite\ValidationWebSite.xproj", "{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FormatFilterWebSite", "test\WebSites\FormatFilterWebSite\FormatFilterWebSite.xproj", "{AC9BE567-540E-4C70-90C2-AAF021307A80}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ControllersFromServicesWebSite", "test\WebSites\ControllersFromServicesWebSite\ControllersFromServicesWebSite.xproj", "{983741B2-4424-4ED1-9B03-7675A67230C8}"
@ -168,6 +162,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.TestDi
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "MvcSandbox", "samples\MvcSandbox\MvcSandbox.xproj", "{14ED4476-9F24-4776-8417-EA6927F6C9C9}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UrlHelperSample.Web", "samples\UrlHelperSample.Web\UrlHelperSample.Web.xproj", "{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -368,16 +364,6 @@ Global
{1976AC4A-FEA4-4587-A158-D9F79736D2B6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{1976AC4A-FEA4-4587-A158-D9F79736D2B6}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{1976AC4A-FEA4-4587-A158-D9F79736D2B6}.Release|x86.ActiveCfg = Release|Any CPU
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Debug|x86.ActiveCfg = Debug|Any CPU
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Release|Any CPU.Build.0 = Release|Any CPU
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Release|x86.ActiveCfg = Release|Any CPU
{61061528-071E-424E-965A-07BCC2F02672}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61061528-071E-424E-965A-07BCC2F02672}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61061528-071E-424E-965A-07BCC2F02672}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -604,18 +590,6 @@ Global
{364EC3C6-C9DB-45E0-A0F2-1EE61E4B429B}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{364EC3C6-C9DB-45E0-A0F2-1EE61E4B429B}.Release|x86.ActiveCfg = Release|Any CPU
{364EC3C6-C9DB-45E0-A0F2-1EE61E4B429B}.Release|x86.Build.0 = Release|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Debug|x86.ActiveCfg = Debug|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Debug|x86.Build.0 = Debug|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Release|Any CPU.Build.0 = Release|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Release|x86.ActiveCfg = Release|Any CPU
{BDEEBE09-C0C4-433C-B0B8-8478C9776996}.Release|x86.Build.0 = Release|Any CPU
{C3123A70-41C4-4122-AD1C-D35DF8958DD7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C3123A70-41C4-4122-AD1C-D35DF8958DD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C3123A70-41C4-4122-AD1C-D35DF8958DD7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -628,18 +602,6 @@ Global
{C3123A70-41C4-4122-AD1C-D35DF8958DD7}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{C3123A70-41C4-4122-AD1C-D35DF8958DD7}.Release|x86.ActiveCfg = Release|Any CPU
{C3123A70-41C4-4122-AD1C-D35DF8958DD7}.Release|x86.Build.0 = Release|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|x86.ActiveCfg = Debug|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Debug|x86.Build.0 = Debug|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|Any CPU.Build.0 = Release|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|x86.ActiveCfg = Release|Any CPU
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0}.Release|x86.Build.0 = Release|Any CPU
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
@ -1023,6 +985,18 @@ Global
{14ED4476-9F24-4776-8417-EA6927F6C9C9}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{14ED4476-9F24-4776-8417-EA6927F6C9C9}.Release|x86.ActiveCfg = Release|Any CPU
{14ED4476-9F24-4776-8417-EA6927F6C9C9}.Release|x86.Build.0 = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|Any CPU.Build.0 = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|x86.ActiveCfg = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Debug|x86.Build.0 = Debug|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|Any CPU.ActiveCfg = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|Any CPU.Build.0 = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|x86.ActiveCfg = Release|Any CPU
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -1048,7 +1022,6 @@ Global
{EE1AB716-F102-4CA3-AD2C-214A44B459A0} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{1976AC4A-FEA4-4587-A158-D9F79736D2B6} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{A192E504-2881-41DC-90D1-B7F1DD1134E8} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{61061528-071E-424E-965A-07BCC2F02672} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{C6304029-78C8-4604-99BE-2078DCA1DD36} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{6DB9B8D0-80F7-4E70-BBB0-0B4C04D79A47} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
@ -1070,9 +1043,7 @@ Global
{AD545A5B-2BA5-4314-88AC-FC2ACF2CC718} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{AF210F69-9D31-43AF-AC3A-CD366E252218} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{364EC3C6-C9DB-45E0-A0F2-1EE61E4B429B} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{BDEEBE09-C0C4-433C-B0B8-8478C9776996} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{C3123A70-41C4-4122-AD1C-D35DF8958DD7} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{AC9BE567-540E-4C70-90C2-AAF021307A80} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{983741B2-4424-4ED1-9B03-7675A67230C8} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
{551DC89E-2A13-4CF2-83D7-1ADD802443D5} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
@ -1105,5 +1076,6 @@ Global
{8FC726B5-E766-44E0-8B38-1313B6D8D9A7} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{9879B5D5-2325-4A81-B4DF-F279FE8FEEB4} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
{14ED4476-9F24-4776-8417-EA6927F6C9C9} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
{73F095D2-D0BD-4D03-BC17-D7A5EF0C0191} = {DAAE4C74-D06F-4874-A166-33305D2643CE}
EndGlobalSection
EndGlobal

View File

@ -1,3 +1,7 @@
/// <autosync enabled="true" />
/// <reference path="../gulpfile.js" />
/// <reference path="js/site.js" />
/// <reference path="lib/bootstrap/dist/js/bootstrap.js" />
/// <reference path="lib/jquery/dist/jquery.js" />
/// <reference path="lib/jquery-validation/dist/jquery.validate.js" />
/// <reference path="lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js" />

View File

@ -1,7 +1,7 @@
// 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 UrlHelperWebSite
namespace UrlHelperSample.Web
{
public class AppOptions
{

View File

@ -3,7 +3,7 @@
using Microsoft.AspNet.Mvc;
namespace UrlHelperWebSite.Controllers
namespace UrlHelperSample.Web.Controllers
{
public class HomeController : Controller
{

View File

@ -4,7 +4,7 @@
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Routing;
namespace UrlHelperWebSite.Controllers
namespace UrlHelperSample.Web.Controllers
{
[Route("api/[controller]/{id?}", Name = "SimplePocoApi")]
public class SimplePocoController

View File

@ -0,0 +1,66 @@
// 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;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Routing;
namespace UrlHelperSample.Web
{
/// <summary>
/// Following are some of the scenarios exercised here:
/// 1. Based on configuration, generate Content urls pointing to local or a CDN server
/// 2. Based on configuration, generate lower case urls
/// </summary>
public class CustomUrlHelper : UrlHelper
{
private readonly AppOptions _options;
public CustomUrlHelper(ActionContext actionContext, AppOptions options)
: base(actionContext)
{
_options = options;
}
/// <summary>
/// Depending on config data, generates an absolute url pointing to a CDN server
/// or falls back to the default behavior
/// </summary>
/// <param name="contentPath">The virtual path of the content.</param>
/// <returns>The absolute url.</returns>
public override string Content(string contentPath)
{
if (_options.ServeCDNContent
&& contentPath.StartsWith("~/", StringComparison.Ordinal))
{
var segment = new PathString(contentPath.Substring(1));
return ConvertToLowercaseUrl(_options.CDNServerBaseUrl + segment);
}
return ConvertToLowercaseUrl(base.Content(contentPath));
}
public override string RouteUrl(UrlRouteContext routeContext)
{
return ConvertToLowercaseUrl(base.RouteUrl(routeContext));
}
public override string Action(UrlActionContext actionContext)
{
return ConvertToLowercaseUrl(base.Action(actionContext));
}
private string ConvertToLowercaseUrl(string url)
{
if (!string.IsNullOrEmpty(url)
&& _options.GenerateLowercaseUrls)
{
return url.ToLowerInvariant();
}
return url;
}
}
}

View File

@ -0,0 +1,24 @@
// 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.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.OptionsModel;
namespace UrlHelperSample.Web
{
public class CustomUrlHelperFactory : IUrlHelperFactory
{
private readonly AppOptions _options;
public CustomUrlHelperFactory(IOptions<AppOptions> options)
{
_options = options.Value;
}
public IUrlHelper GetUrlHelper(ActionContext context)
{
return new CustomUrlHelper(context, _options);
}
}
}

View File

@ -2,34 +2,35 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection;
namespace ValidationWebSite
namespace UrlHelperSample.Web
{
public class Startup
{
// Set up application services
public void ConfigureServices(IServiceCollection services)
{
services.Configure<AppOptions>(optionsSetup =>
{
optionsSetup.ServeCDNContent = true;
optionsSetup.CDNServerBaseUrl = "http://cdn.contoso.com";
optionsSetup.GenerateLowercaseUrls = true;
});
// Add MVC services to the services container
services.AddMvc();
services.AddSingleton<IUrlHelperFactory, CustomUrlHelperFactory>();
}
public void Configure(IApplicationBuilder app)
{
app.UseCultureReplacer();
// Set up file serving for JavaScript files.
app.UseFileServer();
app.UseErrorReporter();
// Add MVC to the request pipeline
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action}/{id?}");
routes.MapRoute("Default", "{controller=Home}/{action=Index}");
});
}
}

View File

@ -1,18 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Project ToolsVersion="14.0.24720" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0.24720</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>87ab84b2-22c1-43c6-bb8a-1d327b446fb0</ProjectGuid>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
<ProjectGuid>73f095d2-d0bd-4d03-bc17-d7a5ef0c0191</ProjectGuid>
<RootNamespace>UrlHelperSample.Web</RootNamespace>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>49635</DevelopmentServerPort>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -0,0 +1,15 @@
{
"commands": {
"weblistener": "Microsoft.AspNet.Server.WebListener",
"web": "Microsoft.AspNet.Server.Kestrel"
},
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
"Microsoft.AspNet.Server.WebListener": "1.0.0-*"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
}
}

View File

@ -1,4 +1,4 @@
UrlHelperWebSite
UrlHelperSample.Web
===
This web site illustrates how to register a `CustomURLHelper` which can based on configuration, generate content

View File

@ -3,8 +3,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.OptionsModel;
using Microsoft.Extensions.Primitives;
using Moq;
using Xunit;
@ -181,6 +186,126 @@ namespace Microsoft.AspNet.Mvc
Assert.NotNull(filter);
}
[Fact]
public void ResponseCache_SetsAllHeaders()
{
// Arrange
var responseCache = new ResponseCacheAttribute()
{
Duration = 100,
Location = ResponseCacheLocation.Any,
VaryByHeader = "Accept"
};
var filter = (ResponseCacheFilter)responseCache.CreateInstance(GetServiceProvider(cacheProfiles: null));
var context = GetActionExecutingContext(filter);
// Act
filter.OnActionExecuting(context);
// Assert
var response = context.HttpContext.Response;
StringValues values;
Assert.True(response.Headers.TryGetValue("Cache-Control", out values));
var data = Assert.Single(values);
AssertHeaderEquals("public, max-age=100", data);
Assert.True(response.Headers.TryGetValue("Vary", out values));
data = Assert.Single(values);
Assert.Equal("Accept", data);
}
public static TheoryData<ResponseCacheAttribute, string> CacheControlData
{
get
{
return new TheoryData<ResponseCacheAttribute, string>
{
{
new ResponseCacheAttribute() { Duration = 100, Location = ResponseCacheLocation.Any },
"public, max-age=100"
},
{
new ResponseCacheAttribute() { Duration = 100, Location = ResponseCacheLocation.Client },
"max-age=100, private"
},
{
new ResponseCacheAttribute() { NoStore = true, Duration = 0 },
"no-store"
},
{
new ResponseCacheAttribute()
{
NoStore = true,
Duration = 0,
Location = ResponseCacheLocation.None
},
"no-store, no-cache"
}
};
}
}
[Theory]
[MemberData(nameof(CacheControlData))]
public void ResponseCache_SetsDifferentCacheControlHeaders(
ResponseCacheAttribute responseCacheAttribute,
string expected)
{
// Arrange
var filter = (ResponseCacheFilter)responseCacheAttribute.CreateInstance(
GetServiceProvider(cacheProfiles: null));
var context = GetActionExecutingContext(filter);
// Act
filter.OnActionExecuting(context);
// Assert
StringValues values;
Assert.True(context.HttpContext.Response.Headers.TryGetValue("Cache-Control", out values));
var data = Assert.Single(values);
AssertHeaderEquals(expected, data);
}
[Fact]
public void SetsCacheControlPublicByDefault()
{
// Arrange
var responseCacheAttribute = new ResponseCacheAttribute() { Duration = 40 };
var filter = (ResponseCacheFilter)responseCacheAttribute.CreateInstance(
GetServiceProvider(cacheProfiles: null));
var context = GetActionExecutingContext(filter);
// Act
filter.OnActionExecuting(context);
// Assert
StringValues values;
Assert.True(context.HttpContext.Response.Headers.TryGetValue("Cache-Control", out values));
var data = Assert.Single(values);
AssertHeaderEquals("public, max-age=40", data);
}
[Fact]
public void ThrowsWhenDurationIsNotSet()
{
// Arrange
var responseCacheAttribute = new ResponseCacheAttribute()
{
VaryByHeader = "Accept"
};
var filter = (ResponseCacheFilter)responseCacheAttribute.CreateInstance(
GetServiceProvider(cacheProfiles: null));
var context = GetActionExecutingContext(filter);
// Act & Assert
var exception = Assert.Throws<InvalidOperationException>(() =>
{
filter.OnActionExecuting(context);
});
Assert.Equal(
"If the 'NoStore' property is not set to true, 'Duration' property must be specified.",
exception.Message);
}
private IServiceProvider GetServiceProvider(Dictionary<string, CacheProfile> cacheProfiles)
{
var serviceProvider = new Mock<IServiceProvider>();
@ -199,5 +324,22 @@ namespace Microsoft.AspNet.Mvc
return serviceProvider.Object;
}
private ActionExecutingContext GetActionExecutingContext(params IFilterMetadata[] filters)
{
return new ActionExecutingContext(
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()),
filters?.ToList() ?? new List<IFilterMetadata>(),
new Dictionary<string, object>(),
new object());
}
private void AssertHeaderEquals(string expected, string actual)
{
// OrderBy is used because the order of the results may vary depending on the platform / client.
Assert.Equal(
expected.Split(',').Select(p => p.Trim()).OrderBy(item => item, StringComparer.Ordinal),
actual.Split(',').Select(p => p.Trim()).OrderBy(item => item, StringComparer.Ordinal));
}
}
}

View File

@ -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 System.Net;
@ -15,11 +15,11 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
/// 1. Based on configuration, generate Content urls pointing to local or a CDN server
/// 2. Based on configuration, generate lower case urls
/// </summary>
public class CustomUrlHelperTests : IClassFixture<MvcTestFixture<UrlHelperWebSite.Startup>>
public class CustomUrlHelperTests : IClassFixture<MvcTestFixture<UrlHelperSample.Web.Startup>>
{
private const string _cdnServerBaseUrl = "http://cdn.contoso.com";
public CustomUrlHelperTests(MvcTestFixture<UrlHelperWebSite.Startup> fixture)
public CustomUrlHelperTests(MvcTestFixture<UrlHelperSample.Web.Startup> fixture)
{
Client = fixture.Client;
}

View File

@ -1,176 +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 System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests
{
public class ModelMetadataAttributeTest : IClassFixture<MvcTestFixture<ValidationWebSite.Startup>>
{
public ModelMetadataAttributeTest(MvcTestFixture<ValidationWebSite.Startup> fixture)
{
Client = fixture.Client;
}
public HttpClient Client { get; }
[Fact]
public async Task ModelMetaDataTypeAttribute_ValidBaseClass_EmptyResponseBody()
{
// Arrange
var input = "{ \"Name\": \"MVC\", \"Contact\":\"4258959019\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"USA\",\"Price\": 21, \"ProductDetails\": {\"Detail1\": \"d1\"," +
" \"Detail2\": \"d2\", \"Detail3\": \"d3\"}}";
var content = new StringContent(input, Encoding.UTF8, "application/json");
var url = "http://localhost/ModelMetadataTypeValidation/ValidateProductViewModelIncludingMetadata";
// Act
var response = await Client.PostAsync(url, content);
// Assert
var body = await response.Content.ReadAsStringAsync();
Assert.Equal("{}", body);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_InvalidPropertiesAndSubPropertiesOnBaseClass_ReturnsErrors()
{
// Arrange
var input = "{ \"Price\": 2, \"ProductDetails\": {\"Detail1\": \"d1\"}}";
var content = new StringContent(input, Encoding.UTF8, "application/json");
var url = "http://localhost/ModelMetadataTypeValidation/ValidateProductViewModelIncludingMetadata";
// Act
var response = await Client.PostAsync(url, content);
// Assert
var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(6, json.Count);
Assert.Equal("CompanyName cannot be null or empty.", json["CompanyName"]);
Assert.Equal("The field Price must be between 20 and 100.", json["Price"]);
// Mono issue - https://github.com/aspnet/External/issues/19
Assert.Equal(PlatformNormalizer.NormalizeContent("The Category field is required."), json["Category"]);
Assert.Equal(PlatformNormalizer.NormalizeContent("The Contact Us field is required."), json["Contact"]);
Assert.Equal(
PlatformNormalizer.NormalizeContent("The Detail2 field is required."),
json["ProductDetails.Detail2"]);
Assert.Equal(
PlatformNormalizer.NormalizeContent("The Detail3 field is required."),
json["ProductDetails.Detail3"]);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_InvalidComplexTypePropertyOnBaseClass_ReturnsErrors()
{
// Arrange
var input = "{ \"Contact\":\"4255678765\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"USA\",\"Price\": 21 }";
var content = new StringContent(input, Encoding.UTF8, "application/json");
var url = "http://localhost/ModelMetadataTypeValidation/ValidateProductViewModelIncludingMetadata";
// Act
var response = await Client.PostAsync(url, content);
// Assert
var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(1, json.Count);
// Mono issue - https://github.com/aspnet/External/issues/19
Assert.Equal(
PlatformNormalizer.NormalizeContent("The ProductDetails field is required."),
json["ProductDetails"]);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_InvalidClassAttributeOnBaseClass_ReturnsErrors()
{
// Arrange
var input = "{ \"Contact\":\"4258959019\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"UK\",\"Price\": 21, \"ProductDetails\": {\"Detail1\": \"d1\"," +
" \"Detail2\": \"d2\", \"Detail3\": \"d3\"}}";
var content = new StringContent(input, Encoding.UTF8, "application/json");
var url = "http://localhost/ModelMetadataTypeValidation/ValidateProductViewModelIncludingMetadata";
// Act
var response = await Client.PostAsync(url, content);
// Assert
var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(1, json.Count);
Assert.Equal("Product must be made in the USA if it is not named.", json[""]);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_ValidDerivedClass_EmptyResponseBody()
{
// Arrange
var input = "{ \"Name\": \"MVC\", \"Contact\":\"4258959019\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"USA\", \"Version\":\"2\"," +
"\"DatePurchased\": \"/Date(1297246301973)/\", \"Price\" : \"110\" }";
var content = new StringContent(input, Encoding.UTF8, "application/json");
var url = "http://localhost/ModelMetadataTypeValidation/ValidateSoftwareViewModelIncludingMetadata";
// Act
var response = await Client.PostAsync(url, content);
// Assert
var body = await response.Content.ReadAsStringAsync();
Assert.Equal("{}", body);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_InvalidPropertiesOnDerivedClass_ReturnsErrors()
{
// Arrange
var input = "{ \"Name\": \"MVC\", \"Contact\":\"425-895-9019\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"USA\",\"Price\": 2}";
var content = new StringContent(input, Encoding.UTF8, "application/json");
var url = "http://localhost/ModelMetadataTypeValidation/ValidateSoftwareViewModelIncludingMetadata";
// Act
var response = await Client.PostAsync(url, content);
// Assert
var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(2, json.Count);
Assert.Equal("The field Price must be between 100 and 200.", json["Price"]);
Assert.Equal("The field Contact must be a string with a maximum length of 10.", json["Contact"]);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_InvalidClassAttributeOnBaseClassProduct_ReturnsErrors()
{
// Arrange
var input = "{ \"Contact\":\"4258959019\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"UK\",\"Version\":\"2\"," +
"\"DatePurchased\": \"/Date(1297246301973)/\", \"Price\" : \"110\" }";
var content = new StringContent(input, Encoding.UTF8, "application/json");
var url = "http://localhost/ModelMetadataTypeValidation/ValidateSoftwareViewModelIncludingMetadata";
// Act
var response = await Client.PostAsync(url, content);
// Assert
var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(1, json.Count);
Assert.Equal("Product must be made in the USA if it is not named.", json[""]);
}
}
}

View File

@ -10,12 +10,12 @@ using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests
{
public class RemoteAttributeValidationTest : IClassFixture<MvcTestFixture<ValidationWebSite.Startup>>
public class RemoteAttributeValidationTest : IClassFixture<MvcTestFixture<BasicWebSite.Startup>>
{
private static readonly Assembly _resourcesAssembly =
typeof(RemoteAttributeValidationTest).GetTypeInfo().Assembly;
public RemoteAttributeValidationTest(MvcTestFixture<ValidationWebSite.Startup> fixture)
public RemoteAttributeValidationTest(MvcTestFixture<BasicWebSite.Startup> fixture)
{
Client = fixture.Client;
}
@ -23,12 +23,12 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
public HttpClient Client { get; }
[Theory]
[InlineData("Aria", "/Aria")]
[InlineData("Area1", "/Area1")]
[InlineData("Root", "")]
public async Task RemoteAttribute_LeadsToExpectedValidationAttributes(string areaName, string pathSegment)
{
// Arrange
var outputFile = "compiler/resources/ValidationWebSite." + areaName + ".RemoteAttribute_Home.Create.html";
var outputFile = "compiler/resources/BasicWebSite." + areaName + ".RemoteAttribute_Home.Create.html";
var expectedContent =
await ResourceFile.ReadResourceAsync(_resourcesAssembly, outputFile, sourceFile: false);
var url = "http://localhost" + pathSegment + "/RemoteAttribute_Home/Create";
@ -55,9 +55,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
[Theory]
[InlineData("", "\"/RemoteAttribute_Verify/IsIdAvailable rejects Joe1.\"")]
[InlineData("/Aria", "false")]
[InlineData("/AnotherAria",
"\"/AnotherAria/RemoteAttribute_Verify/IsIdAvailable rejects 'Joe4' with 'Joe1', 'Joe2', and 'Joe3'.\"")]
[InlineData("/Area1", "false")]
[InlineData("/Area2",
"\"/Area2/RemoteAttribute_Verify/IsIdAvailable rejects 'Joe4' with 'Joe1', 'Joe2', and 'Joe3'.\"")]
public async Task RemoteAttribute_VerificationAction_GetReturnsExpectedJson(
string pathSegment,
string expectedContent)
@ -79,7 +79,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
[Theory]
[InlineData("", "\"/RemoteAttribute_Verify/IsIdAvailable rejects Jane1.\"")]
[InlineData("/Aria", "false")]
[InlineData("/Area1", "false")]
public async Task RemoteAttribute_VerificationAction_PostReturnsExpectedJson(
string pathSegment,
string expectedContent)

View File

@ -1,295 +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 System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests
{
public class ResponseCacheTest : IClassFixture<MvcTestFixture<ResponseCacheWebSite.Startup>>
{
public ResponseCacheTest(MvcTestFixture<ResponseCacheWebSite.Startup> fixture)
{
Client = fixture.Client;
}
public HttpClient Client { get; }
[Fact]
public async Task ResponseCache_SetsAllHeaders()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheHeaders/Index");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=100", data);
data = Assert.Single(response.Headers.GetValues("Vary"));
Assert.Equal("Accept", data);
}
public static IEnumerable<object[]> CacheControlData
{
get
{
yield return new object[] { "http://localhost/CacheHeaders/PublicCache", "public, max-age=100" };
yield return new object[] { "http://localhost/CacheHeaders/ClientCache", "max-age=100, private" };
yield return new object[] { "http://localhost/CacheHeaders/NoStore", "no-store" };
yield return new object[] { "http://localhost/CacheHeaders/NoCacheAtAll", "no-store, no-cache" };
}
}
[Theory]
[MemberData(nameof(CacheControlData))]
public async Task ResponseCache_SetsDifferentCacheControlHeaders(string url, string expected)
{
// Arrange & Act
var response = await Client.GetAsync(url);
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals(expected, data);
}
[Fact]
public async Task SetsHeadersForAllActionsOfClass()
{
// Arrange & Act
var response1 = await Client.GetAsync("http://localhost/ClassLevelCache/GetHelloWorld");
var response2 = await Client.GetAsync("http://localhost/ClassLevelCache/GetFooBar");
// Assert
var data = Assert.Single(response1.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=100", data);
data = Assert.Single(response1.Headers.GetValues("Vary"));
Assert.Equal("Accept", data);
data = Assert.Single(response2.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=100", data);
data = Assert.Single(response2.Headers.GetValues("Vary"));
Assert.Equal("Accept", data);
}
[Fact]
public async Task HeadersSetInActionOverridesTheOnesInClass()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/ClassLevelCache/ConflictExistingHeader");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=20", data);
}
[Fact]
public async Task HeadersToNotCacheAParticularAction()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/ClassLevelCache/DoNotCacheThisAction");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("no-store, no-cache", data);
}
[Fact]
public async Task ClassLevelHeadersAreUnsetByActionLevelHeaders()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/ClassLevelNoStore/CacheThisAction");
// Assert
var data = Assert.Single(response.Headers.GetValues("Vary"));
Assert.Equal("Accept", data);
data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=10", data);
IEnumerable<string> pragmaValues;
response.Headers.TryGetValues("Pragma", out pragmaValues);
Assert.Null(pragmaValues);
}
[Fact]
public async Task SetsCacheControlPublicByDefault()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheHeaders/SetsCacheControlPublicByDefault");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=40", data);
}
[Fact]
public async Task ThrowsWhenDurationIsNotSet()
{
// Arrange & Act
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
() => Client.GetAsync("http://localhost/CacheHeaders/ThrowsWhenDurationIsNotSet"));
Assert.Equal(
"If the 'NoStore' property is not set to true, 'Duration' property must be specified.",
ex.Message);
}
// Cache Profiles
[Fact]
public async Task ResponseCache_SetsAllHeaders_FromCacheProfile()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheProfiles/PublicCache30Sec");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=30", data);
}
[Fact]
public async Task ResponseCache_SetsAllHeaders_ChosesTheRightProfile()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheProfiles/PrivateCache30Sec");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("max-age=30, private", data);
}
[Fact]
public async Task ResponseCache_SetsNoCacheHeaders()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheProfiles/NoCache");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("no-store, no-cache", data);
data = Assert.Single(response.Headers.GetValues("Pragma"));
Assert.Equal("no-cache", data);
}
[Fact]
public async Task ResponseCache_AddsHeaders()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheProfiles/CacheProfileAddParameter");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=30", data);
data = Assert.Single(response.Headers.GetValues("Vary"));
Assert.Equal("Accept", data);
}
[Fact]
public async Task ResponseCache_ModifiesHeaders()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheProfiles/CacheProfileOverride");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=10", data);
}
[Fact]
public async Task ResponseCache_FallbackToFilter_IfNoAttribute()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheProfiles/FallbackToFilter");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
Assert.Equal("no-store", data);
data = Assert.Single(response.Headers.GetValues("Vary"));
Assert.Equal("TestDefault", data);
}
[Fact]
public async Task ResponseCacheAttribute_OnAction_OverridesTheValuesOnClass()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/ClassLevelNoStore/CacheThisActionWithProfileSettings");
// Assert
var data = Assert.Single(response.Headers.GetValues("Vary"));
Assert.Equal("Accept", data);
data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=30", data);
IEnumerable<string> pragmaValues;
response.Headers.TryGetValues("Pragma", out pragmaValues);
Assert.Null(pragmaValues);
}
// Cache profile overrides
[Fact]
public async Task ResponseCacheAttribute_OverridesProfileDuration_FromAttributeProperty()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheProfileOverrides/PublicCache30SecTo15Sec");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=15", data);
}
[Fact]
public async Task ResponseCacheAttribute_OverridesProfileLocation_FromAttributeProperty()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheProfileOverrides/PublicCache30SecToPrivateCache");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("max-age=30, private", data);
}
[Fact]
public async Task ResponseCacheAttribute_OverridesProfileNoStore_FromAttributeProperty()
{
// Arrange & Act
var response = await Client.GetAsync("http://localhost/CacheProfileOverrides/PublicCache30SecToNoStore");
// Assert
var data = Assert.Single(response.Headers.GetValues("Cache-control"));
Assert.Equal("no-store", data);
}
[Fact]
public async Task ResponseCacheAttribute_OverridesProfileVaryBy_FromAttributeProperty()
{
// Arrange & Act
var response = await Client.GetAsync(
"http://localhost/CacheProfileOverrides/PublicCache30SecWithVaryByAcceptToVaryByTest");
// Assert
var cacheControl = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=30", cacheControl);
var vary = Assert.Single(response.Headers.GetValues("Vary"));
Assert.Equal("Test", vary);
}
[Fact]
public async Task ResponseCacheAttribute_OverridesProfileVaryBy_FromAttributeProperty_AndRemovesVaryHeader()
{
// Arrange & Act
var response = await Client.GetAsync(
"http://localhost/CacheProfileOverrides/PublicCache30SecWithVaryByAcceptToVaryByNone");
// Assert
var cacheControl = Assert.Single(response.Headers.GetValues("Cache-control"));
AssertHeaderEquals("public, max-age=30", cacheControl);
Assert.Throws<InvalidOperationException>(() => response.Headers.GetValues("Vary"));
}
private void AssertHeaderEquals(string expected, string actual)
{
// OrderBy is used because the order of the results may very depending on the platform / client.
Assert.Equal(
expected.Split(',').Select(p => p.Trim()).OrderBy(item => item, StringComparer.Ordinal),
actual.Split(',').Select(p => p.Trim()).OrderBy(item => item, StringComparer.Ordinal));
}
}
}

View File

@ -1,137 +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 System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNet.Testing;
using Newtonsoft.Json;
using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests
{
public class TryValidateModelTest : IClassFixture<MvcTestFixture<ValidationWebSite.Startup>>
{
public TryValidateModelTest(MvcTestFixture<ValidationWebSite.Startup> fixture)
{
Client = fixture.Client;
}
public HttpClient Client { get; }
[Fact]
public async Task TryValidateModel_ClearParameterValidationError_ReturnsErrorsForInvalidProperties()
{
// Arrange
var input = "{ \"Price\": 2, \"Contact\": \"acvrdzersaererererfdsfdsfdsfsdf\", " +
"\"ProductDetails\": {\"Detail1\": \"d1\", \"Detail2\": \"d2\", \"Detail3\": \"d3\"}}";
var content = new StringContent(input, Encoding.UTF8, "application/json");
var url =
"http://localhost/ModelMetadataTypeValidation/" +
"TryValidateModelAfterClearingValidationErrorInParameter?theImpossibleString=test";
// Act
var response = await Client.PostAsync(url, content);
// Assert
var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(4, json.Count);
Assert.Equal("CompanyName cannot be null or empty.", json["CompanyName"]);
Assert.Equal("The field Price must be between 20 and 100.", json["Price"]);
// Mono issue - https://github.com/aspnet/External/issues/19
Assert.Equal(
PlatformNormalizer.NormalizeContent("The Category field is required."),
json["Category"]);
AssertErrorEquals(
"The field Contact Us must be a string with a maximum length of 20." +
"The field Contact Us must match the regular expression " +
(TestPlatformHelper.IsMono ? "^[0-9]*$." : "'^[0-9]*$'."),
json["Contact"]);
}
[Fact]
public async Task TryValidateModel_InvalidTypeOnDerivedModel_ReturnsErrors()
{
// Arrange
var url = "http://localhost/ModelMetadataTypeValidation/TryValidateModelSoftwareViewModelWithPrefix";
// Act
var response = await Client.GetAsync(url);
// Assert
var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal(1, json.Count);
Assert.Equal("Product must be made in the USA if it is not named.", json["software"]);
}
[Fact]
public async Task TryValidateModel_ValidDerivedModel_ReturnsEmptyResponseBody()
{
// Arrange
var url = "http://localhost/ModelMetadataTypeValidation/TryValidateModelValidModelNoPrefix";
// Act
var response = await Client.GetAsync(url);
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var body = await response.Content.ReadAsStringAsync();
Assert.Equal("{}", body);
}
[Fact]
public async Task TryValidateModel_CollectionsModel_ReturnsErrorsForInvalidProperties()
{
// Arrange
var input = "[ { \"Price\": 2, \"Contact\": \"acvrdzersaererererfdsfdsfdsfsdf\", " +
"\"ProductDetails\": {\"Detail1\": \"d1\", \"Detail2\": \"d2\", \"Detail3\": \"d3\"} }," +
"{\"Price\": 2, \"Contact\": \"acvrdzersaererererfdsfdsfdsfsdf\", " +
"\"ProductDetails\": {\"Detail1\": \"d1\", \"Detail2\": \"d2\", \"Detail3\": \"d3\"} }]";
var content = new StringContent(input, Encoding.UTF8, "application/json");
var url =
"http://localhost/ModelMetadataTypeValidation/TryValidateModelWithCollectionsModel";
// Act
var response = await Client.PostAsync(url, content);
// Assert
var body = await response.Content.ReadAsStringAsync();
var json = JsonConvert.DeserializeObject<Dictionary<string, string>>(body);
Assert.Equal("CompanyName cannot be null or empty.", json["[0].CompanyName"]);
Assert.Equal("The field Price must be between 20 and 100.", json["[0].Price"]);
// Mono issue - https://github.com/aspnet/External/issues/19
Assert.Equal(
PlatformNormalizer.NormalizeContent("The Category field is required."),
json["[0].Category"]);
AssertErrorEquals(
"The field Contact Us must be a string with a maximum length of 20." +
"The field Contact Us must match the regular expression " +
(TestPlatformHelper.IsMono ? "^[0-9]*$." : "'^[0-9]*$'."),
json["[0].Contact"]);
Assert.Equal("CompanyName cannot be null or empty.", json["[1].CompanyName"]);
Assert.Equal("The field Price must be between 20 and 100.", json["[1].Price"]);
Assert.Equal(
PlatformNormalizer.NormalizeContent("The Category field is required."),
json["[1].Category"]);
AssertErrorEquals(
"The field Contact Us must be a string with a maximum length of 20." +
"The field Contact Us must match the regular expression " +
(TestPlatformHelper.IsMono ? "^[0-9]*$." : "'^[0-9]*$'."),
json["[1].Contact"]);
}
private void AssertErrorEquals(string expected, string actual)
{
// OrderBy is used because the order of the results may very depending on the platform / client.
Assert.Equal(
expected.Split('.').OrderBy(item => item, StringComparer.Ordinal),
actual.Split('.').OrderBy(item => item, StringComparer.Ordinal));
}
}
}

View File

@ -1,21 +1,21 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Create in Aria area. - My ASP.NET Application</title>
<title>Create in Area1 area. - My ASP.NET Application</title>
</head>
<body>
<div>
<div>
<div>
<a href="/">Validation web site</a>
<a href="/RemoteAttribute_Home/Details">Basic web site</a>
</div>
<div>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/Aria">Aria Home</a></li>
<li><a href="/RemoteAttribute_Home/Details">Home</a></li>
<li><a href="/Area1/RemoteAttribute_Home/Details">Area1 Home</a></li>
</ul>
</div>
</div>
@ -23,8 +23,8 @@
<div>
<h2>Create in Aria area.</h2>
<form action="/Aria/RemoteAttribute_Home/Create" method="post"> <div class="form-horizontal">
<h2>Create in Area1 area.</h2>
<form action="/Area1/RemoteAttribute_Home/Create" method="post"> <div class="form-horizontal">
<h4>Person</h4>
<hr />
@ -40,7 +40,7 @@
<div class="form-group">
<label class="control-label col-md-2" for="UserId1">UserId1</label>
<div class="col-md-10">
<input class="form-control text-box single-line" data-val="true" data-val-remote="&#x27;UserId1&#x27; is invalid." data-val-remote-additionalfields="*.UserId1" data-val-remote-url="/Aria/RemoteAttribute_Verify/IsIdAvailable" id="UserId1" name="UserId1" type="text" value="" />
<input class="form-control text-box single-line" data-val="true" data-val-remote="&#x27;UserId1&#x27; is invalid." data-val-remote-additionalfields="*.UserId1" data-val-remote-url="/Area1/RemoteAttribute_Verify/IsIdAvailable" id="UserId1" name="UserId1" type="text" value="" />
<span class="field-validation-valid text-danger" data-valmsg-for="UserId1" data-valmsg-replace="true"></span>
</div>
</div>
@ -56,7 +56,7 @@
<div class="form-group">
<label class="control-label col-md-2" for="UserId3">UserId3</label>
<div class="col-md-10">
<input class="form-control text-box single-line" data-val="true" data-val-remote="/Aria/RemoteAttribute_Verify/IsIdAvailable rejects you." data-val-remote-additionalfields="*.UserId3" data-val-remote-url="/Aria/RemoteAttribute_Verify/IsIdAvailable" id="UserId3" name="UserId3" type="text" value="" />
<input class="form-control text-box single-line" data-val="true" data-val-remote="/Area1/RemoteAttribute_Verify/IsIdAvailable rejects you." data-val-remote-additionalfields="*.UserId3" data-val-remote-url="/Area1/RemoteAttribute_Verify/IsIdAvailable" id="UserId3" name="UserId3" type="text" value="" />
<span class="field-validation-valid text-danger" data-valmsg-for="UserId3" data-valmsg-replace="true"></span>
</div>
</div>
@ -64,7 +64,7 @@
<div class="form-group">
<label class="control-label col-md-2" for="UserId4">UserId4</label>
<div class="col-md-10">
<input class="form-control text-box single-line" data-val="true" data-val-remote="&#x27;UserId4&#x27; is invalid." data-val-remote-additionalfields="*.UserId4,*.UserId1,*.UserId2,*.UserId3" data-val-remote-url="/AnotherAria/RemoteAttribute_Verify/IsIdAvailable" id="UserId4" name="UserId4" type="text" value="" />
<input class="form-control text-box single-line" data-val="true" data-val-remote="&#x27;UserId4&#x27; is invalid." data-val-remote-additionalfields="*.UserId4,*.UserId1,*.UserId2,*.UserId3" data-val-remote-url="/Area2/RemoteAttribute_Verify/IsIdAvailable" id="UserId4" name="UserId4" type="text" value="" />
<span class="field-validation-valid text-danger" data-valmsg-for="UserId4" data-valmsg-replace="true"></span>
</div>
</div>
@ -77,7 +77,7 @@
</div>
</form>
<div>
<a href="/Aria">Go back to home</a>
<a href="/Area1/RemoteAttribute_Home/Details">Go back to home</a>
</div>

View File

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
@ -9,13 +9,13 @@
<div>
<div>
<div>
<a href="/">Validation web site</a>
<a href="/RemoteAttribute_Home/Details">Basic web site</a>
</div>
<div>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/Aria">Aria Home</a></li>
<li><a href="/RemoteAttribute_Home/Details">Home</a></li>
<li><a href="/Area1/RemoteAttribute_Home/Details">Area1 Home</a></li>
</ul>
</div>
</div>
@ -56,7 +56,7 @@
<div class="form-group">
<label class="control-label col-md-2" for="UserId3">UserId3</label>
<div class="col-md-10">
<input class="form-control text-box single-line" data-val="true" data-val-remote="/Aria/RemoteAttribute_Verify/IsIdAvailable rejects you." data-val-remote-additionalfields="*.UserId3" data-val-remote-url="/Aria/RemoteAttribute_Verify/IsIdAvailable" id="UserId3" name="UserId3" type="text" value="" />
<input class="form-control text-box single-line" data-val="true" data-val-remote="/Area1/RemoteAttribute_Verify/IsIdAvailable rejects you." data-val-remote-additionalfields="*.UserId3" data-val-remote-url="/Area1/RemoteAttribute_Verify/IsIdAvailable" id="UserId3" name="UserId3" type="text" value="" />
<span class="field-validation-valid text-danger" data-valmsg-for="UserId3" data-valmsg-replace="true"></span>
</div>
</div>
@ -64,7 +64,7 @@
<div class="form-group">
<label class="control-label col-md-2" for="UserId4">UserId4</label>
<div class="col-md-10">
<input class="form-control text-box single-line" data-val="true" data-val-remote="&#x27;UserId4&#x27; is invalid." data-val-remote-additionalfields="*.UserId4,*.UserId1,*.UserId2,*.UserId3" data-val-remote-url="/AnotherAria/RemoteAttribute_Verify/IsIdAvailable" id="UserId4" name="UserId4" type="text" value="" />
<input class="form-control text-box single-line" data-val="true" data-val-remote="&#x27;UserId4&#x27; is invalid." data-val-remote-additionalfields="*.UserId4,*.UserId1,*.UserId2,*.UserId3" data-val-remote-url="/Area2/RemoteAttribute_Verify/IsIdAvailable" id="UserId4" name="UserId4" type="text" value="" />
<span class="field-validation-valid text-danger" data-valmsg-for="UserId4" data-valmsg-replace="true"></span>
</div>
</div>
@ -77,7 +77,7 @@
</div>
</form>
<div>
<a href="/">Go back to home</a>
<a href="/RemoteAttribute_Home/Details">Go back to home</a>
</div>

View File

@ -49,12 +49,10 @@
"RazorEmbeddedViewsWebSite": "1.0.0",
"RazorPageExecutionInstrumentationWebSite": "1.0.0",
"RazorWebSite": "1.0.0",
"ResponseCacheWebSite": "1.0.0",
"RoutingWebSite": "1.0.0",
"TagHelperSample.Web": "1.0.0",
"TagHelpersWebSite": "1.0.0",
"UrlHelperWebSite": "1.0.0",
"ValidationWebSite": "1.0.0",
"UrlHelperSample.Web": "1.0.0",
"VersioningWebSite": "1.0.0",
"WebApiCompatShimWebSite": "1.0.0",
"XmlFormattersWebSite": "1.0.0",

View File

@ -1,6 +1,7 @@
// 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.ComponentModel.DataAnnotations;
using System.IO;
using System.Text;
@ -25,6 +26,287 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
public string Street { get; set; }
}
[Fact]
public async Task ModelMetaDataTypeAttribute_ValidBaseClass_NoModelStateErrors()
{
// Arrange
var input = "{ \"Name\": \"MVC\", \"Contact\":\"4258959019\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"USA\",\"Price\": 21, " +
"\"ProductDetails\": {\"Detail1\": \"d1\", \"Detail2\": \"d2\", \"Detail3\": \"d3\"}}";
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "Parameter1",
ParameterType = typeof(ProductViewModel),
BindingInfo = new BindingInfo()
{
BindingSource = BindingSource.Body
}
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
request =>
{
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(input));
request.ContentType = "application/json;charset=utf-8";
});
var modelState = operationContext.ActionContext.ModelState;
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, operationContext);
// Assert
Assert.True(modelBindingResult.IsModelSet);
var boundPerson = Assert.IsType<ProductViewModel>(modelBindingResult.Model);
Assert.True(modelState.IsValid);
Assert.NotNull(boundPerson);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_InvalidPropertiesAndSubPropertiesOnBaseClass_HasModelStateErrors()
{
// Arrange
var input = "{ \"Price\": 2, \"ProductDetails\": {\"Detail1\": \"d1\"}}";
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "Parameter1",
BindingInfo = new BindingInfo()
{
BindingSource = BindingSource.Body
},
ParameterType = typeof(ProductViewModel)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
request =>
{
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(input));
request.ContentType = "application/json";
});
var modelState = operationContext.ActionContext.ModelState;
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, operationContext);
// Assert
Assert.True(modelBindingResult.IsModelSet);
var boundPerson = Assert.IsType<ProductViewModel>(modelBindingResult.Model);
Assert.NotNull(boundPerson);
Assert.False(modelState.IsValid);
var modelStateErrors = CreateValidationDictionary(modelState);
Assert.Equal("CompanyName cannot be null or empty.", modelStateErrors["CompanyName"]);
Assert.Equal("The field Price must be between 20 and 100.", modelStateErrors["Price"]);
// Mono issue - https://github.com/aspnet/External/issues/19
Assert.Equal(PlatformNormalizer.NormalizeContent("The Category field is required."), modelStateErrors["Category"]);
Assert.Equal(PlatformNormalizer.NormalizeContent("The Contact Us field is required."), modelStateErrors["Contact"]);
Assert.Equal(
PlatformNormalizer.NormalizeContent("The Detail2 field is required."),
modelStateErrors["ProductDetails.Detail2"]);
Assert.Equal(
PlatformNormalizer.NormalizeContent("The Detail3 field is required."),
modelStateErrors["ProductDetails.Detail3"]);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_InvalidComplexTypePropertyOnBaseClass_HasModelStateErrors()
{
// Arrange
var input = "{ \"Contact\":\"4255678765\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"USA\",\"Price\": 21 }";
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "Parameter1",
BindingInfo = new BindingInfo()
{
BindingSource = BindingSource.Body
},
ParameterType = typeof(ProductViewModel)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
request =>
{
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(input));
request.ContentType = "application/json";
});
var modelState = operationContext.ActionContext.ModelState;
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, operationContext);
// Assert
Assert.True(modelBindingResult.IsModelSet);
var boundPerson = Assert.IsType<ProductViewModel>(modelBindingResult.Model);
Assert.NotNull(boundPerson);
Assert.False(modelState.IsValid);
var modelStateErrors = CreateValidationDictionary(modelState);
Assert.Equal(
PlatformNormalizer.NormalizeContent("The ProductDetails field is required."),
modelStateErrors["ProductDetails"]);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_InvalidClassAttributeOnBaseClass_HasModelStateErrors()
{
// Arrange
var input = "{ \"Contact\":\"4258959019\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"UK\",\"Price\": 21, \"ProductDetails\": {\"Detail1\": \"d1\"," +
" \"Detail2\": \"d2\", \"Detail3\": \"d3\"}}";
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "Parameter1",
BindingInfo = new BindingInfo()
{
BindingSource = BindingSource.Body
},
ParameterType = typeof(ProductViewModel)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
request =>
{
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(input));
request.ContentType = "application/json";
});
var modelState = operationContext.ActionContext.ModelState;
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, operationContext);
// Assert
Assert.True(modelBindingResult.IsModelSet);
var boundPerson = Assert.IsType<ProductViewModel>(modelBindingResult.Model);
Assert.NotNull(boundPerson);
Assert.False(modelState.IsValid);
var modelStateErrors = CreateValidationDictionary(modelState);
Assert.Single(modelStateErrors);
Assert.Equal("Product must be made in the USA if it is not named.", modelStateErrors[""]);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_ValidDerivedClass_NoModelStateErrors()
{
// Arrange
var input = "{ \"Name\": \"MVC\", \"Contact\":\"4258959019\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"USA\", \"Version\":\"2\"," +
"\"DatePurchased\": \"/Date(1297246301973)/\", \"Price\" : \"110\" }";
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "Parameter1",
BindingInfo = new BindingInfo()
{
BindingSource = BindingSource.Body
},
ParameterType = typeof(SoftwareViewModel)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
request =>
{
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(input));
request.ContentType = "application/json";
});
var modelState = operationContext.ActionContext.ModelState;
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, operationContext);
// Assert
Assert.True(modelBindingResult.IsModelSet);
var boundPerson = Assert.IsType<SoftwareViewModel>(modelBindingResult.Model);
Assert.NotNull(boundPerson);
Assert.True(modelState.IsValid);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_InvalidPropertiesOnDerivedClass_HasModelStateErrors()
{
// Arrange
var input = "{ \"Name\": \"MVC\", \"Contact\":\"425-895-9019\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"USA\",\"Price\": 2}";
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "Parameter1",
BindingInfo = new BindingInfo()
{
BindingSource = BindingSource.Body
},
ParameterType = typeof(SoftwareViewModel)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
request =>
{
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(input));
request.ContentType = "application/json";
});
var modelState = operationContext.ActionContext.ModelState;
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, operationContext);
// Assert
Assert.True(modelBindingResult.IsModelSet);
var boundPerson = Assert.IsType<SoftwareViewModel>(modelBindingResult.Model);
Assert.NotNull(boundPerson);
Assert.False(modelState.IsValid);
var modelStateErrors = CreateValidationDictionary(modelState);
Assert.Equal(2, modelStateErrors.Count);
Assert.Equal("The field Price must be between 100 and 200.", modelStateErrors["Price"]);
Assert.Equal("The field Contact must be a string with a maximum length of 10.", modelStateErrors["Contact"]);
}
[Fact]
public async Task ModelMetaDataTypeAttribute_InvalidClassAttributeOnBaseClassProduct_HasModelStateErrors()
{
// Arrange
var input = "{ \"Contact\":\"4258959019\", \"Category\":\"Technology\"," +
"\"CompanyName\":\"Microsoft\", \"Country\":\"UK\",\"Version\":\"2\"," +
"\"DatePurchased\": \"/Date(1297246301973)/\", \"Price\" : \"110\" }";
var argumentBinder = ModelBindingTestHelper.GetArgumentBinder();
var parameter = new ParameterDescriptor()
{
Name = "Parameter1",
BindingInfo = new BindingInfo()
{
BindingSource = BindingSource.Body
},
ParameterType = typeof(SoftwareViewModel)
};
var operationContext = ModelBindingTestHelper.GetOperationBindingContext(
request =>
{
request.Body = new MemoryStream(Encoding.UTF8.GetBytes(input));
request.ContentType = "application/json";
});
var modelState = operationContext.ActionContext.ModelState;
// Act
var modelBindingResult = await argumentBinder.BindModelAsync(parameter, operationContext);
// Assert
Assert.True(modelBindingResult.IsModelSet);
var boundPerson = Assert.IsType<SoftwareViewModel>(modelBindingResult.Model);
Assert.NotNull(boundPerson);
Assert.False(modelState.IsValid);
var modelStateErrors = CreateValidationDictionary(modelState);
Assert.Single(modelStateErrors);
Assert.Equal("Product must be made in the USA if it is not named.", modelStateErrors[""]);
}
[Fact]
public async Task FromBodyAndRequiredOnProperty_EmptyBody_AddsModelStateError()
{
@ -376,5 +658,27 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var entry = Assert.Single(modelState);
Assert.Equal("CustomParameter.Address", entry.Key);
}
private Dictionary<string, string> CreateValidationDictionary(ModelStateDictionary modelState)
{
var result = new Dictionary<string, string>();
foreach (var item in modelState)
{
var errorMessage = string.Empty;
foreach (var error in item.Value.Errors)
{
if (error != null)
{
errorMessage = errorMessage + error.ErrorMessage;
}
}
if (!string.IsNullOrEmpty(errorMessage))
{
result.Add(item.Key, errorMessage);
}
}
return result;
}
}
}

View File

@ -1,9 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.ComponentModel.DataAnnotations;
namespace ValidationWebSite
namespace Microsoft.AspNet.Mvc.IntegrationTests
{
public class CompanyNameAttribute : ValidationAttribute
{
@ -18,4 +18,4 @@ namespace ValidationWebSite
return null;
}
}
}
}

View File

@ -1,10 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel.DataAnnotations;
namespace ValidationWebSite.Models
namespace Microsoft.AspNet.Mvc.IntegrationTests
{
[ProductValidator]
public class Product
@ -27,4 +26,4 @@ namespace ValidationWebSite.Models
[Required]
public ProductDetails ProductDetails { get; set; }
}
}
}

View File

@ -1,9 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.ComponentModel.DataAnnotations;
namespace ValidationWebSite.Models
namespace Microsoft.AspNet.Mvc.IntegrationTests
{
public class ProductDetails
{
@ -16,4 +16,4 @@ namespace ValidationWebSite.Models
[Required]
public string Detail3 { get; set; }
}
}
}

View File

@ -1,12 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.Mvc;
using ValidationWebSite.Models;
namespace ValidationWebSite.ViewModels
namespace Microsoft.AspNet.Mvc.IntegrationTests
{
[ModelMetadataType(typeof(Product))]
public class ProductViewModel
@ -29,4 +26,4 @@ namespace ValidationWebSite.ViewModels
public ProductDetails ProductDetails { get; set; }
}
}
}

View File

@ -1,10 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel.DataAnnotations;
namespace ValidationWebSite.Models
namespace Microsoft.AspNet.Mvc.IntegrationTests
{
public class Software : Product
{
@ -19,4 +19,4 @@ namespace ValidationWebSite.Models
[StringLength(10)]
public new string Contact { get; set; }
}
}
}

View File

@ -1,15 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNet.Mvc;
using ValidationWebSite.Models;
namespace ValidationWebSite.ViewModels
namespace Microsoft.AspNet.Mvc.IntegrationTests
{
[ModelMetadataType(typeof(Software))]
public class SoftwareViewModel
public class SoftwareViewModel
{
[RegularExpression("^[0-9]*$")]
public string Version { get; set; }
@ -28,4 +26,4 @@ namespace ValidationWebSite.ViewModels
public string CompanyName { get; set; }
}
}
}

View File

@ -1,10 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.ComponentModel.DataAnnotations;
using ValidationWebSite.ViewModels;
namespace ValidationWebSite
namespace Microsoft.AspNet.Mvc.IntegrationTests
{
public class ProductValidatorAttribute : ValidationAttribute
{
@ -39,4 +38,4 @@ namespace ValidationWebSite
+ value.GetType() + " instance");
}
}
}
}

View File

@ -0,0 +1,184 @@
// 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;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Testing;
using Xunit;
namespace Microsoft.AspNet.Mvc.IntegrationTests
{
public class TryValidateModelIntegrationTest
{
[Fact]
public void ModelState_IsInvalid_ForInvalidData_OnDerivedModel()
{
// Arrange
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = operationContext.ActionContext.ModelState;
var model = new SoftwareViewModel
{
Category = "Technology",
CompanyName = "Microsoft",
Contact = "4258393231",
Country = "UK", // Here the validate country is USA only
DatePurchased = new DateTime(2010, 10, 10),
Price = 110,
Version = "2"
};
var oldModel = model;
// Act
var result = TryValidateModel(model, "software", operationContext);
// Assert
Assert.False(result);
Assert.Same(oldModel, model);
Assert.False(modelState.IsValid);
var modelStateErrors = GetModelStateErrors(modelState);
Assert.Single(modelStateErrors);
Assert.Equal("Product must be made in the USA if it is not named.", modelStateErrors["software"]);
}
[Fact]
public void ModelState_IsValid_ForValidData_OnDerivedModel()
{
// Arrange
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = operationContext.ActionContext.ModelState;
var model = new SoftwareViewModel
{
Category = "Technology",
CompanyName = "Microsoft",
Contact = "4258393231",
Country = "USA",
DatePurchased = new DateTime(2010, 10, 10),
Name = "MVC",
Price = 110,
Version = "2"
};
var oldModel = model;
// Act
var result = TryValidateModel(model, prefix: string.Empty, operationContext: operationContext);
// Assert
Assert.True(result);
Assert.Same(oldModel, model);
Assert.True(modelState.IsValid);
var modelStateErrors = GetModelStateErrors(modelState);
Assert.Empty(modelStateErrors);
}
[Fact]
public void TryValidateModel_CollectionsModel_ReturnsErrorsForInvalidProperties()
{
// Arrange
var operationContext = ModelBindingTestHelper.GetOperationBindingContext();
var modelState = operationContext.ActionContext.ModelState;
var model = new List<ProductViewModel>();
model.Add(new ProductViewModel()
{
Price = 2,
Contact = "acvrdzersaererererfdsfdsfdsfsdf",
ProductDetails = new ProductDetails()
{
Detail1 = "d1",
Detail2 = "d2",
Detail3 = "d3"
}
});
model.Add(new ProductViewModel()
{
Price = 2,
Contact = "acvrdzersaererererfdsfdsfdsfsdf",
ProductDetails = new ProductDetails()
{
Detail1 = "d1",
Detail2 = "d2",
Detail3 = "d3"
}
});
var oldModel = model;
// Act
var result = TryValidateModel(model, prefix: string.Empty, operationContext: operationContext);
// Assert
Assert.False(result);
Assert.False(modelState.IsValid);
var modelStateErrors = GetModelStateErrors(modelState);
Assert.Equal("CompanyName cannot be null or empty.", modelStateErrors["[0].CompanyName"]);
Assert.Equal("The field Price must be between 20 and 100.", modelStateErrors["[0].Price"]);
Assert.Equal(
PlatformNormalizer.NormalizeContent("The Category field is required."),
modelStateErrors["[0].Category"]);
AssertErrorEquals(
"The field Contact Us must be a string with a maximum length of 20." +
"The field Contact Us must match the regular expression " +
(TestPlatformHelper.IsMono ? "^[0-9]*$." : "'^[0-9]*$'."),
modelStateErrors["[0].Contact"]);
Assert.Equal("CompanyName cannot be null or empty.", modelStateErrors["[1].CompanyName"]);
Assert.Equal("The field Price must be between 20 and 100.", modelStateErrors["[1].Price"]);
Assert.Equal(
PlatformNormalizer.NormalizeContent("The Category field is required."),
modelStateErrors["[1].Category"]);
AssertErrorEquals(
"The field Contact Us must be a string with a maximum length of 20." +
"The field Contact Us must match the regular expression " +
(TestPlatformHelper.IsMono ? "^[0-9]*$." : "'^[0-9]*$'."),
modelStateErrors["[1].Contact"]);
}
private bool TryValidateModel(
object model,
string prefix,
OperationBindingContext operationContext)
{
var controller = new TestController();
controller.ControllerContext = new ControllerContext(operationContext.ActionContext);
controller.ObjectValidator = ModelBindingTestHelper.GetObjectValidator(operationContext.MetadataProvider);
controller.MetadataProvider = operationContext.MetadataProvider;
controller.ControllerContext.ValidatorProviders = new[] { operationContext.ValidatorProvider }.ToList();
return controller.TryValidateModel(model, prefix);
}
private void AssertErrorEquals(string expected, string actual)
{
// OrderBy is used because the order of the results may very depending on the platform / client.
Assert.Equal(
expected.Split('.').OrderBy(item => item, StringComparer.Ordinal),
actual.Split('.').OrderBy(item => item, StringComparer.Ordinal));
}
private Dictionary<string, string> GetModelStateErrors(ModelStateDictionary modelState)
{
var result = new Dictionary<string, string>();
foreach (var item in modelState)
{
var errorMessage = string.Empty;
foreach (var error in item.Value.Errors)
{
if (error != null)
{
errorMessage = errorMessage + error.ErrorMessage;
}
}
if (!string.IsNullOrEmpty(errorMessage))
{
result.Add(item.Key, errorMessage);
}
}
return result;
}
private class TestController : Controller
{
}
}
}

View File

@ -1,41 +1,39 @@
// 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 BasicWebSite.Models;
using Microsoft.AspNet.Mvc;
using ValidationWebSite.Models;
namespace ValidationWebSite.Controllers
namespace BasicWebSite.Areas.Area1.Controllers
{
[Area("Area1")]
[Route("[area]/[controller]/[action]")]
public class RemoteAttribute_HomeController : Controller
{
private static Person _person;
private static RemoteAttributeUser _user;
[HttpGet]
[Route("[Controller]/[Action]")]
public IActionResult Create()
{
return View();
}
[HttpPost]
[Route("[Controller]/[Action]")]
public IActionResult Create(Person person)
public IActionResult Create(RemoteAttributeUser user)
{
ModelState.Remove("id");
if (!ModelState.IsValid)
{
return View(person);
return View(user);
}
_person = person;
_user = user;
return RedirectToAction(nameof(Details));
}
[Route("", Name = "Home", Order = -1)]
[Route("[Controller]/Index")]
public IActionResult Details()
{
return View(_person);
return View(_user);
}
}
}
}

View File

@ -3,15 +3,15 @@
using Microsoft.AspNet.Mvc;
namespace ValidationWebSite.MyArea.Controllers
namespace BasicWebSite.Areas.Area1.Controllers
{
[Area("Aria")]
[Area("Area1")]
[Route("[area]/[controller]/[action]")]
public class RemoteAttribute_VerifyController : Controller
{
// This action is overloaded and may receive requests to validate either UserId1 or UserId3.
// Demonstrates use of the default error message.
[AcceptVerbs("Get", "Post")]
[Route("[Area]/[Controller]/[Action]", Order = -2)]
public IActionResult IsIdAvailable(string userId1, string userId3)
{
return Json(data: false);

View File

@ -1,9 +1,9 @@
@model ValidationWebSite.Models.Person
@model BasicWebSite.Models.RemoteAttributeUser
@{
Layout = "_Layout.cshtml";
object areaObject;
ViewContext.ActionDescriptor.RouteValueDefaults.TryGetValue("area", out areaObject);
var areaName = (areaObject as string) ?? "root";
ViewBag.Title = "Create in " + areaName + " area.";
}

View File

@ -1,9 +1,9 @@
@model ValidationWebSite.Models.Person
@model BasicWebSite.Models.RemoteAttributeUser
@{
Layout = "_Layout.cshtml";
object areaObject;
ViewContext.ActionDescriptor.RouteValueDefaults.TryGetValue("area", out areaObject);
var areaName = (areaObject as string) ?? "root";
ViewBag.Title = "Details in " + areaName + " area.";
}
@ -64,13 +64,5 @@
</div>
<p>
@Html.ActionLink("Create a new one", "Create") |
@if (string.Equals("Aria", areaName, StringComparison.OrdinalIgnoreCase))
{
@Html.RouteLink("Go back to home", "Home")
}
else
{
@Html.RouteLink("Go to Aria home", "AriaHome")
}
@Html.ActionLink("Create a new one", "Create")
</p>

View File

@ -9,13 +9,13 @@
<div>
<div>
<div>
@Html.ActionLink("Validation web site", "Details", "RemoteAttribute_Home", routeValues: new { area = (object)null })
@Html.ActionLink("Basic web site", "Details", "RemoteAttribute_Home", routeValues: new { area = (object)null })
</div>
<div>
<ul>
<li>@Html.ActionLink("Home", "Details", "RemoteAttribute_Home", routeValues: new { area = string.Empty })</li>
<li>@Html.ActionLink("Aria Home", "Details", "RemoteAttribute_Home", routeValues: new { area = "Aria" })</li>
<li>@Html.ActionLink("Area1 Home", "Details", "RemoteAttribute_Home", routeValues: new { area = "Area1" })</li>
</ul>
</div>
</div>

View File

@ -0,0 +1,25 @@
// 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.AspNet.Mvc;
using BasicWebSite.Models;
namespace BasicWebSite.Ares.Area2.Controllers
{
[Area("Area2")]
[Route("[area]/[controller]/[action]")]
public class RemoteAttribute_VerifyController : Controller
{
// Demonstrates validation action when AdditionalFields causes client to send multiple values.
[HttpGet]
public IActionResult IsIdAvailable(RemoteAttributeUser user)
{
return Json(data: string.Format(
"/Area2/RemoteAttribute_Verify/IsIdAvailable rejects '{0}' with '{1}', '{2}', and '{3}'.",
user.UserId4,
user.UserId1,
user.UserId2,
user.UserId3));
}
}
}

View File

@ -1,16 +1,15 @@
// 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 BasicWebSite.Models;
using Microsoft.AspNet.Mvc;
using ValidationWebSite.Models;
namespace ValidationWebSite.MyArea.Controllers
namespace BasicWebSite.Controllers
{
[Area("Aria")]
[Route("[Area]/[Controller]/[Action]", Order = -2)]
[Route("[controller]/[action]")]
public class RemoteAttribute_HomeController : Controller
{
private static Person _person;
private static RemoteAttributeUser _user;
[HttpGet]
public IActionResult Create()
@ -19,23 +18,21 @@ namespace ValidationWebSite.MyArea.Controllers
}
[HttpPost]
public IActionResult Create(Person person)
public IActionResult Create(RemoteAttributeUser user)
{
ModelState.Remove("id");
if (!ModelState.IsValid)
{
return View(person);
return View(user);
}
_person = person;
_user = user;
return RedirectToAction(nameof(Details));
}
[Route("/[Area]", Name = "AriaHome", Order = -3)]
[Route("/[Area]/[Controller]/Index", Order = -2)]
public IActionResult Details()
{
return View(_person);
return View(_user);
}
}
}
}

View File

@ -3,9 +3,9 @@
using Microsoft.AspNet.Mvc;
namespace ValidationWebSite.Controllers
namespace BasicWebSite.Controllers
{
[Route("[Controller]/[Action]")]
[Route("[controller]/[action]")]
public class RemoteAttribute_VerifyController : Controller
{
// This action is overloaded and may receive requests to validate either UserId1 or UserId2.

View File

@ -0,0 +1,34 @@
// 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.AspNet.Mvc;
namespace BasicWebSite.Models
{
public class RemoteAttributeUser
{
public int Id { get; set; }
// Controller in current area.
[Remote(action: "IsIdAvailable", controller: "RemoteAttribute_Verify")]
public string UserId1 { get; set; }
// Controller in root area.
[Remote(action: "IsIdAvailable", controller: "RemoteAttribute_Verify", areaName: null, HttpMethod = "Post")]
public string UserId2 { get; set; }
[Remote(
action: "IsIdAvailable",
controller: "RemoteAttribute_Verify",
areaName:"Area1",
ErrorMessage = "/Area1/RemoteAttribute_Verify/IsIdAvailable rejects you.")]
public string UserId3 { get; set; }
[Remote(
action:"IsIdAvailable",
controller: "RemoteAttribute_Verify",
areaName: "Area2",
AdditionalFields = "UserId1, UserId2, UserId3")]
public string UserId4 { get; set; }
}
}

View File

@ -30,6 +30,8 @@ namespace BasicWebSite
{
app.UseCultureReplacer();
app.UseStaticFiles();
// Initializes the RequestId service for each request
app.UseMiddleware<RequestIdMiddleware>();

View File

@ -0,0 +1,75 @@
@model BasicWebSite.Models.RemoteAttributeUser
@{
Layout = "_Layout.cshtml";
object areaObject;
ViewContext.ActionDescriptor.RouteValueDefaults.TryGetValue("area", out areaObject);
var areaName = (areaObject as string) ?? "root";
ViewBag.Title = "Create in " + areaName + " area.";
}
<h2>@ViewBag.Title</h2>
@using (Html.BeginForm())
{
<div class="form-horizontal">
<h4>Person</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Id, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Id, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Id, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.UserId1, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.UserId1, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.UserId1, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.UserId2, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.UserId2, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.UserId2, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.UserId3, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.UserId3, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.UserId3, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.UserId4, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.UserId4, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.UserId4, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Go back to home", "Details")
</div>
@section Scripts {
@* Until script helpers are available, add script references manually. *@
@* @Scripts.Render("~/bundles/jqueryval") *@
<script src="@Url.Content("~/lib/jquery-validation/jquery.validate.js")"></script>
<script src="@Url.Content("~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js")"></script>
}

View File

@ -0,0 +1,68 @@
@model BasicWebSite.Models.RemoteAttributeUser
@{
Layout = "_Layout.cshtml";
object areaObject;
ViewContext.ActionDescriptor.RouteValueDefaults.TryGetValue("area", out areaObject);
var areaName = (areaObject as string) ?? "root";
ViewBag.Title = "Details in " + areaName + " area.";
}
<h2>@ViewBag.Title</h2>
<div>
<h4>Person</h4>
<hr />
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.Id)
</dt>
<dd>
@Html.DisplayFor(model => model.Id)
</dd>
</dl>
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.UserId1)
</dt>
<dd>
@Html.DisplayFor(model => model.UserId1)
</dd>
</dl>
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.UserId2)
</dt>
<dd>
@Html.DisplayFor(model => model.UserId2)
</dd>
</dl>
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.UserId3)
</dt>
<dd>
@Html.DisplayFor(model => model.UserId3)
</dd>
</dl>
<dl class="dl-horizontal">
<dt>
@Html.DisplayNameFor(model => model.UserId4)
</dt>
<dd>
@Html.DisplayFor(model => model.UserId4)
</dd>
</dl>
</div>
<p>
@Html.ActionLink("Create a new one", "Create")
</p>

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - My ASP.NET Application</title>
</head>
<body>
<div>
<div>
<div>
@Html.ActionLink("Basic web site", "Details", "RemoteAttribute_Home", routeValues: new { area = (object)null })
</div>
<div>
<ul>
<li>@Html.ActionLink("Home", "Details", "RemoteAttribute_Home", routeValues: new { area = string.Empty })</li>
<li>@Html.ActionLink("Area1 Home", "Details", "RemoteAttribute_Home", routeValues: new { area = "Area1" })</li>
</ul>
</div>
</div>
</div>
<div>
@RenderBody()
</div>
<script src="~/lib/jquery/jquery.js"></script>
@RenderSection("scripts", required: false)
</body>
</html>

View File

@ -1,5 +1,5 @@
{
"name": "ValidationWebSite",
"name": "BasicWebSite",
"description": "Web site demonstrating various validations.",
"private": true,
"dependencies": {

View File

@ -1,6 +1,6 @@
{
{
"version": "0.0.0",
"name": "ValidationWebSite",
"name": "BasicWebSite",
"description": "Web site demonstrating various validations.",
"private": true,
"devDependencies": {

View File

@ -1,7 +1,7 @@
{
"commands": {
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
"kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5000"
"weblistener": "Microsoft.AspNet.Server.WebListener",
"web": "Microsoft.AspNet.Server.Kestrel"
},
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-*",
@ -15,5 +15,9 @@
"dnx451": { },
"dnxcore50": { }
},
"webroot": "wwwroot"
"exclude": [
"wwwroot",
"node_modules",
"bower_components"
]
}

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
</handlers>
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" forwardWindowsAuthToken="false" startupTimeLimit="3600" />
</system.webServer>
</configuration>

View File

@ -1,67 +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.AspNet.Mvc;
namespace ResponseCacheWebSite
{
public class CacheHeadersController : Controller
{
[HttpGet("/CacheHeaders/Index")]
[ResponseCache(Duration = 100, Location = ResponseCacheLocation.Any, VaryByHeader = "Accept")]
public IActionResult Index()
{
return Content("Hello World!");
}
[HttpGet("/CacheHeaders/PublicCache")]
[ResponseCache(Duration = 100, Location = ResponseCacheLocation.Any)]
public IActionResult PublicCache()
{
return Content("Hello World!");
}
[HttpGet("/CacheHeaders/ClientCache")]
[ResponseCache(Duration = 100, Location = ResponseCacheLocation.Client)]
public IActionResult ClientCache()
{
return Content("Hello World!");
}
[HttpGet("/CacheHeaders/NoStore")]
[ResponseCache(NoStore = true, Duration = 0)]
public IActionResult NoStore()
{
return Content("Hello World!");
}
[HttpGet("/CacheHeaders/NoCacheAtAll")]
[ResponseCache(NoStore = true, Duration = 0, Location = ResponseCacheLocation.None)]
public IActionResult NoCacheAtAll()
{
return Content("Hello World!");
}
[HttpGet("/CacheHeaders/SetHeadersInAction")]
[ResponseCache(Duration = 40)]
public IActionResult SetHeadersInAction()
{
Response.Headers["Cache-control"] = "max-age=10";
return Content("Hello World!");
}
[HttpGet("/CacheHeaders/SetsCacheControlPublicByDefault")]
[ResponseCache(Duration = 40)]
public IActionResult SetsCacheControlPublicByDefault()
{
return Content("Hello World!");
}
[HttpGet("/CacheHeaders/ThrowsWhenDurationIsNotSet")]
[ResponseCache(VaryByHeader = "Accept")]
public IActionResult ThrowsWhenDurationIsNotSet()
{
return Content("Hello World!");
}
}
}

View File

@ -1,51 +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.AspNet.Mvc;
namespace ResponseCacheWebSite.Controllers
{
public class CacheProfilesController
{
[HttpGet("/CacheProfiles/PublicCache30Sec")]
[ResponseCache(CacheProfileName = "PublicCache30Sec")]
public string PublicCache30Sec()
{
return "Hello World!";
}
[HttpGet("/CacheProfiles/PrivateCache30Sec")]
[ResponseCache(CacheProfileName = "PrivateCache30Sec")]
public string PrivateCache30Sec()
{
return "Hello World!";
}
[HttpGet("/CacheProfiles/NoCache")]
[ResponseCache(CacheProfileName = "NoCache")]
public string NoCache()
{
return "Hello World!";
}
[HttpGet("/CacheProfiles/CacheProfileAddParameter")]
[ResponseCache(CacheProfileName = "PublicCache30Sec", VaryByHeader = "Accept")]
public string CacheProfileAddParameter()
{
return "Hello World!";
}
[HttpGet("/CacheProfiles/CacheProfileOverride")]
[ResponseCache(CacheProfileName = "PublicCache30Sec", Duration = 10)]
public string CacheProfileOverride()
{
return "Hello World!";
}
[HttpGet("/CacheProfiles/FallbackToFilter")]
public string FallbackToFilter()
{
return "Hello World!";
}
}
}

View File

@ -1,43 +0,0 @@
using System;
using Microsoft.AspNet.Mvc;
namespace ResponseCacheWebSite.Controllers
{
public class CacheProfilesOverridesController
{
[HttpGet("/CacheProfileOverrides/PublicCache30SecTo15Sec")]
[ResponseCache(CacheProfileName = "PublicCache30Sec", Duration = 15)]
public string PublicCache30SecTo15Sec()
{
return "Hello World!";
}
[HttpGet("/CacheProfileOverrides/PublicCache30SecToPrivateCache")]
[ResponseCache(CacheProfileName = "PublicCache30Sec", Location = ResponseCacheLocation.Client)]
public string PublicCache30SecToPrivateCache()
{
return "Hello World!";
}
[HttpGet("/CacheProfileOverrides/PublicCache30SecToNoStore")]
[ResponseCache(CacheProfileName = "PublicCache30Sec", NoStore = true)]
public string PublicCache30SecToNoStore()
{
return "Hello World!";
}
[HttpGet("/CacheProfileOverrides/PublicCache30SecWithVaryByAcceptToVaryByTest")]
[ResponseCache(CacheProfileName = "PublicCache30Sec", VaryByHeader = "Test")]
public string PublicCache30SecWithVaryByAcceptToVaryByTest()
{
return "Hello World!";
}
[HttpGet("/CacheProfileOverrides/PublicCache30SecWithVaryByAcceptToVaryByNone")]
[ResponseCache(CacheProfileName = "PublicCache30Sec", VaryByHeader = null)]
public string PublicCache30SecWithVaryByAcceptToVaryByNone()
{
return "Hello World!";
}
}
}

View File

@ -1,37 +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.AspNet.Mvc;
namespace ResponseCacheWebSite
{
[ResponseCache(Duration = 100, Location = ResponseCacheLocation.Any, VaryByHeader = "Accept")]
public class ClassLevelCacheController
{
[HttpGet("/ClassLevelCache/GetHelloWorld")]
public string GetHelloWorld()
{
return "Hello, World!";
}
[HttpGet("/ClassLevelCache/GetFooBar")]
public string GetFooBar()
{
return "Foo Bar!";
}
[HttpGet("/ClassLevelCache/ConflictExistingHeader")]
[ResponseCache(Duration = 20)]
public string ConflictExistingHeader()
{
return "Conflict";
}
[HttpGet("/ClassLevelCache/DoNotCacheThisAction")]
[ResponseCache(NoStore = true, Duration = 0, Location = ResponseCacheLocation.None)]
public string DoNotCacheThisAction()
{
return "Conflict";
}
}
}

View File

@ -1,31 +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.AspNet.Mvc;
namespace ResponseCacheWebSite
{
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None, Duration = 0)]
public class ClassLevelNoStoreController
{
[HttpGet("/ClassLevelNoStore/GetHelloWorld")]
public string GetHelloWorld()
{
return "Hello, World!";
}
[HttpGet("/ClassLevelNoStore/CacheThisAction")]
[ResponseCache(VaryByHeader = "Accept", Duration = 10)]
public string CacheThisAction()
{
return "Conflict";
}
[HttpGet("/ClassLevelNoStore/CacheThisActionWithProfileSettings")]
[ResponseCache(CacheProfileName = "PublicCache30Sec", VaryByHeader = "Accept")]
public string CacheThisActionWithProfileSettings()
{
return "Conflict";
}
}
}

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>bdeebe09-c0c4-433c-b0b8-8478c9776996</ProjectGuid>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>63072</DevelopmentServerPort>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -1,61 +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.AspNet.Builder;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
namespace ResponseCacheWebSite
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
options.CacheProfiles.Add(
"PublicCache30Sec", new CacheProfile
{
Duration = 30,
Location = ResponseCacheLocation.Any
});
options.CacheProfiles.Add(
"PrivateCache30Sec", new CacheProfile
{
Duration = 30,
Location = ResponseCacheLocation.Client
});
options.CacheProfiles.Add(
"NoCache", new CacheProfile
{
NoStore = true,
Duration = 0,
Location = ResponseCacheLocation.None
});
options.CacheProfiles.Add(
"PublicCache30SecVaryByAcceptHeader", new CacheProfile
{
Duration = 30,
Location = ResponseCacheLocation.Any,
VaryByHeader = "Accept"
});
options.Filters.Add(new ResponseCacheFilter(new CacheProfile
{
NoStore = true,
VaryByHeader = "TestDefault",
}));
});
}
public void Configure(IApplicationBuilder app)
{
app.UseCultureReplacer();
app.UseMvcWithDefaultRoute();
}
}
}

View File

@ -1,18 +0,0 @@
{
"commands": {
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
"kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5000"
},
"dependencies": {
"Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
},
"webroot": "wwwroot"
}

View File

@ -1,4 +0,0 @@
ResponseCacheWebSite
===
This web site illustrates how to use response caching.

View File

@ -1 +0,0 @@
HelloWorld

File diff suppressed because one or more lines are too long

View File

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>a192e504-2881-41dc-90d1-b7f1dd1134e8</ProjectGuid>
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
<DevelopmentServerPort>49643</DevelopmentServerPort>
</PropertyGroup>
<Import Project="$(VSToolsPath)\DNX\Microsoft.DNX.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -1,18 +0,0 @@
{
"commands": {
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
"kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5000"
},
"dependencies": {
"Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
},
"webroot": "wwwroot"
}

View File

@ -1 +0,0 @@
HelloWorld

View File

@ -1,25 +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.AspNet.Mvc;
using ValidationWebSite.Models;
namespace ValidationWebSite.AnotherArea.Controllers
{
[Area("AnotherAria")]
[Route("[Area]/[Controller]/[Action]", Order = -2)]
public class RemoteAttribute_VerifyController : Controller
{
// Demonstrates validation action when AdditionalFields causes client to send multiple values.
[HttpGet]
public IActionResult IsIdAvailable(Person person)
{
return Json(data: string.Format(
"/AnotherAria/RemoteAttribute_Verify/IsIdAvailable rejects '{0}' with '{1}', '{2}', and '{3}'.",
person.UserId4,
person.UserId1,
person.UserId2,
person.UserId3));
}
}
}

View File

@ -1,110 +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 System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using Microsoft.AspNet.Mvc;
using ValidationWebSite.ViewModels;
namespace ValidationWebSite.Controllers
{
public class ModelMetadataTypeValidationController : Controller
{
[HttpPost]
public object ValidateProductViewModelIncludingMetadata([FromBody] ProductViewModel product)
{
return CreateValidationDictionary();
}
[HttpPost]
public object ValidateSoftwareViewModelIncludingMetadata([FromBody] SoftwareViewModel software)
{
return CreateValidationDictionary();
}
[HttpPost]
public object TryValidateModelAfterClearingValidationErrorInParameter(
[Required, MaxLength(3), StringLength(10, MinimumLength = 3)] string theImpossibleString,
[FromBody] ProductViewModel product)
{
// Clear ModelState entry. TryValidateModel should not add entries except those found within the
// passed model.
ModelState.ClearValidationState("theImpossibleString");
TryValidateModel(product);
return CreateValidationDictionary();
}
[HttpPost]
public object TryValidateModelWithCollectionsModel([FromBody] List<ProductViewModel> products)
{
TryValidateModel(products);
return CreateValidationDictionary();
}
[HttpGet]
public object TryValidateModelSoftwareViewModelWithPrefix()
{
var softwareViewModel = new SoftwareViewModel
{
Category = "Technology",
CompanyName = "Microsoft",
Contact = "4258393231",
Country = "UK",
DatePurchased = new DateTime(2010, 10, 10),
Price = 110,
Version = "2"
};
TryValidateModel(softwareViewModel, "software");
return CreateValidationDictionary();
}
[HttpGet]
public object TryValidateModelValidModelNoPrefix()
{
var softwareViewModel = new SoftwareViewModel
{
Category = "Technology",
CompanyName = "Microsoft",
Contact = "4258393231",
Country = "USA",
DatePurchased = new DateTime(2010, 10, 10),
Name = "MVC",
Price = 110,
Version = "2"
};
TryValidateModel(softwareViewModel);
return CreateValidationDictionary();
}
private Dictionary<string, string> CreateValidationDictionary()
{
var result = new Dictionary<string, string>();
foreach (var item in ModelState)
{
var errorMessage = string.Empty;
foreach (var error in item.Value.Errors)
{
if (error != null)
{
errorMessage = errorMessage + error.ErrorMessage;
}
}
if (!string.IsNullOrEmpty(errorMessage))
{
result.Add(item.Key, errorMessage);
}
}
return result;
}
}
}

View File

@ -1,36 +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.AspNet.Mvc;
namespace ValidationWebSite.Models
{
public class Person
{
public int Id { get; set; }
// Controller in current area.
[Remote("IsIdAvailable", "RemoteAttribute_Verify")]
public string UserId1 { get; set; }
// Controller in root area.
[Remote("IsIdAvailable", "RemoteAttribute_Verify", null, HttpMethod = "Post")]
public string UserId2 { get; set; }
// Controller in MyArea area.
[Remote(
"IsIdAvailable",
"RemoteAttribute_Verify",
"Aria",
ErrorMessage = "/Aria/RemoteAttribute_Verify/IsIdAvailable rejects you.")]
public string UserId3 { get; set; }
// Controller in AnotherArea area.
[Remote(
"IsIdAvailable",
"RemoteAttribute_Verify",
"AnotherAria",
AdditionalFields = "UserId1, UserId2, UserId3")]
public string UserId4 { get; set; }
}
}

View File

@ -1,6 +0,0 @@
ValidationWebSite
===
This web site illustrates how to add `ModelMetadataType` attribute and validate the models during model binding.
It also show how to validate models using the `TryValidateModel` API as well as how to use the `RemoteAttribute` as
part of validation. `RemoteAttribute` scenarios shown here all work in combination with attribute routing.

View File

@ -1,7 +0,0 @@
@{
Layout = "/Views/Shared/_Layout.cshtml";
ViewBag.Title = "Error";
}
<h1>Error.</h1>
<h2>An error occurred while processing your request.</h2>

View File

@ -1,3 +0,0 @@
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}

View File

@ -1,27 +0,0 @@
{
"commands": {
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
"kestrel": "Microsoft.AspNet.Hosting --server Microsoft.AspNet.Server.Kestrel --server.urls http://localhost:5000"
},
"dependencies": {
"Microsoft.AspNet.Server.Kestrel": "1.0.0-*",
"Microsoft.AspNet.Mvc": "6.0.0-*",
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
},
"frameworks": {
"dnx451": { },
"dnxcore50": { }
},
"exclude": [
"wwwroot",
"node_modules",
"bower_components"
],
"publishExclude": [
"**.user",
"**.vspscc"
],
"webroot": "wwwroot"
}

View File

@ -1 +0,0 @@
HelloWorld