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
This commit is contained in:
harshgMSFT 2014-07-22 16:26:27 -07:00
parent 099adda3d7
commit 6ee034e64f
30 changed files with 1089 additions and 26 deletions

17
Mvc.sln
View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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
{
/// <summary>
/// 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 <see cref="ObjectResult"/>.
/// </summary>
[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<MediaTypeHeaderValue> 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<MediaTypeHeaderValue> GetContentTypes(string firstArg, string[] args)
{
var contentTypes = new List<MediaTypeHeaderValue>();
contentTypes.Add(MediaTypeHeaderValue.Parse(firstArg));
foreach (var item in args)
{
var contentType = MediaTypeHeaderValue.Parse(item);
contentTypes.Add(contentType);
}
return contentTypes;
}
}
}

View File

@ -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(

View File

@ -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
{
/// <summary>
/// Provides a return type and a set of possible content types returned by a successful execution of the action.
/// </summary>
public interface IProducesMetadataProvider
{
/// <summary>
/// Optimistic return type of the action.
/// </summary>
Type Type { get; set; }
/// <summary>
/// A collection of allowed content types which can be produced by the action.
/// </summary>
IList<MediaTypeHeaderValue> ContentTypes { get; set; }
}
}

View File

@ -35,28 +35,30 @@
<Compile Include="Logging\LoggerExtensions.cs" />
<Compile Include="Logging\MvcRouteHandlerRouteAsyncValues.cs" />
<Compile Include="Logging\StringBuilderHelpers.cs" />
<Compile Include="OptionDescriptors\DefaultModelBinderProvider.cs" />
<Compile Include="OptionDescriptors\DefaultValueProviderFactoryProvider.cs" />
<Compile Include="OptionDescriptors\DefaultViewEngineProvider.cs" />
<Compile Include="OptionDescriptors\ModelBinderDescriptor.cs" />
<Compile Include="OptionDescriptors\OutputFormatterDescriptorExtensions.cs" />
<Compile Include="OptionDescriptors\ModelBinderDescriptorExtensions.cs" />
<Compile Include="OptionDescriptors\OptionDescriptorBasedProvider.cs" />
<Compile Include="OptionDescriptors\OptionDescriptor.cs" />
<Compile Include="OptionDescriptors\OutputFormatterDescriptor.cs" />
<Compile Include="OptionDescriptors\ValueProviderFactoryDescriptor.cs" />
<Compile Include="OptionDescriptors\ViewEngineDescriptor.cs" />
<Compile Include="OptionDescriptors\ValueProviderFactoryDescriptorExtensions.cs" />
<Compile Include="OptionDescriptors\ViewEngineDescriptorExtensions.cs" />
<Compile Include="Filters\ProducesAttribute.cs" />
<Compile Include="Formatters\DefaultOutputFormattersProvider.cs" />
<Compile Include="Formatters\IOutputFormatter.cs" />
<Compile Include="Formatters\StringWithQualityHeaderValueComparer.cs" />
<Compile Include="IProducesMetadataProvider.cs" />
<Compile Include="Formatters\IOutputFormattersProvider.cs" />
<Compile Include="Formatters\OutputFormatterContext.cs" />
<Compile Include="Formatters\HeaderParsingHelpers.cs" />
<Compile Include="Formatters\JsonOutputFormatter.cs" />
<Compile Include="Formatters\MediaTypeWithQualityHeaderValueComparer.cs" />
<Compile Include="Formatters\OutputFormatter.cs" />
<Compile Include="OptionDescriptors\DefaultModelBinderProvider.cs" />
<Compile Include="OptionDescriptors\DefaultValueProviderFactoryProvider.cs" />
<Compile Include="OptionDescriptors\DefaultViewEngineProvider.cs" />
<Compile Include="OptionDescriptors\ModelBinderDescriptor.cs" />
<Compile Include="OptionDescriptors\ModelBinderDescriptorExtensions.cs" />
<Compile Include="OptionDescriptors\OptionDescriptor.cs" />
<Compile Include="OptionDescriptors\OptionDescriptorBasedProvider.cs" />
<Compile Include="OptionDescriptors\OutputFormatterDescriptor.cs" />
<Compile Include="OptionDescriptors\OutputFormatterDescriptorExtensions.cs" />
<Compile Include="OptionDescriptors\ValueProviderFactoryDescriptor.cs" />
<Compile Include="OptionDescriptors\ValueProviderFactoryDescriptorExtensions.cs" />
<Compile Include="OptionDescriptors\ViewEngineDescriptor.cs" />
<Compile Include="OptionDescriptors\ViewEngineDescriptorExtensions.cs" />
<Compile Include="ParameterBinding\ModelBindingHelper.cs" />
<Compile Include="ActionInvokerFactory.cs" />
<Compile Include="ActionInvokerProviderContext.cs" />

View File

@ -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<string, string>(StringComparer.OrdinalIgnoreCase),
};
return mediaTypeHeader;
return true;
}
protected static Dictionary<string, string> ParseParameters(string inputString)

