From 6ee034e64fef259e3ecf7a07f949b8f19ec20921 Mon Sep 17 00:00:00 2001 From: harshgMSFT Date: Tue, 22 Jul 2014 16:26:27 -0700 Subject: [PATCH] ProducesAttribute + Adding Functional Tests Conflicts: src/Microsoft.AspNet.Mvc.Core/Formatters/OutputFormatter.cs src/Microsoft.AspNet.Mvc.Core/Resources.resx src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/project.json test/Microsoft.AspNet.Mvc.FunctionalTests/project.json Adding Resources + tests Conflicts: src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs src/Microsoft.AspNet.Mvc.Core/Resources.resx Adding produces content Attribute Conflicts: src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj Conflicts: src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj test/Microsoft.AspNet.Mvc.Core.Test/Microsoft.AspNet.Mvc.Core.Test.kproj --- Mvc.sln | 17 ++ samples/MvcSample.Web/HomeController.cs | 6 + .../ActionResults/ObjectResult.cs | 6 +- .../Filters/ProducesAttribute.cs | 52 ++++ .../Formatters/OutputFormatter.cs | 5 +- .../IProducesMetadataProvider.cs | 25 ++ .../Microsoft.AspNet.Mvc.Core.kproj | 28 +- .../MediaTypeHeaderValue.cs | 20 +- ...t.AspNet.Mvc.HeaderValueAbstractions.kproj | 6 + .../Properties/Resources.Designer.cs | 46 ++++ .../Resources.resx | 123 +++++++++ .../project.json | 2 + .../Filters/ProducesAttributeTests.cs | 80 ++++++ .../Microsoft.AspNet.Mvc.Core.Test.kproj | 11 +- .../project.json | 1 + .../ConnegTests.cs | 253 ++++++++++++++++++ ...Microsoft.AspNet.Mvc.FunctionalTests.kproj | 1 + .../project.json | 1 + .../ConnegWebSite/ConnegWebsite.kproj | 41 +++ test/WebSites/ConnegWebSite/ContentType.cs | 45 ++++ .../Controllers/HomeController.cs | 15 ++ .../NoProducesContentOnClassController.cs | 28 ++ .../Controllers/NormalController.cs | 64 +++++ .../ProducesContentBaseController.cs | 42 +++ .../ProducesContentOnClassController.cs | 44 +++ .../Controllers/TextPlainController.cs | 51 ++++ test/WebSites/ConnegWebSite/Models/User.cs | 17 ++ .../ConnegWebSite/PlainTextFormatter.cs | 43 +++ test/WebSites/ConnegWebSite/Startup.cs | 31 +++ test/WebSites/ConnegWebSite/project.json | 11 + 30 files changed, 1089 insertions(+), 26 deletions(-) create mode 100644 src/Microsoft.AspNet.Mvc.Core/Filters/ProducesAttribute.cs create mode 100644 src/Microsoft.AspNet.Mvc.Core/IProducesMetadataProvider.cs create mode 100644 src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Properties/Resources.Designer.cs create mode 100644 src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Resources.resx create mode 100644 test/Microsoft.AspNet.Mvc.Core.Test/Filters/ProducesAttributeTests.cs create mode 100644 test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs create mode 100644 test/WebSites/ConnegWebSite/ConnegWebsite.kproj create mode 100644 test/WebSites/ConnegWebSite/ContentType.cs create mode 100644 test/WebSites/ConnegWebSite/Controllers/HomeController.cs create mode 100644 test/WebSites/ConnegWebSite/Controllers/NoProducesContentOnClassController.cs create mode 100644 test/WebSites/ConnegWebSite/Controllers/NormalController.cs create mode 100644 test/WebSites/ConnegWebSite/Controllers/ProducesContentBaseController.cs create mode 100644 test/WebSites/ConnegWebSite/Controllers/ProducesContentOnClassController.cs create mode 100644 test/WebSites/ConnegWebSite/Controllers/TextPlainController.cs create mode 100644 test/WebSites/ConnegWebSite/Models/User.cs create mode 100644 test/WebSites/ConnegWebSite/PlainTextFormatter.cs create mode 100644 test/WebSites/ConnegWebSite/Startup.cs create mode 100644 test/WebSites/ConnegWebSite/project.json diff --git a/Mvc.sln b/Mvc.sln index 8f7bca4e31..d6c3adbc18 100644 --- a/Mvc.sln +++ b/Mvc.sln @@ -61,6 +61,12 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Header EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.HeaderValueAbstractions.Tests", "test\Microsoft.AspNet.Mvc.HeaderValueAbstractions.Test\Microsoft.AspNet.Mvc.HeaderValueAbstractions.Tests.kproj", "{E69FD235-2042-43A4-9970-59CB29955B4E}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FAD65E9C-3CF3-4F68-9757-C7358604030B}" + ProjectSection(SolutionItems) = preProject + global.json = global.json + EndProjectSection +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ConnegWebsite", "test\WebSites\ConnegWebSite\ConnegWebsite.kproj", "{C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -321,6 +327,16 @@ Global {E69FD235-2042-43A4-9970-59CB29955B4E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {E69FD235-2042-43A4-9970-59CB29955B4E}.Release|Mixed Platforms.Build.0 = Release|Any CPU {E69FD235-2042-43A4-9970-59CB29955B4E}.Release|x86.ActiveCfg = Release|Any CPU + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Debug|x86.ActiveCfg = Debug|Any CPU + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|Any CPU.Build.0 = Release|Any CPU + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -352,5 +368,6 @@ Global {14F79E79-AE79-48FA-95DE-D794EF4EABB3} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} {98335B23-E4B9-4CAD-9749-0DED32A659A1} = {32285FA4-6B46-4D6B-A840-2B13E4C8B58E} {E69FD235-2042-43A4-9970-59CB29955B4E} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1} + {C6E5AFFA-890A-448F-8DE3-878B1D3C9FC7} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C} EndGlobalSection EndGlobal diff --git a/samples/MvcSample.Web/HomeController.cs b/samples/MvcSample.Web/HomeController.cs index 0fce895466..2928cde9e4 100644 --- a/samples/MvcSample.Web/HomeController.cs +++ b/samples/MvcSample.Web/HomeController.cs @@ -97,6 +97,12 @@ namespace MvcSample.Web Context.Response.WriteAsync("Hello World raw"); } + [Produces("application/json", "application/custom", "text/json", Type = typeof(User))] + public object ReturnUser() + { + return CreateUser(); + } + public User CreateUser() { User user = new User() diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionResults/ObjectResult.cs b/src/Microsoft.AspNet.Mvc.Core/ActionResults/ObjectResult.cs index 4e633b5c8e..0d54fb1fce 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ActionResults/ObjectResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ActionResults/ObjectResult.cs @@ -71,9 +71,11 @@ namespace Microsoft.AspNet.Mvc if (selectedFormatter == null) { + var requestContentType = formatterContext.ActionContext.HttpContext.Request.ContentType; + // No formatter found based on accept headers, fall back on request contentType. - var incomingContentType = - MediaTypeHeaderValue.Parse(formatterContext.ActionContext.HttpContext.Request.ContentType); + MediaTypeHeaderValue incomingContentType = null; + MediaTypeHeaderValue.TryParse(requestContentType, out incomingContentType); // In case the incomingContentType is null (as can be the case with get requests), // we need to pick the first formatter which diff --git a/src/Microsoft.AspNet.Mvc.Core/Filters/ProducesAttribute.cs b/src/Microsoft.AspNet.Mvc.Core/Filters/ProducesAttribute.cs new file mode 100644 index 0000000000..534a0345c9 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/Filters/ProducesAttribute.cs @@ -0,0 +1,52 @@ +// 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.Collections.Generic; +using System.Linq; +using Microsoft.AspNet.Mvc.Core; +using Microsoft.AspNet.Mvc.HeaderValueAbstractions; + +namespace Microsoft.AspNet.Mvc +{ + /// + /// Specifies the allowed content types and the type of the value returned by the action + /// which can be used to select a formatter while executing . + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)] + public class ProducesAttribute : ResultFilterAttribute, IProducesMetadataProvider + { + public ProducesAttribute(string contentType, params string[] additionalContentTypes) + { + ContentTypes = GetContentTypes(contentType, additionalContentTypes); + } + + public Type Type { get; set; } + + public IList ContentTypes { get; set; } + + public override void OnResultExecuting([NotNull] ResultExecutingContext context) + { + base.OnResultExecuting(context); + var objectResult = context.Result as ObjectResult; + + if (objectResult != null) + { + objectResult.ContentTypes = ContentTypes; + } + } + + private List GetContentTypes(string firstArg, string[] args) + { + var contentTypes = new List(); + contentTypes.Add(MediaTypeHeaderValue.Parse(firstArg)); + foreach (var item in args) + { + var contentType = MediaTypeHeaderValue.Parse(item); + contentTypes.Add(contentType); + } + + return contentTypes; + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/Formatters/OutputFormatter.cs b/src/Microsoft.AspNet.Mvc.Core/Formatters/OutputFormatter.cs index 9bd41f033d..ff42bb55b8 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Formatters/OutputFormatter.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Formatters/OutputFormatter.cs @@ -53,8 +53,9 @@ namespace Microsoft.AspNet.Mvc if (encoding == null) { // Match based on request acceptHeader. - var requestContentType = MediaTypeHeaderValue.Parse(request.ContentType); - if (requestContentType != null && !string.IsNullOrEmpty(requestContentType.Charset)) + MediaTypeHeaderValue requestContentType = null; + if (MediaTypeHeaderValue.TryParse(request.ContentType, out requestContentType) && + !string.IsNullOrEmpty(requestContentType.Charset)) { var requestCharset = requestContentType.Charset; encoding = SupportedEncodings.FirstOrDefault( diff --git a/src/Microsoft.AspNet.Mvc.Core/IProducesMetadataProvider.cs b/src/Microsoft.AspNet.Mvc.Core/IProducesMetadataProvider.cs new file mode 100644 index 0000000000..2dc8f58fd6 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/IProducesMetadataProvider.cs @@ -0,0 +1,25 @@ +// 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.Collections.Generic; +using Microsoft.AspNet.Mvc.HeaderValueAbstractions; + +namespace Microsoft.AspNet.Mvc +{ + /// + /// Provides a return type and a set of possible content types returned by a successful execution of the action. + /// + public interface IProducesMetadataProvider + { + /// + /// Optimistic return type of the action. + /// + Type Type { get; set; } + + /// + /// A collection of allowed content types which can be produced by the action. + /// + IList ContentTypes { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj b/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj index 2735d502b4..95345dd69e 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj +++ b/src/Microsoft.AspNet.Mvc.Core/Microsoft.AspNet.Mvc.Core.kproj @@ -35,28 +35,30 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/MediaTypeHeaderValue.cs b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/MediaTypeHeaderValue.cs index cfbfac16d9..c8011b52a4 100644 --- a/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/MediaTypeHeaderValue.cs +++ b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/MediaTypeHeaderValue.cs @@ -52,16 +52,28 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions public static MediaTypeHeaderValue Parse(string input) { + MediaTypeHeaderValue headerValue = null; + if (!TryParse(input, out headerValue)) + { + throw new ArgumentException(Resources.FormatInvalidContentType(input)); + } + + return headerValue; + } + + public static bool TryParse(string input, out MediaTypeHeaderValue headerValue) + { + headerValue = null; if (string.IsNullOrEmpty(input)) { - return null; + return false; } var inputArray = input.Split(new[] { ';' }, 2); var mediaTypeParts = inputArray[0].Split('/'); if (mediaTypeParts.Length != 2) { - return null; + return false; } // TODO: throw if the media type and subtypes are invalid. @@ -85,7 +97,7 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions parameters.TryGetValue("charset", out charset); } - var mediaTypeHeader = new MediaTypeHeaderValue() + headerValue = new MediaTypeHeaderValue() { MediaType = mediaType, MediaSubType = mediaSubType, @@ -94,7 +106,7 @@ namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions Parameters = parameters ?? new Dictionary(StringComparer.OrdinalIgnoreCase), }; - return mediaTypeHeader; + return true; } protected static Dictionary ParseParameters(string inputString) diff --git a/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Microsoft.AspNet.Mvc.HeaderValueAbstractions.kproj b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Microsoft.AspNet.Mvc.HeaderValueAbstractions.kproj index d9ecfd883f..6fc2ae284f 100644 --- a/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Microsoft.AspNet.Mvc.HeaderValueAbstractions.kproj +++ b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Microsoft.AspNet.Mvc.HeaderValueAbstractions.kproj @@ -21,10 +21,16 @@ + + + + ResXFileCodeGenerator + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..2299e4a0fd --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Properties/Resources.Designer.cs @@ -0,0 +1,46 @@ +// +namespace Microsoft.AspNet.Mvc.HeaderValueAbstractions +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.AspNet.Mvc.HeaderValueAbstractions.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// Invalid Argument. Content type '{0}' could not be parsed. + /// + internal static string InvalidContentType + { + get { return GetString("InvalidContentType"); } + } + + /// + /// Invalid Argument. Content type '{0}' could not be parsed. + /// + internal static string FormatInvalidContentType(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidContentType"), p0); + } + + private static string GetString(string name, params string[] formatterNames) + { + var value = _resourceManager.GetString(name); + + System.Diagnostics.Debug.Assert(value != null); + + if (formatterNames != null) + { + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } + } + + return value; + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Resources.resx b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Resources.resx new file mode 100644 index 0000000000..d1a33eedd0 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/Resources.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Invalid Argument. Content type '{0}' could not be parsed. + + \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/project.json b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/project.json index 0cbe5678d9..710b4d10bd 100644 --- a/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/project.json +++ b/src/Microsoft.AspNet.Mvc.HeaderValueAbstractions/project.json @@ -6,6 +6,8 @@ "k10": { "dependencies": { "System.Collections": "4.0.10.0", + "System.Diagnostics.Debug": "4.0.10.0", + "System.Resources.ResourceManager": "4.0.0.0", "System.Runtime": "4.0.20.0", "System.Runtime.Extensions": "4.0.10.0" } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Filters/ProducesAttributeTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Filters/ProducesAttributeTests.cs new file mode 100644 index 0000000000..ae0992cbeb --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Filters/ProducesAttributeTests.cs @@ -0,0 +1,80 @@ +// 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.Threading.Tasks; +using Microsoft.AspNet.Mvc.HeaderValueAbstractions; +using Microsoft.AspNet.PipelineCore; +using Microsoft.AspNet.Routing; +using Xunit; + +namespace Microsoft.AspNet.Mvc.Test +{ + public class ProducesAttributeTests + { + [Fact] + public async Task ProducesContentAttribute_SetsContentType() + { + // Arrange + var mediaType1 = MediaTypeHeaderValue.Parse("application/json"); + var mediaType2 = MediaTypeHeaderValue.Parse("text/json;charset=utf-8"); + var producesContentAttribute = new ProducesAttribute("application/json", "text/json;charset=utf-8"); + var resultExecutingContext = CreateResultExecutingContext(producesContentAttribute); + var next = new ResultExecutionDelegate( + () => Task.FromResult(CreateResultExecutedContext(resultExecutingContext))); + + // Act + await producesContentAttribute.OnResultExecutionAsync(resultExecutingContext, next); + + // Assert + var objectResult = resultExecutingContext.Result as ObjectResult; + Assert.Equal(2, objectResult.ContentTypes.Count); + ValidateMediaType(mediaType1, objectResult.ContentTypes[0]); + ValidateMediaType(mediaType2, objectResult.ContentTypes[1]); + } + + [Theory] + [InlineData("")] + [InlineData(null)] + [InlineData("invalid")] + public void ProducesAttribute_InvalidContentType_Throws(string content) + { + // Act & Assert + var ex = Assert.Throws( + () => new ProducesAttribute(content)); + Assert.Equal("Invalid Argument. Content type '" + content + "' could not be parsed.", + ex.Message); + } + + private static void ValidateMediaType(MediaTypeHeaderValue expectedMediaType, MediaTypeHeaderValue actualMediaType) + { + Assert.Equal(expectedMediaType.MediaType, actualMediaType.MediaType); + Assert.Equal(expectedMediaType.MediaSubType, actualMediaType.MediaSubType); + Assert.Equal(expectedMediaType.Charset, actualMediaType.Charset); + Assert.Equal(expectedMediaType.MediaTypeRange, actualMediaType.MediaTypeRange); + Assert.Equal(expectedMediaType.Parameters.Count, actualMediaType.Parameters.Count); + foreach (var item in expectedMediaType.Parameters) + { + Assert.Equal(item.Value, actualMediaType.Parameters[item.Key]); + } + } + + private static ResultExecutedContext CreateResultExecutedContext(ResultExecutingContext context) + { + return new ResultExecutedContext(context, context.Filters, context.Result); + } + + private static ResultExecutingContext CreateResultExecutingContext(IFilter filter) + { + return new ResultExecutingContext( + CreateActionContext(), + new IFilter[] { filter, }, + new ObjectResult("Some Value")); + } + + private static ActionContext CreateActionContext() + { + return new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Microsoft.AspNet.Mvc.Core.Test.kproj b/test/Microsoft.AspNet.Mvc.Core.Test/Microsoft.AspNet.Mvc.Core.Test.kproj index 9cc9c1569c..971a81b273 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Microsoft.AspNet.Mvc.Core.Test.kproj +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Microsoft.AspNet.Mvc.Core.Test.kproj @@ -31,6 +31,8 @@ + + @@ -40,6 +42,7 @@ + @@ -48,12 +51,10 @@ + - - - @@ -92,8 +93,8 @@ - + @@ -103,10 +104,10 @@ + - diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/project.json b/test/Microsoft.AspNet.Mvc.Core.Test/project.json index 28f4d47e51..d5d27f9f21 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/project.json +++ b/test/Microsoft.AspNet.Mvc.Core.Test/project.json @@ -4,6 +4,7 @@ }, "dependencies": { "Microsoft.AspNet.Http": "1.0.0-*", + "Microsoft.AspNet.PipelineCore": "1.0.0-*", "Microsoft.AspNet.Mvc.HeaderValueAbstractions": "1.0.0-*", "Microsoft.AspNet.Mvc" : "", "Microsoft.AspNet.Mvc.Core" : "", diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs new file mode 100644 index 0000000000..fe2fb85a78 --- /dev/null +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ConnegTests.cs @@ -0,0 +1,253 @@ +// 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.Threading.Tasks; +using ConnegWebsite; +using Microsoft.AspNet.Builder; +using Microsoft.AspNet.TestHost; +using Xunit; + +namespace Microsoft.AspNet.Mvc.FunctionalTests +{ + public class ConnegTests + { + private readonly IServiceProvider _provider = TestHelper.CreateServices("ConnegWebsite"); + private readonly Action _app = new Startup().Configure; + + [Fact] + public async Task ProducesContentAttribute_SingleContentType_PicksTheFirstSupportedFormatter() + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + + // Selects custom even though it is last in the list. + var expectedContentType = "application/custom;charset=utf-8"; + var expectedBody = "Written using custom format."; + + // Act + var result = await client.GetAsync("http://localhost/Normal/WriteUserUsingCustomFormat"); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + Assert.Equal(expectedBody, body); + } + + [Fact] + public async Task ProducesContentAttribute_MultipleContentTypes_RunsConnegToSelectFormatter() + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + var expectedContentType = "application/json;charset=utf-8"; + var expectedBody = "{\r\n \"Name\": \"My name\",\r\n \"Address\": \"My address\"\r\n}"; + + // Act + var result = await client.GetAsync("http://localhost/Normal/MultipleAllowedContentTypes"); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + Assert.Equal(expectedBody, body); + } + + [Fact] + public async Task NoProducesContentAttribute_ActionReturningString_RunsUsingTextFormatter() + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + var expectedContentType = "text/plain;charset=utf-8"; + var expectedBody = "NormalController"; + + // Act + var result = await client.GetAsync("http://localhost/Normal/ReturnClassName"); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + Assert.Equal(expectedBody, body); + } + + [Fact] + public async Task NoProducesContentAttribute_ActionReturningAnyObject_RunsUsingDefaultFormatters() + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + var expectedContentType = "application/json;charset=utf-8"; + //var expectedBody = "\"NormalController\""; + + // Act + var result = await client.GetAsync("http://localhost/Normal/ReturnUser"); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + } + + [Fact] + public async Task NoMatchingFormatter_ForTheGivenContentType_Returns406() + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + + // Act + var result = await client.GetAsync("http://localhost/Normal/ReturnUser_NoMatchingFormatter"); + + // Assert + Assert.Equal(406, result.HttpContext.Response.StatusCode); + } + + [Fact] + public async Task ProducesContentAttribute_OnAction_OverridesTheValueOnClass() + { + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + + // Value on the class is application/json. + var expectedContentType = "application/custom_ProducesContentBaseController_Action;charset=utf-8"; + var expectedBody = "ProducesContentBaseController"; + + // Act + var result = await client.GetAsync("http://localhost/ProducesContentBase/ReturnClassName"); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + Assert.Equal(expectedBody, body); + } + + [Fact] + public async Task ProducesContentAttribute_OnDerivedClass_OverridesTheValueOnBaseClass() + { + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + var expectedContentType = "application/custom_ProducesContentOnClassController;charset=utf-8"; + var expectedBody = "ProducesContentOnClassController"; + + // Act + var result = await client.GetAsync( + "http://localhost/ProducesContentOnClass/ReturnClassNameWithNoContentTypeOnAction"); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + Assert.Equal(expectedBody, body); + } + + [Fact] + public async Task ProducesContentAttribute_OnDerivedAction_OverridesTheValueOnBaseClass() + { + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + var expectedContentType = "application/custom_NoProducesContentOnClassController_Action;charset=utf-8"; + var expectedBody = "NoProducesContentOnClassController"; + + // Act + var result = await client.GetAsync("http://localhost/NoProducesContentOnClass/ReturnClassName"); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + Assert.Equal(expectedBody, body); + } + + [Fact] + public async Task ProducesContentAttribute_OnDerivedAction_OverridesTheValueOnBaseAction() + { + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + var expectedContentType = "application/custom_NoProducesContentOnClassController_Action;charset=utf-8"; + var expectedBody = "NoProducesContentOnClassController"; + + // Act + var result = await client.GetAsync("http://localhost/NoProducesContentOnClass/ReturnClassName"); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + Assert.Equal(expectedBody, body); + } + + [Fact] + public async Task ProducesContentAttribute_OnDerivedClassAndAction_OverridesTheValueOnBaseClass() + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + var expectedContentType = "application/custom_ProducesContentOnClassController_Action;charset=utf-8"; + var expectedBody = "ProducesContentOnClassController"; + + // Act + var result = await client.GetAsync("http://localhost/ProducesContentOnClass/ReturnClassNameContentTypeOnDerivedAction"); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + Assert.Equal(expectedBody, body); + } + + + [InlineData("ReturnTaskOfString")] + [InlineData("ReturnTaskOfObject_StringValue")] + [InlineData("ReturnString")] + [InlineData("ReturnObject_StringValue")] + [InlineData("ReturnString_NullValue")] + public async Task TextPlainFormatter_ReturnsTextPlainContentType(string actionName) + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + var expectedContentType = "text/plain;charset=utf-8"; + var expectedBody = actionName; + + // Act + var result = await client.GetAsync("http://localhost/TextPlain/" + actionName); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + Assert.Equal(expectedBody, body); + } + + [InlineData("ReturnTaskOfObject_ObjectValue")] + [InlineData("ReturnObject_ObjectValue")] + [InlineData("ReturnObject_NullValue")] + public async Task TextPlainFormatter_DoesNotSelectTextPlainFormatterForNonStringValue(string actionName) + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + var expectedContentType = "application/json;charset=utf-8"; + var expectedBody = actionName; + + // Act + var result = await client.GetAsync("http://localhost/TextPlain/" + actionName); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + } + + [InlineData("ReturnString_NullValue")] + public async Task TextPlainFormatter_DoesNotWriteNullValue(string actionName) + { + // Arrange + var server = TestServer.Create(_provider, _app); + var client = server.Handler; + var expectedContentType = "text/plain;charset=utf-8"; + string expectedBody = null; + + // Act + var result = await client.GetAsync("http://localhost/TextPlain/" + actionName); + + // Assert + Assert.Equal(expectedContentType, result.HttpContext.Response.ContentType); + var body = await result.HttpContext.Response.ReadBodyAsStringAsync(); + Assert.Equal(expectedBody, body); + } + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj b/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj index c60a012307..0002e0cf6e 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/Microsoft.AspNet.Mvc.FunctionalTests.kproj @@ -31,6 +31,7 @@ + diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json index e9a88b59dd..90a5f6a8b2 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/project.json @@ -6,6 +6,7 @@ "ActivatorWebSite": "", "BasicWebSite": "", "CompositeViewEngine": "", + "ConnegWebsite": "", "FormatterWebSite": "", "InlineConstraintsWebSite": "", "Microsoft.AspNet.TestHost": "1.0.0-*", diff --git a/test/WebSites/ConnegWebSite/ConnegWebsite.kproj b/test/WebSites/ConnegWebSite/ConnegWebsite.kproj new file mode 100644 index 0000000000..dd3b32c0d0 --- /dev/null +++ b/test/WebSites/ConnegWebSite/ConnegWebsite.kproj @@ -0,0 +1,41 @@ + + + + 12.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + c6e5affa-890a-448f-8de3-878b1d3c9fc7 + Library + + + ConsoleDebugger + + + WebDebugger + + + + + + + 2.0 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/WebSites/ConnegWebSite/ContentType.cs b/test/WebSites/ConnegWebSite/ContentType.cs new file mode 100644 index 0000000000..d152773bed --- /dev/null +++ b/test/WebSites/ConnegWebSite/ContentType.cs @@ -0,0 +1,45 @@ +// 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.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Mvc.HeaderValueAbstractions; + +namespace ConnegWebsite +{ + public class CustomFormatter : OutputFormatter + { + public string ContentType { get; private set; } + + public CustomFormatter(string contentType) + { + ContentType = contentType; + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse(contentType)); + SupportedEncodings.Add(Encoding.GetEncoding("utf-8")); + } + + public override bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType) + { + if (base.CanWriteResult(context, contentType)) + { + var actionReturnString = context.Object as string; + if (actionReturnString != null) + { + return true; + } + } + return false; + } + + public override async Task WriteResponseBodyAsync(OutputFormatterContext context) + { + var response = context.ActionContext.HttpContext.Response; + response.ContentType = ContentType + ";charset=utf-8"; + await response.WriteAsync(context.Object as string); + } + } +} \ No newline at end of file diff --git a/test/WebSites/ConnegWebSite/Controllers/HomeController.cs b/test/WebSites/ConnegWebSite/Controllers/HomeController.cs new file mode 100644 index 0000000000..ec92463c3b --- /dev/null +++ b/test/WebSites/ConnegWebSite/Controllers/HomeController.cs @@ -0,0 +1,15 @@ +// 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 Microsoft.AspNet.Mvc; + +namespace ConnegWebsite +{ + public class HomeController : Controller + { + public IActionResult Index() + { + return new JsonResult("Index Method"); + } + } +} \ No newline at end of file diff --git a/test/WebSites/ConnegWebSite/Controllers/NoProducesContentOnClassController.cs b/test/WebSites/ConnegWebSite/Controllers/NoProducesContentOnClassController.cs new file mode 100644 index 0000000000..570a63a2b1 --- /dev/null +++ b/test/WebSites/ConnegWebSite/Controllers/NoProducesContentOnClassController.cs @@ -0,0 +1,28 @@ +// 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 Microsoft.AspNet.Mvc; + +namespace ConnegWebsite +{ + public class NoProducesContentOnClassController : ProducesContentBaseController + { + public override void OnActionExecuted(ActionExecutedContext context) + { + var result = context.Result as ObjectResult; + if (result != null) + { + result.Formatters.Add(new CustomFormatter("application/custom_NoProducesContentOnClassController_Action")); + } + + base.OnActionExecuted(context); + } + + [Produces("application/custom_NoProducesContentOnClassController_Action")] + public override string ReturnClassName() + { + // should be written using the formatter provided by this action and not the base action. + return "NoProducesContentOnClassController"; + } + } +} \ No newline at end of file diff --git a/test/WebSites/ConnegWebSite/Controllers/NormalController.cs b/test/WebSites/ConnegWebSite/Controllers/NormalController.cs new file mode 100644 index 0000000000..04e6b589dd --- /dev/null +++ b/test/WebSites/ConnegWebSite/Controllers/NormalController.cs @@ -0,0 +1,64 @@ +// 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 Microsoft.AspNet.Mvc; + +namespace ConnegWebsite +{ + public class NormalController : Controller + { + public override void OnActionExecuted(ActionExecutedContext context) + { + var result = context.Result as ObjectResult; + if (result != null) + { + result.Formatters.Add(new PlainTextFormatter()); + result.Formatters.Add(new CustomFormatter("application/custom")); + result.Formatters.Add(new JsonOutputFormatter(JsonOutputFormatter.CreateDefaultSettings(), + indent: true)); + } + + base.OnActionExecuted(context); + } + + public string ReturnClassName() + { + return "NormalController"; + } + + public User ReturnUser() + { + return CreateUser(); + } + + [Produces("application/NoFormatter")] + public User ReturnUser_NoMatchingFormatter() + { + return CreateUser(); + } + + [Produces("application/custom", "application/json", "text/json")] + public User MultipleAllowedContentTypes() + { + return CreateUser(); + } + + [Produces("application/custom")] + public string WriteUserUsingCustomFormat() + { + return "Written using custom format."; + } + + [NonAction] + public User CreateUser() + { + User user = new User() + { + Name = "My name", + Address = "My address", + }; + + return user; + } + } +} \ No newline at end of file diff --git a/test/WebSites/ConnegWebSite/Controllers/ProducesContentBaseController.cs b/test/WebSites/ConnegWebSite/Controllers/ProducesContentBaseController.cs new file mode 100644 index 0000000000..f6cfa2db11 --- /dev/null +++ b/test/WebSites/ConnegWebSite/Controllers/ProducesContentBaseController.cs @@ -0,0 +1,42 @@ +// 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 Microsoft.AspNet.Mvc; + +namespace ConnegWebsite +{ + [Produces("application/custom_ProducesContentBaseController")] + public class ProducesContentBaseController : Controller + { + public override void OnActionExecuted(ActionExecutedContext context) + { + var result = context.Result as ObjectResult; + if(result != null) + { + result.Formatters.Add(new PlainTextFormatter()); + result.Formatters.Add(new CustomFormatter("application/custom_ProducesContentBaseController")); + result.Formatters.Add(new CustomFormatter("application/custom_ProducesContentBaseController_Action")); + } + + base.OnActionExecuted(context); + } + + [Produces("application/custom_ProducesContentBaseController_Action")] + public virtual string ReturnClassName() + { + // Should be written using the action's content type. Overriding the one at the class. + return "ProducesContentBaseController"; + } + + public virtual string ReturnClassNameWithNoContentTypeOnAction() + { + // Should be written using the action's content type. Overriding the one at the class. + return "ProducesContentBaseController"; + } + + public virtual string ReturnClassNameContentTypeOnDerivedAction() + { + return "ProducesContentBaseController"; + } + } +} \ No newline at end of file diff --git a/test/WebSites/ConnegWebSite/Controllers/ProducesContentOnClassController.cs b/test/WebSites/ConnegWebSite/Controllers/ProducesContentOnClassController.cs new file mode 100644 index 0000000000..a1a864f990 --- /dev/null +++ b/test/WebSites/ConnegWebSite/Controllers/ProducesContentOnClassController.cs @@ -0,0 +1,44 @@ +// 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 Microsoft.AspNet.Mvc; + +namespace ConnegWebsite +{ + [Produces("application/custom_ProducesContentOnClassController")] + public class ProducesContentOnClassController : ProducesContentBaseController + { + public override void OnActionExecuted(ActionExecutedContext context) + { + var result = context.Result as ObjectResult; + if (result != null) + { + result.Formatters.Add(new CustomFormatter("application/custom_ProducesContentOnClassController")); + result.Formatters.Add( + new CustomFormatter("application/custom_ProducesContentOnClassController_Action")); + } + + base.OnActionExecuted(context); + } + + // No Content type defined by the derived class action. + public override string ReturnClassName() + { + // should be written using the content defined at base class's action. + return "ProducesContentOnClassController"; + } + + public override string ReturnClassNameWithNoContentTypeOnAction() + { + // should be written using the content defined at derived class's class. + return "ProducesContentOnClassController"; + } + + [Produces("application/custom_ProducesContentOnClassController_Action")] + public override string ReturnClassNameContentTypeOnDerivedAction() + { + // should be written using the content defined at derived class's class. + return "ProducesContentOnClassController"; + } + } +} \ No newline at end of file diff --git a/test/WebSites/ConnegWebSite/Controllers/TextPlainController.cs b/test/WebSites/ConnegWebSite/Controllers/TextPlainController.cs new file mode 100644 index 0000000000..a3d17b7d70 --- /dev/null +++ b/test/WebSites/ConnegWebSite/Controllers/TextPlainController.cs @@ -0,0 +1,51 @@ +// 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.Threading.Tasks; +using Microsoft.AspNet.Mvc; + +namespace ConnegWebsite +{ + public class TextPlainController : Controller + { + public Task ReturnTaskOfString() + { + return Task.FromResult("ReturnTaskOfString"); + } + + public Task ReturnTaskOfObject_StringValue() + { + return Task.FromResult("ReturnTaskOfObject_StringValue"); + } + + public Task ReturnTaskOfObject_ObjectValue() + { + return Task.FromResult(new object()); + } + + public string ReturnString() + { + return "ReturnString"; + } + + public object ReturnObject_StringValue() + { + return ""; + } + + public object ReturnObject_ObjectValue() + { + return new object(); + } + + public string ReturnString_NullValue() + { + return null; + } + + public object ReturnObject_NullValue() + { + return null; + } + } +} \ No newline at end of file diff --git a/test/WebSites/ConnegWebSite/Models/User.cs b/test/WebSites/ConnegWebSite/Models/User.cs new file mode 100644 index 0000000000..863985f8e3 --- /dev/null +++ b/test/WebSites/ConnegWebSite/Models/User.cs @@ -0,0 +1,17 @@ +// 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.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace ConnegWebsite +{ + [DisplayColumn("Name")] + public class User + { + [Required] + [MinLength(4)] + public string Name { get; set; } + public string Address { get; set; } + } +} \ No newline at end of file diff --git a/test/WebSites/ConnegWebSite/PlainTextFormatter.cs b/test/WebSites/ConnegWebSite/PlainTextFormatter.cs new file mode 100644 index 0000000000..4fc540074f --- /dev/null +++ b/test/WebSites/ConnegWebSite/PlainTextFormatter.cs @@ -0,0 +1,43 @@ +// 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.Text; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Mvc.HeaderValueAbstractions; + +namespace ConnegWebsite +{ + public class PlainTextFormatter : OutputFormatter + { + public PlainTextFormatter() + { + SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("text/plain")); + SupportedEncodings.Add(Encoding.GetEncoding("utf-8")); + } + + public override bool CanWriteResult(OutputFormatterContext context, MediaTypeHeaderValue contentType) + { + if (base.CanWriteResult(context, contentType)) + { + var actionReturnString = context.Object as string; + if (actionReturnString != null) + { + return true; + } + } + + return false; + } + + public override async Task WriteResponseBodyAsync(OutputFormatterContext context) + { + var response = context.ActionContext.HttpContext.Response; + response.ContentType = "text/plain;charset=utf-8"; + await response.WriteAsync(context.Object as string); + } + } +} \ No newline at end of file diff --git a/test/WebSites/ConnegWebSite/Startup.cs b/test/WebSites/ConnegWebSite/Startup.cs new file mode 100644 index 0000000000..943c84e5d1 --- /dev/null +++ b/test/WebSites/ConnegWebSite/Startup.cs @@ -0,0 +1,31 @@ +// 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 Microsoft.AspNet.Builder; +using Microsoft.AspNet.Routing; +using Microsoft.Framework.DependencyInjection; + +namespace ConnegWebsite +{ + public class Startup + { + public void Configure(IBuilder app) + { + var configuration = app.GetTestConfiguration(); + + // Set up application services + app.UseServices(services => + { + // Add MVC services to the services container + services.AddMvc(configuration); + }); + + // Add MVC to the request pipeline + app.UseMvc(routes => + { + routes.MapRoute("ActionAsMethod", "{controller}/{action}", + defaults: new { controller = "Home", action = "Index" }); + }); + } + } +} diff --git a/test/WebSites/ConnegWebSite/project.json b/test/WebSites/ConnegWebSite/project.json new file mode 100644 index 0000000000..a6de3a4d44 --- /dev/null +++ b/test/WebSites/ConnegWebSite/project.json @@ -0,0 +1,11 @@ +{ + "dependencies": { + "Microsoft.AspNet.Mvc": "", + "Microsoft.AspNet.Server.IIS": "1.0.0-*", + "Microsoft.AspNet.Mvc.TestConfiguration": "" + }, + "frameworks": { + "net45": { }, + "k10": { } + } +}