View File

@ -21,10 +21,16 @@
<Compile Include="MediaTypeHeaderValue.cs" />
<Compile Include="MediaTypeHeaderValueRange.cs" />
<Compile Include="MediaTypeWithQualityHeaderValue.cs" />
<Compile Include="Properties\Resources.Designer.cs" />
<Compile Include="StringWithQualityHeaderValue.cs" />
</ItemGroup>
<ItemGroup>
<Content Include="project.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -0,0 +1,46 @@
// <auto-generated />
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);
/// <summary>
/// Invalid Argument. Content type '{0}' could not be parsed.
/// </summary>
internal static string InvalidContentType
{
get { return GetString("InvalidContentType"); }
}
/// <summary>
/// Invalid Argument. Content type '{0}' could not be parsed.
/// </summary>
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;
}
}
}

View File

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="InvalidContentType" xml:space="preserve">
<value>Invalid Argument. Content type '{0}' could not be parsed.</value>
</data>
</root>

View File

@ -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"
}

View File

@ -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<ArgumentException>(
() => 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());
}
}
}

View File

@ -31,6 +31,8 @@
<Compile Include="ActionResults\RedirectToActionResultTest.cs" />
<Compile Include="ActionResults\RedirectToRouteResultTest.cs" />
<Compile Include="AntiXsrf\AntiForgeryOptionsTests.cs" />
<Compile Include="Filters\ProducesAttributeTests.cs" />
<Compile Include="Formatters\OutputFormatterTests.cs" />
<Compile Include="Formatters\TextPlainFormatterTests.cs" />
<Compile Include="Logging\BeginScopeContext.cs" />
<Compile Include="Logging\TestLoggerFactory.cs" />
@ -40,6 +42,7 @@
<Compile Include="Logging\NullLoggerFactory.cs" />
<Compile Include="Logging\TestSink.cs" />
<Compile Include="Logging\TestLogger.cs" />
<Compile Include="MediaTypeWithQualityHeaderValueTests.cs" />
<Compile Include="MvcRouteHandlerTests.cs" />
<Compile Include="OptionDescriptors\DefaultModelBindersProviderTest.cs" />
<Compile Include="OptionDescriptors\DefaultValueProviderFactoryProviderTest.cs" />
@ -48,12 +51,10 @@
<Compile Include="OptionDescriptors\ModelBinderDescriptorTest.cs" />
<Compile Include="OptionDescriptors\OutputFormatterDescriptorExtensionTest.cs" />
<Compile Include="OptionDescriptors\OutputFormatterDescriptorTest.cs" />
<Compile Include="OptionDescriptors\ValueProviderFactoryDescriptorExtensionsTest.cs" />
<Compile Include="OptionDescriptors\ValueProviderFactoryDescriptorTest.cs" />
<Compile Include="OptionDescriptors\ViewEngineDescriptorTest.cs" />
<Compile Include="OptionDescriptors\ValueProviderFactoryDescriptorExtensionsTest.cs" />
<Compile Include="OptionDescriptors\ViewEngineDscriptorExtensionsTest.cs" />
<Compile Include="Formatters\OutputFormatterTests.cs" />
<Compile Include="MediaTypeWithQualityHeaderValueTests.cs" />
<Compile Include="ParameterBinding\ModelBindingHelperTest.cs" />
<Compile Include="AntiXsrf\AntiForgeryTokenSerializerTest.cs" />
<Compile Include="AntiXsrf\ITokenProvider.cs" />
@ -92,8 +93,8 @@
<Compile Include="Rendering\DefaultDisplayTemplatesTests.cs" />
<Compile Include="Rendering\DefaultEditorTemplatesTests.cs" />
<Compile Include="Rendering\DefaultTemplatesUtilities.cs" />
<Compile Include="Rendering\HtmlHelperDisplayNameExtensionsTest.cs" />
<Compile Include="Rendering\HtmlAttributePropertyHelperTest.cs" />
<Compile Include="Rendering\HtmlHelperDisplayNameExtensionsTest.cs" />
<Compile Include="Rendering\HtmlHelperDisplayTextTest.cs" />
<Compile Include="Rendering\HtmlHelperLabelExtensionsTest.cs" />
<Compile Include="Rendering\HtmlHelperNameExtensionsTest.cs" />
@ -103,10 +104,10 @@
<Compile Include="KnownRouteValueConstraintTests.cs" />
<Compile Include="Routing\AttributeRoutePrecedenceTests.cs" />
<Compile Include="Routing\AttributeRouteTemplateTests.cs" />
<Compile Include="Routing\AttributeRouteTests.cs" />
<Compile Include="Routing\AttributeRoutingTest.cs" />
<Compile Include="StaticActionDiscoveryConventions.cs" />
<Compile Include="StaticControllerAssemblyProvider.cs" />
<Compile Include="Routing\AttributeRouteTests.cs" />
<Compile Include="TestController.cs" />
<Compile Include="TypeHelperTest.cs" />
<Compile Include="UrlHelperTest.cs" />

View File

@ -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" : "",

View File

@ -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<IBuilder> _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);
}
}
}

View File

@ -31,6 +31,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="BasicTests.cs" />
<Compile Include="ConnegTests.cs" />
<Compile Include="ViewEngineTests.cs" />
<Compile Include="ActivatorTests.cs" />
<Compile Include="ValueProviderTests.cs" />

View File

@ -6,6 +6,7 @@
"ActivatorWebSite": "",
"BasicWebSite": "",
"CompositeViewEngine": "",
"ConnegWebsite": "",
"FormatterWebSite": "",
"InlineConstraintsWebSite": "",
"Microsoft.AspNet.TestHost": "1.0.0-*",

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="__ToolsVersion__" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">12.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
<PropertyGroup Label="Globals">
<ProjectGuid>c6e5affa-890a-448f-8de3-878b1d3c9fc7</ProjectGuid>
<OutputType>Library</OutputType>
</PropertyGroup>
<PropertyGroup Condition="$(OutputType) == 'Console'">
<DebuggerFlavor>ConsoleDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="$(OutputType) == 'Web'">
<DebuggerFlavor>WebDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
</PropertyGroup>
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<ItemGroup>
<Content Include="Project.json" />
</ItemGroup>
<ItemGroup>
<Compile Include="Controllers\NormalController.cs" />
<Compile Include="Controllers\NoProducesContentOnClassController.cs" />
<Compile Include="Controllers\ProducesContentBaseController.cs" />
<Compile Include="Controllers\ProducesContentOnClassController.cs" />
<Compile Include="Controllers\HomeController.cs" />
<Compile Include="Controllers\TextPlainController.cs" />
<Compile Include="Models\User.cs" />
<Compile Include="ContentType.cs" />
<Compile Include="PlainTextFormatter.cs" />
<Compile Include="Startup.cs" />
</ItemGroup>
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
</Project>

View File

@ -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);
}
}
}

View File

@ -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");
}
}
}

View File

@ -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";
}
}
}

View File

@ -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;
}
}
}

View File

@ -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";
}
}
}

View File

@ -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";
}
}
}

View File

@ -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<string> ReturnTaskOfString()
{
return Task.FromResult<string>("ReturnTaskOfString");
}
public Task<object> ReturnTaskOfObject_StringValue()
{
return Task.FromResult<object>("ReturnTaskOfObject_StringValue");
}
public Task<object> ReturnTaskOfObject_ObjectValue()
{
return Task.FromResult<object>(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;
}
}
}

View File

@ -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; }
}
}

View File

@ -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);
}
}
}

View File

@ -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" });
});
}
}
}

View File

@ -0,0 +1,11 @@
{
"dependencies": {
"Microsoft.AspNet.Mvc": "",
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
"Microsoft.AspNet.Mvc.TestConfiguration": ""
},
"frameworks": {
"net45": { },
"k10": { }
}
}