Adding functional tests and attribute route tests.
Incorporating PR coments.
This commit is contained in:
parent
d91b7776b3
commit
c8b911b596
15
Mvc.sln
15
Mvc.sln
|
|
@ -130,6 +130,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "ValidationWebSite", "test\W
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Mvc.Xml.Test", "test\Microsoft.AspNet.Mvc.Xml.Test\Microsoft.AspNet.Mvc.Xml.Test.kproj", "{22019146-BDFA-442E-8C8E-345FB9644578}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FormatFilterWebSite", "test\WebSites\FormatFilterWebSite\FormatFilterWebSite.kproj", "{AC9BE567-540E-4C70-90C2-AAF021307A80}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -740,6 +742,18 @@ Global
|
|||
{22019146-BDFA-442E-8C8E-345FB9644578}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{22019146-BDFA-442E-8C8E-345FB9644578}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{22019146-BDFA-442E-8C8E-345FB9644578}.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
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80}.Release|x86.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -803,5 +817,6 @@ Global
|
|||
{C3123A70-41C4-4122-AD1C-D35DF8958DD7} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{87AB84B2-22C1-43C6-BB8A-1D327B446FB0} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{22019146-BDFA-442E-8C8E-345FB9644578} = {3BA657BF-28B1-42DA-B5B0-1C4601FCF7B1}
|
||||
{AC9BE567-540E-4C70-90C2-AAF021307A80} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
// 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 MvcSample.Web.Controllers
|
||||
{
|
||||
[FormatFilter]
|
||||
public class FormatFilterController : Controller
|
||||
{
|
||||
public Product GetProduct(int id)
|
||||
{
|
||||
return new Product() { SampleInt = id };
|
||||
}
|
||||
|
||||
[Produces("application/custom", "application/json", "text/json")]
|
||||
public Product ProducesMethod(int id)
|
||||
{
|
||||
return new Product() { SampleInt = id }; ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
using System;
|
||||
|
||||
namespace MvcSample.Web
|
||||
{
|
||||
public class Product
|
||||
{
|
||||
public int SampleInt { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,6 @@ using Microsoft.Framework.ConfigurationModel;
|
|||
using Microsoft.Framework.DependencyInjection;
|
||||
using MvcSample.Web.Filters;
|
||||
using MvcSample.Web.Services;
|
||||
using Microsoft.AspNet.Mvc.Core.Filters;
|
||||
|
||||
#if ASPNET50
|
||||
using Autofac;
|
||||
|
|
@ -64,13 +63,9 @@ namespace MvcSample.Web
|
|||
services.Configure<MvcOptions>(options =>
|
||||
{
|
||||
options.Filters.Add(typeof(PassThroughAttribute), order: 17);
|
||||
<<<<<<< HEAD
|
||||
|
||||
options.AddXmlDataContractSerializerFormatter();
|
||||
=======
|
||||
var formatFilter = new FormatFilter();
|
||||
var formatFilter = new FormatFilterAttribute();
|
||||
options.Filters.Add(formatFilter);
|
||||
>>>>>>> This is MVC part of feature URL Extensions. It does following:
|
||||
});
|
||||
services.Configure<RazorViewEngineOptions>(options =>
|
||||
{
|
||||
|
|
@ -113,7 +108,7 @@ namespace MvcSample.Web
|
|||
options.Filters.Add(typeof(PassThroughAttribute), order: 17);
|
||||
options.AddXmlDataContractSerializerFormatter();
|
||||
|
||||
var formatFilter = new FormatFilter();
|
||||
var formatFilter = new FormatFilterAttribute();
|
||||
options.Filters.Add(formatFilter);
|
||||
});
|
||||
});
|
||||
|
|
@ -121,10 +116,8 @@ namespace MvcSample.Web
|
|||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute("FormatRoute", "{controller}/{action}/{id}.{format?}");
|
||||
routes.MapRoute("areaRoute", "{area:exists}/{controller}/{action}");
|
||||
|
||||
routes.MapRoute("formatRoute", "{controller}/{action}/{format}");
|
||||
|
||||
routes.MapRoute(
|
||||
"controllerActionRoute",
|
||||
"{controller}/{action}",
|
||||
|
|
|
|||
|
|
@ -1,90 +0,0 @@
|
|||
using System;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using System.Threading.Tasks;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Core.Filters
|
||||
{
|
||||
public class FormatFilter : IFormatFilter
|
||||
{
|
||||
public void OnResourceExecuting([NotNull] ResourceExecutingContext context)
|
||||
{
|
||||
var options = (IOptions<MvcOptions>)context.HttpContext.RequestServices.GetService(
|
||||
typeof(IOptions<MvcOptions>));
|
||||
string format = null;
|
||||
|
||||
if (context.RouteData.Values.ContainsKey("format"))
|
||||
{
|
||||
format = context.RouteData.Values["format"].ToString();
|
||||
}
|
||||
else if(context.HttpContext.Request.Query.ContainsKey("format"))
|
||||
{
|
||||
format = context.HttpContext.Request.Query.Get("format").ToString();
|
||||
}
|
||||
|
||||
if (format != null)
|
||||
{
|
||||
var contentType = options.Options.OutputFormatterOptions.GetContentTypeForFormat(format);
|
||||
if (contentType == null)
|
||||
{
|
||||
// no contentType exists for the foramt, return 404
|
||||
context.Result = new HttpNotFoundResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (context.Filters.Any(f => f is ProducesAttribute))
|
||||
{
|
||||
var produces = context.Filters.First(f => f is ProducesAttribute) as ProducesAttribute;
|
||||
if(!produces.ContentTypes.Contains(contentType))
|
||||
{
|
||||
context.Result = new HttpNotFoundResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnResourceExecuted([NotNull] ResourceExecutedContext context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnResultExecuting([NotNull]ResultExecutingContext context)
|
||||
{
|
||||
var options = (IOptions<MvcOptions>)context.HttpContext.RequestServices.GetService(
|
||||
typeof(IOptions<MvcOptions>));
|
||||
string format = null;
|
||||
|
||||
if (context.RouteData.Values.ContainsKey("format"))
|
||||
{
|
||||
format = context.RouteData.Values["format"].ToString();
|
||||
}
|
||||
else if (context.HttpContext.Request.Query.ContainsKey("format"))
|
||||
{
|
||||
format = context.HttpContext.Request.Query.Get("format").ToString();
|
||||
}
|
||||
if (format != null)
|
||||
{
|
||||
var contentType = options.Options.OutputFormatterOptions.GetContentTypeForFormat(format);
|
||||
if (contentType != null)
|
||||
{
|
||||
var objectResult = context.Result as ObjectResult;
|
||||
if (objectResult != null)
|
||||
{
|
||||
objectResult.ContentTypes.Clear();
|
||||
objectResult.ContentTypes.Add(contentType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Result = new HttpStatusCodeResult(404);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnResultExecuted([NotNull]ResultExecutedContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
// 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.Diagnostics;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Mvc.Description;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// This will look at the format parameter if present in the route data or query data and
|
||||
/// sets the content type in ObjectResult corresponding to the format value.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||
public class FormatFilterAttribute : Attribute, IFormatFilter, IResourceFilter, IResultFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// As a resourceFilter, this filter looks at the request and rejects it
|
||||
/// before going ahead if
|
||||
/// 1. The Format in the request doesnt match any format in the map.
|
||||
/// 2. If there is a conflicting producesFilter.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
public void OnResourceExecuting([NotNull] ResourceExecutingContext context)
|
||||
{
|
||||
var format = GetFormat(context);
|
||||
|
||||
if (format != null && !string.IsNullOrEmpty(format.ToString()))
|
||||
{
|
||||
var formatContentType = GetContentType(format, context);
|
||||
if (formatContentType == null)
|
||||
{
|
||||
// no contentType exists for the format, return 404
|
||||
context.Result = new HttpNotFoundResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
var responseTypeFilters = context.Filters.OfType<IApiResponseMetadataProvider>();
|
||||
if (responseTypeFilters.Count() != 0)
|
||||
{
|
||||
var contentTypes = new List<MediaTypeHeaderValue>();
|
||||
foreach (var filter in responseTypeFilters)
|
||||
{
|
||||
filter.SetContentTypes(contentTypes);
|
||||
}
|
||||
|
||||
if (!contentTypes.Any(c => c.IsSubsetOf(formatContentType)))
|
||||
{
|
||||
context.Result = new HttpNotFoundResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnResourceExecuted([NotNull] ResourceExecutedContext context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnResultExecuting([NotNull] ResultExecutingContext context)
|
||||
{
|
||||
var format = GetFormat(context);
|
||||
if (format != null)
|
||||
{
|
||||
var contentType = GetContentType(format, context);
|
||||
Debug.Assert(contentType != null);
|
||||
|
||||
var objectResult = context.Result as ObjectResult;
|
||||
if (objectResult != null)
|
||||
{
|
||||
objectResult.ContentTypes.Clear();
|
||||
objectResult.ContentTypes.Add(contentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnResultExecuted([NotNull] ResultExecutedContext context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public MediaTypeHeaderValue GetContentTypeForCurrentRequest(FilterContext context)
|
||||
{
|
||||
var format = GetFormat(context);
|
||||
if (format != null && !string.IsNullOrEmpty(format.ToString()))
|
||||
{
|
||||
return GetContentType(format, context);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private object GetFormat(FilterContext context)
|
||||
{
|
||||
object format = null;
|
||||
|
||||
if (!context.RouteData.Values.TryGetValue("format", out format))
|
||||
{
|
||||
if (context.HttpContext.Request.Query.ContainsKey("format"))
|
||||
{
|
||||
format = context.HttpContext.Request.Query.Get("format");
|
||||
}
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
private MediaTypeHeaderValue GetContentType(object format, FilterContext context)
|
||||
{
|
||||
Debug.Assert(format != null);
|
||||
var options = context.HttpContext.RequestServices.GetService<IOptions<MvcOptions>>();
|
||||
var contentType = options.Options.FormatterMappings.GetContentTypeForFormat(format.ToString());
|
||||
return contentType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,16 @@
|
|||
using System;
|
||||
// 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.
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Core.Filters
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public interface IFormatFilter : IResourceFilter, IResultFilter
|
||||
/// <summary>
|
||||
/// Implement this interface if you want to have your own implementation of FormatFilter
|
||||
/// </summary>
|
||||
public interface IFormatFilter : IFilter
|
||||
{
|
||||
|
||||
MediaTypeHeaderValue GetContentTypeForCurrentRequest(FilterContext context);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,6 @@ using Microsoft.AspNet.Mvc.Core;
|
|||
using Microsoft.AspNet.Mvc.Description;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -37,7 +36,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
// Check if FormatFilter has already set the content type
|
||||
// If it has, dont override it
|
||||
if (objectResult.ContentTypes.Count == 0)
|
||||
var formatFilter = context.Filters.OfType<IFormatFilter>().LastOrDefault();
|
||||
if (formatFilter == null || formatFilter.GetContentTypeForCurrentRequest(context) == null)
|
||||
{
|
||||
SetContentTypes(objectResult.ContentTypes);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
// 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.Net.Http.Headers;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// These options are used to specify mapping between the Url Format and corresponding ContentType.
|
||||
/// </summary>
|
||||
public class FormatterMappings
|
||||
{
|
||||
private readonly Dictionary<string, MediaTypeHeaderValue> _map =
|
||||
new Dictionary<string, MediaTypeHeaderValue>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public void SetFormatMapping([NotNull] string format, [NotNull] MediaTypeHeaderValue contentType)
|
||||
{
|
||||
if (contentType == null)
|
||||
{
|
||||
throw new ArgumentException((Resources.ArgumentCannotBeNullOrEmpty), "contentType");
|
||||
}
|
||||
|
||||
format = RemovePeriodIfPresent(format);
|
||||
_map[format] = contentType;
|
||||
}
|
||||
|
||||
public MediaTypeHeaderValue GetContentTypeForFormat(string format)
|
||||
{
|
||||
format = RemovePeriodIfPresent(format);
|
||||
MediaTypeHeaderValue value = null;
|
||||
_map.TryGetValue(format, out value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private string RemovePeriodIfPresent(string format)
|
||||
{
|
||||
if (string.IsNullOrEmpty(format))
|
||||
{
|
||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "format");
|
||||
}
|
||||
if (format.StartsWith("."))
|
||||
{
|
||||
format = format.Substring(1);
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,7 +18,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
{
|
||||
private AntiForgeryOptions _antiForgeryOptions = new AntiForgeryOptions();
|
||||
private int _maxModelStateErrors = ModelStateDictionary.DefaultMaxAllowedErrors;
|
||||
//private OutputFormatterOptions _outputFormatterOptions = new OutputFormatterOptions();
|
||||
|
||||
public MvcOptions()
|
||||
{
|
||||
|
|
@ -29,7 +28,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
OutputFormatters = new List<OutputFormatterDescriptor>();
|
||||
InputFormatters = new List<InputFormatterDescriptor>();
|
||||
Filters = new List<IFilter>();
|
||||
OutputFormatterOptions = new OutputFormatterOptions();
|
||||
FormatterMappings = new FormatterMappings();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -55,7 +54,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
public OutputFormatterOptions OutputFormatterOptions { get; }
|
||||
public FormatterMappings FormatterMappings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of <see cref="IFilter"/> which are used to construct filters that
|
||||
|
|
@ -69,16 +68,6 @@ namespace Microsoft.AspNet.Mvc
|
|||
/// </summary>
|
||||
public List<OutputFormatterDescriptor> OutputFormatters { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the mapping for output format specified in URL (extension) and content type
|
||||
/// </summary>
|
||||
/// <param name="format">URL extension for output format</param>
|
||||
/// <param name="contentType">Content type mapping to the format</param>
|
||||
public void AddFormatMapping(string format, MediaTypeHeaderValue contentType)
|
||||
{
|
||||
OutputFormatterOptions.AddFormatMapping(format, contentType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of the <see cref="InputFormatterDescriptor" /> which are used to construct
|
||||
/// a list of <see cref="IInputFormatter"/> by <see cref="IInputFormattersProvider"/>.
|
||||
|
|
|
|||
|
|
@ -1,46 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Core
|
||||
{
|
||||
public class OutputFormatterOptions
|
||||
{
|
||||
private Dictionary<string, MediaTypeHeaderValue> map = new Dictionary<string, MediaTypeHeaderValue>();
|
||||
|
||||
public void AddFormatMapping(string format, MediaTypeHeaderValue contentType)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(format) && contentType != null)
|
||||
{
|
||||
if(format.StartsWith("."))
|
||||
{
|
||||
format = format.TrimStart('.');
|
||||
}
|
||||
|
||||
map[format.ToLower()] = contentType;
|
||||
}
|
||||
}
|
||||
|
||||
public MediaTypeHeaderValue GetContentTypeForFormat(string format)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(format))
|
||||
{
|
||||
if (format.StartsWith("."))
|
||||
{
|
||||
format = format.TrimStart('.');
|
||||
}
|
||||
|
||||
if (map.ContainsKey(format.ToLower()))
|
||||
{
|
||||
return map[format.ToLower()];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -13,9 +13,7 @@
|
|||
"Microsoft.AspNet.Routing": "1.0.0-*",
|
||||
"Microsoft.AspNet.Security": "1.0.0-*",
|
||||
"Microsoft.AspNet.Security.DataProtection": "1.0.0-*",
|
||||
"Microsoft.Framework.Runtime.Interfaces": { "version": "1.0.0-*", "type": "build" },
|
||||
"Microsoft.Net.Http": "2.2.13.0",
|
||||
"Microsoft.Net.Http.Server": "1.0.0.0-rc1-11332"
|
||||
"Microsoft.Framework.Runtime.Interfaces": { "version": "1.0.0-*", "type": "build" }
|
||||
},
|
||||
"frameworks": {
|
||||
"aspnet50": {},
|
||||
|
|
|
|||
|
|
@ -46,9 +46,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
options.OutputFormatters.Add(new StringOutputFormatter());
|
||||
options.OutputFormatters.Add(new JsonOutputFormatter());
|
||||
|
||||
// Set up default mapping for xml and json extensions to content type
|
||||
options.AddFormatMapping("json", MediaTypeHeaderValue.Parse("application/json"));
|
||||
options.AddFormatMapping("xml", MediaTypeHeaderValue.Parse("application/xml"));
|
||||
// Set up default mapping for json extensions to content type
|
||||
options.FormatterMappings.SetFormatMapping("json", MediaTypeHeaderValue.Parse("application/json"));
|
||||
|
||||
// Set up default input formatters.
|
||||
options.InputFormatters.Add(new JsonInputFormatter());
|
||||
|
|
|
|||
|
|
@ -1,223 +1,348 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Mvc.Core.Filters;
|
||||
using Microsoft.AspNet.PipelineCore;
|
||||
// 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 Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Http.Core;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Xunit;
|
||||
|
||||
#if ASPNET50
|
||||
using Moq;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
using Microsoft.AspNet.Http;
|
||||
using System.Net;
|
||||
#endif
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Core.Test
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public enum FormatPlace
|
||||
{
|
||||
RouteData,
|
||||
QueryData,
|
||||
RouteAndQueryData
|
||||
}
|
||||
|
||||
public class FormatFilterTests
|
||||
{
|
||||
public enum FormatSource
|
||||
{
|
||||
RouteData,
|
||||
QueryData,
|
||||
RouteAndQueryData
|
||||
}
|
||||
|
||||
#if ASPNET50
|
||||
[Theory]
|
||||
[InlineData("json", FormatPlace.RouteData, "application/json")]
|
||||
[InlineData("json", FormatPlace.QueryData, "application/json")]
|
||||
[InlineData("json", FormatPlace.RouteAndQueryData, "application/json")]
|
||||
public void FormatFilter_ContextContainsFormat_DefaultFormat(string format,
|
||||
FormatPlace place,
|
||||
[InlineData("json", FormatSource.RouteData, "application/json")]
|
||||
[InlineData("json", FormatSource.QueryData, "application/json")]
|
||||
[InlineData("json", FormatSource.RouteAndQueryData, "application/json")]
|
||||
public void FormatFilter_ContextContainsFormat_DefaultFormat(
|
||||
string format,
|
||||
FormatSource place,
|
||||
string contentType)
|
||||
{
|
||||
// Arrange
|
||||
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
||||
var context = CreateResultExecutingContext(format, place);
|
||||
var filter = new FormatFilter();
|
||||
var mediaType = MediaTypeHeaderValue.Parse("application/json");
|
||||
var resultExecutingContext = CreateResultExecutingContext(
|
||||
format,
|
||||
FormatSource.RouteData);
|
||||
var resourceExecutingContext = CreateResourceExecutingContext(
|
||||
new IFilter[] { },
|
||||
format,
|
||||
FormatSource.RouteData);
|
||||
var filter = new FormatFilterAttribute();
|
||||
|
||||
// Act
|
||||
filter.OnResultExecuting(context);
|
||||
filter.OnResourceExecuting(resourceExecutingContext);
|
||||
|
||||
// Assert
|
||||
Assert.Null(resourceExecutingContext.Result);
|
||||
|
||||
// Act
|
||||
filter.OnResultExecuting(resultExecutingContext);
|
||||
|
||||
// Assert
|
||||
var objectResult = context.Result as ObjectResult;
|
||||
var objectResult = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
||||
Assert.Equal(1, objectResult.ContentTypes.Count);
|
||||
ValidateMediaType(mediaType, objectResult.ContentTypes[0]);
|
||||
AssertMediaTypesEqual(mediaType, objectResult.ContentTypes[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatFilter_ContextContainsFormat_InRouteAndQueryData()
|
||||
{
|
||||
// Arrange
|
||||
var mediaType = MediaTypeHeaderValue.Parse("application/json");
|
||||
|
||||
var httpContext = CreateMockHttpContext();
|
||||
|
||||
// Routedata contains json
|
||||
var data = new RouteData();
|
||||
data.Values.Add("format", "json");
|
||||
|
||||
// Query contains xml
|
||||
httpContext.Setup(c => c.Request.Query.ContainsKey("format")).Returns(true);
|
||||
httpContext.Setup(c => c.Request.Query.Get("format")).Returns("xml");
|
||||
var ac = new ActionContext(httpContext.Object, data, new ActionDescriptor());
|
||||
|
||||
var resultExecutingContext = new ResultExecutingContext(
|
||||
ac,
|
||||
new IFilter[] { },
|
||||
new ObjectResult("Hello!"),
|
||||
controller: new object());
|
||||
|
||||
var resourceExecutingContext = new ResourceExecutingContext(
|
||||
ac,
|
||||
new IFilter[] { });
|
||||
|
||||
var filter = new FormatFilterAttribute();
|
||||
|
||||
// Act
|
||||
filter.OnResourceExecuting(resourceExecutingContext);
|
||||
filter.OnResultExecuting(resultExecutingContext);
|
||||
|
||||
// Assert
|
||||
var objectResult = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
||||
Assert.Equal(1, objectResult.ContentTypes.Count);
|
||||
AssertMediaTypesEqual(mediaType, objectResult.ContentTypes[0]);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("foo", FormatPlace.RouteData, "application/foo")]
|
||||
[InlineData("foo", FormatPlace.QueryData, "application/foo")]
|
||||
[InlineData("foo", FormatPlace.RouteAndQueryData, "application/foo")]
|
||||
[InlineData("foo", FormatSource.RouteData, "application/foo")]
|
||||
[InlineData("foo", FormatSource.QueryData, "application/foo")]
|
||||
[InlineData("foo", FormatSource.RouteAndQueryData, "application/foo")]
|
||||
public void FormatFilter_ContextContainsFormat_Custom(
|
||||
string format,
|
||||
FormatPlace place,
|
||||
FormatSource place,
|
||||
string contentType)
|
||||
{
|
||||
// Arrange
|
||||
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
||||
var context = CreateResultExecutingContext(format, place);
|
||||
var options = (IOptions<MvcOptions>)context.HttpContext.RequestServices.GetService(
|
||||
typeof(IOptions<MvcOptions>));
|
||||
options.Options.AddFormatMapping(format, MediaTypeHeaderValue.Parse(contentType));
|
||||
var filter = new FormatFilter();
|
||||
var resultExecutingContext = CreateResultExecutingContext(format, place);
|
||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilter[] { }, format, place);
|
||||
var options = resultExecutingContext.HttpContext.RequestServices.GetService<IOptions<MvcOptions>>();
|
||||
options.Options.FormatterMappings.SetFormatMapping(format, MediaTypeHeaderValue.Parse(contentType));
|
||||
|
||||
var filter = new FormatFilterAttribute();
|
||||
|
||||
// Act
|
||||
filter.OnResultExecuting(context);
|
||||
|
||||
filter.OnResourceExecuting(resourceExecutingContext);
|
||||
filter.OnResultExecuting(resultExecutingContext);
|
||||
|
||||
// Assert
|
||||
var objectResult = context.Result as ObjectResult;
|
||||
var objectResult = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
||||
Assert.Equal(1, objectResult.ContentTypes.Count);
|
||||
ValidateMediaType(mediaType, objectResult.ContentTypes[0]);
|
||||
AssertMediaTypesEqual(mediaType, objectResult.ContentTypes[0]);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("foo", FormatPlace.RouteData, "application/foo")]
|
||||
public void FormatFilter_ContextContainsFormat_NonExisting(
|
||||
[InlineData("foo", FormatSource.RouteData, "application/foo")]
|
||||
[InlineData("foo", FormatSource.QueryData, "application/foo")]
|
||||
public void FormatFilter_ContextContainsNonExistingFormat(
|
||||
string format,
|
||||
FormatPlace place,
|
||||
FormatSource place,
|
||||
string contentType)
|
||||
{
|
||||
// Arrange
|
||||
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilter[] { }, format, place);
|
||||
var filter = new FormatFilter();
|
||||
var filter = new FormatFilterAttribute();
|
||||
|
||||
// Act
|
||||
filter.OnResourceExecuting(resourceExecutingContext);
|
||||
|
||||
// Assert
|
||||
var actionResult = resourceExecutingContext.Result;
|
||||
Assert.True(actionResult is HttpNotFoundResult);
|
||||
Assert.IsType<HttpNotFoundResult>(actionResult);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatFilter_ContextDoesntContainFormat()
|
||||
{
|
||||
// Arrange
|
||||
// Arrange
|
||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilter[] { });
|
||||
var filter = new FormatFilter();
|
||||
var filter = new FormatFilterAttribute();
|
||||
|
||||
// Act
|
||||
filter.OnResourceExecuting(resourceExecutingContext);
|
||||
|
||||
// Assert
|
||||
var result = resourceExecutingContext.Result as IActionResult;
|
||||
Assert.False(result is HttpNotFoundResult);
|
||||
Assert.Null(resourceExecutingContext.Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("json", FormatPlace.RouteData, "application/json")]
|
||||
[InlineData("json", FormatPlace.QueryData, "application/json")]
|
||||
[InlineData("json", FormatSource.RouteData, "application/json")]
|
||||
[InlineData("json", FormatSource.QueryData, "application/json")]
|
||||
public void FormatFilter_ContextContainsFormat_ContainsProducesFilter_Matching(
|
||||
string format,
|
||||
FormatPlace place,
|
||||
FormatSource place,
|
||||
string contentType)
|
||||
{
|
||||
// Arrange
|
||||
var produces = new ProducesAttribute(contentType, new string[] { "application/foo", "text/bar" });
|
||||
var context = CreateResourceExecutingContext(new IFilter[] { produces }, format, place);
|
||||
var filter = new FormatFilter();
|
||||
var filter = new FormatFilterAttribute();
|
||||
|
||||
// Act
|
||||
filter.OnResourceExecuting(context);
|
||||
|
||||
// Assert
|
||||
var result = context.Result as IActionResult;
|
||||
Assert.False(result is HttpNotFoundResult);
|
||||
// Assert
|
||||
Assert.Null(context.Result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatFilter_ContextContainsFormat_ContainsProducesFilter_WildCardMatching()
|
||||
{
|
||||
// Arrange
|
||||
var produces = new ProducesAttribute(
|
||||
"application/baz",
|
||||
new string[] { "application/foo", "text/bar" });
|
||||
var context = CreateResourceExecutingContext(new IFilter[] { produces }, "star", FormatSource.RouteData);
|
||||
var options = context.HttpContext.RequestServices.GetService<IOptions<MvcOptions>>();
|
||||
options.Options.FormatterMappings.SetFormatMapping("star", MediaTypeHeaderValue.Parse("application/*"));
|
||||
|
||||
var filter = new FormatFilterAttribute();
|
||||
|
||||
// Act
|
||||
filter.OnResourceExecuting(context);
|
||||
|
||||
// Assert
|
||||
Assert.Null(context.Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("json", FormatPlace.RouteData, "application/json")]
|
||||
[InlineData("json", FormatPlace.QueryData, "application/json")]
|
||||
[InlineData("json", FormatSource.RouteData, "application/json")]
|
||||
[InlineData("json", FormatSource.QueryData, "application/json")]
|
||||
public void FormatFilter_ContextContainsFormat_ContainsProducesFilter_Conflicting(
|
||||
string format,
|
||||
FormatPlace place,
|
||||
FormatSource place,
|
||||
string contentType)
|
||||
{
|
||||
// Arrange
|
||||
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
||||
var produces = new ProducesAttribute("application/xml", new string[] { "application/foo", "text/bar" });
|
||||
var context = CreateResourceExecutingContext(new IFilter[] { produces }, format, place);
|
||||
var filter = new FormatFilter();
|
||||
var filter = new FormatFilterAttribute();
|
||||
|
||||
// Act
|
||||
filter.OnResourceExecuting(context);
|
||||
|
||||
// Assert
|
||||
var result = context.Result as IActionResult;
|
||||
Assert.True(result is HttpNotFoundResult);
|
||||
var result = Assert.IsType<HttpNotFoundResult>(context.Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("", FormatSource.RouteData)]
|
||||
[InlineData(null, FormatSource.QueryData)]
|
||||
[InlineData("", FormatSource.RouteData)]
|
||||
[InlineData(null, FormatSource.QueryData)]
|
||||
public void FormatFilter_ContextContainsFormat_Invalid(
|
||||
string format,
|
||||
FormatSource place)
|
||||
{
|
||||
// Arrange
|
||||
var resourceExecutingContext = CreateResourceExecutingContext(
|
||||
new IFilter[] { },
|
||||
format,
|
||||
FormatSource.RouteData);
|
||||
var filter = new FormatFilterAttribute();
|
||||
|
||||
// Act
|
||||
filter.OnResourceExecuting(resourceExecutingContext);
|
||||
|
||||
// Assert
|
||||
Assert.Null(resourceExecutingContext.Result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("json", FormatSource.RouteData, "application/json")]
|
||||
[InlineData("json", FormatSource.QueryData, "application/json")]
|
||||
[InlineData("", FormatSource.RouteAndQueryData, null)]
|
||||
[InlineData(null, FormatSource.RouteAndQueryData, null)]
|
||||
public void FormatFilter_GetContentTypeForRequest(
|
||||
string format,
|
||||
FormatSource place,
|
||||
string contentType)
|
||||
{
|
||||
// Arrange
|
||||
var resourceExecutingContext = CreateResourceExecutingContext(
|
||||
new IFilter[] { },
|
||||
format,
|
||||
FormatSource.RouteData);
|
||||
var filter = new FormatFilterAttribute();
|
||||
var returnContentType = filter.GetContentTypeForCurrentRequest(resourceExecutingContext);
|
||||
|
||||
|
||||
MediaTypeHeaderValue mediaType = null;
|
||||
if (returnContentType != null)
|
||||
{
|
||||
mediaType = MediaTypeHeaderValue.Parse("application/json");
|
||||
}
|
||||
|
||||
Assert.Equal(mediaType, returnContentType);
|
||||
}
|
||||
|
||||
private static ResourceExecutingContext CreateResourceExecutingContext(
|
||||
IFilter[] filters,
|
||||
string format = null,
|
||||
FormatPlace? place = null)
|
||||
FormatSource? place = null)
|
||||
{
|
||||
if(format == null || place == null)
|
||||
if (format == null || place == null)
|
||||
{
|
||||
var context = new ResourceExecutingContext(
|
||||
CreateActionContext(),
|
||||
filters);
|
||||
context.Result = new HttpStatusCodeResult(200);
|
||||
return context;
|
||||
}
|
||||
|
||||
var context1 = new ResourceExecutingContext(
|
||||
CreateActionContext(format, place),
|
||||
filters);
|
||||
context1.Result = new HttpStatusCodeResult(200);
|
||||
return context1;
|
||||
}
|
||||
|
||||
private static ResultExecutingContext CreateResultExecutingContext(
|
||||
string format = null,
|
||||
FormatPlace? place = null)
|
||||
FormatSource? place = null)
|
||||
{
|
||||
if (format == null || place == null)
|
||||
if (format == null && place == null)
|
||||
{
|
||||
return new ResultExecutingContext(
|
||||
new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor()),
|
||||
new IFilter[] { },
|
||||
new ObjectResult("Some Value"));
|
||||
new ObjectResult("Some Value"),
|
||||
controller: new object());
|
||||
}
|
||||
|
||||
return new ResultExecutingContext(
|
||||
CreateActionContext(format, place),
|
||||
new IFilter[] { },
|
||||
new ObjectResult("Some Value"));
|
||||
new ObjectResult("Some Value"),
|
||||
controller: new object());
|
||||
}
|
||||
|
||||
private static ActionContext CreateActionContext(string format = null, FormatPlace? place = null)
|
||||
private static ActionContext CreateActionContext(string format = null, FormatSource? place = null)
|
||||
{
|
||||
var httpContext = CreateMockHttpContext();
|
||||
var data = new RouteData();
|
||||
|
||||
if (place == FormatPlace.RouteData || place == FormatPlace.RouteAndQueryData)
|
||||
{
|
||||
var data = new RouteData();
|
||||
if (place == FormatSource.RouteData || place == FormatSource.RouteAndQueryData)
|
||||
{
|
||||
data.Values.Add("format", format);
|
||||
httpContext.Setup(c => c.Request.Query.ContainsKey("format")).Returns(false);
|
||||
return new ActionContext(httpContext.Object, data, new ActionDescriptor());
|
||||
httpContext.Setup(c => c.Request.Query.ContainsKey("format")).Returns(false);
|
||||
}
|
||||
|
||||
if (place == FormatPlace.QueryData || place == FormatPlace.RouteAndQueryData)
|
||||
if (place == FormatSource.QueryData || place == FormatSource.RouteAndQueryData)
|
||||
{
|
||||
httpContext.Setup(c => c.Request.Query.ContainsKey("format")).Returns(true);
|
||||
httpContext.Setup(c => c.Request.Query.Get("format")).Returns(format);
|
||||
return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
||||
httpContext.Setup(c => c.Request.Query.Get("format")).Returns(format);
|
||||
}
|
||||
else if(place == null && format == null)
|
||||
else if (place == null && format == null)
|
||||
{
|
||||
httpContext.Setup(c => c.Request.Query.ContainsKey("format")).Returns(false);
|
||||
return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor());
|
||||
httpContext.Setup(c => c.Request.Query.ContainsKey("format")).Returns(false);
|
||||
}
|
||||
|
||||
return null;
|
||||
return new ActionContext(httpContext.Object, data, new ActionDescriptor());
|
||||
}
|
||||
|
||||
private static Mock<HttpContext> CreateMockHttpContext()
|
||||
{
|
||||
MvcOptions options = new MvcOptions();
|
||||
var options = new MvcOptions();
|
||||
MvcOptionsSetup.ConfigureMvc(options);
|
||||
var mvcOptions = new Mock<IOptions<MvcOptions>>();
|
||||
mvcOptions.Setup(o => o.Options).Returns(options);
|
||||
|
|
@ -236,7 +361,9 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
return httpContext;
|
||||
}
|
||||
|
||||
private static void ValidateMediaType(MediaTypeHeaderValue expectedMediaType, MediaTypeHeaderValue actualMediaType)
|
||||
private static void AssertMediaTypesEqual(
|
||||
MediaTypeHeaderValue expectedMediaType,
|
||||
MediaTypeHeaderValue actualMediaType)
|
||||
{
|
||||
Assert.Equal(expectedMediaType.MediaType, actualMediaType.MediaType);
|
||||
Assert.Equal(expectedMediaType.SubType, actualMediaType.SubType);
|
||||
|
|
@ -249,5 +376,6 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
Assert.Equal(item.Value, NameValueHeaderValue.Find(actualMediaType.Parameters, item.Name).Value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,10 @@ using Microsoft.AspNet.Routing;
|
|||
using Microsoft.Net.Http.Headers;
|
||||
using Xunit;
|
||||
|
||||
#if ASPNET50
|
||||
using Moq;
|
||||
#endif
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Test
|
||||
{
|
||||
public class ProducesAttributeTests
|
||||
|
|
@ -20,7 +24,7 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
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 resultExecutingContext = CreateResultExecutingContext(new IFilter[] { producesContentAttribute });
|
||||
var next = new ResultExecutionDelegate(
|
||||
() => Task.FromResult(CreateResultExecutedContext(resultExecutingContext)));
|
||||
|
||||
|
|
@ -33,6 +37,33 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
ValidateMediaType(mediaType1, objectResult.ContentTypes[0]);
|
||||
ValidateMediaType(mediaType2, objectResult.ContentTypes[1]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProducesContentAttribute_FormatFilterAttribute()
|
||||
{
|
||||
// Arrange
|
||||
var mediaType1 = MediaTypeHeaderValue.Parse("application/xml");
|
||||
var mediaType2 = MediaTypeHeaderValue.Parse("application/json");
|
||||
var producesContentAttribute = new ProducesAttribute("application/xml");
|
||||
|
||||
var formatFilter = new Mock<IFormatFilter>();
|
||||
formatFilter.Setup(f => f.GetContentTypeForCurrentRequest(It.IsAny<FilterContext>()))
|
||||
.Returns(mediaType2);
|
||||
|
||||
var filters = new IFilter[] { producesContentAttribute, formatFilter.Object };
|
||||
var resultExecutingContext = CreateResultExecutingContext(filters);
|
||||
|
||||
var next = new ResultExecutionDelegate(
|
||||
() => Task.FromResult(CreateResultExecutedContext(resultExecutingContext)));
|
||||
|
||||
// Act
|
||||
await producesContentAttribute.OnResultExecutionAsync(resultExecutingContext, next);
|
||||
|
||||
// Assert
|
||||
var objectResult = Assert.IsType<ObjectResult>(resultExecutingContext.Result);
|
||||
Assert.Equal(0, objectResult.ContentTypes.Count);
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData("", "")]
|
||||
|
|
@ -95,13 +126,12 @@ namespace Microsoft.AspNet.Mvc.Test
|
|||
return new ResultExecutedContext(context, context.Filters, context.Result, context.Controller);
|
||||
}
|
||||
|
||||
private static ResultExecutingContext CreateResultExecutingContext(IFilter filter)
|
||||
private static ResultExecutingContext CreateResultExecutingContext(IFilter[] filters)
|
||||
{
|
||||
return new ResultExecutingContext(
|
||||
CreateActionContext(),
|
||||
new IFilter[] { filter, },
|
||||
new ObjectResult("Some Value"),
|
||||
controller: new object());
|
||||
filters,
|
||||
new ObjectResult("Some Value"));
|
||||
}
|
||||
|
||||
private static ActionContext CreateActionContext()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,53 @@
|
|||
// 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 Microsoft.Net.Http.Headers;
|
||||
using Xunit;
|
||||
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
public class FormatterMappingsTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(".xml", "application/xml", "xml")]
|
||||
[InlineData("json", "application/json", "JSON")]
|
||||
[InlineData(".foo", "text/foo", "Foo")]
|
||||
[InlineData(".Json", "application/json", "json")]
|
||||
[InlineData("FOo", "text/foo", "FOO")]
|
||||
public void FormatterMappings_SetFormatMapping_DiffSetGetFormat(string setFormat, string contentType, string getFormat)
|
||||
{
|
||||
// Arrange
|
||||
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
||||
var options = new FormatterMappings();
|
||||
options.SetFormatMapping(setFormat, mediaType);
|
||||
|
||||
// Act
|
||||
var returnmediaType = options.GetContentTypeForFormat(getFormat);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(mediaType, returnmediaType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("xml", null)]
|
||||
[InlineData(".json", null)]
|
||||
[InlineData(null, "application/json")]
|
||||
[InlineData("", "text/foo")]
|
||||
public void FormatterMappings_SetFormatMapping_Invalid(string format, string contentType)
|
||||
{
|
||||
// Arrange
|
||||
MediaTypeHeaderValue mediaType = null;
|
||||
if (!string.IsNullOrEmpty(contentType))
|
||||
{
|
||||
mediaType = MediaTypeHeaderValue.Parse(contentType);
|
||||
}
|
||||
|
||||
var options = new FormatterMappings();
|
||||
|
||||
// Act and Assert
|
||||
Assert.Throws<ArgumentException>(() => options.SetFormatMapping(format, mediaType));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
using System;
|
||||
using Microsoft.AspNet.Mvc.Core;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Xunit;
|
||||
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Core.Test
|
||||
{
|
||||
public class OutputFormatterOptionsTest
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("xml", "application/xml")]
|
||||
[InlineData("json", "application/json")]
|
||||
[InlineData("foo", "text/foo")]
|
||||
[InlineData(".json", "application/json")]
|
||||
[InlineData(".foo", "text/foo")]
|
||||
public void OutputFormatterOptions_AddFormatMapping_Valid(string format, string contentType)
|
||||
{
|
||||
// Arrange
|
||||
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
||||
OutputFormatterOptions options = new OutputFormatterOptions();
|
||||
options.AddFormatMapping(format, mediaType);
|
||||
|
||||
// Act
|
||||
var returnmediaType = options.GetContentTypeForFormat(format);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(mediaType, returnmediaType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(".xml", "application/xml", "xml")]
|
||||
[InlineData("json", "application/json", "JSON")]
|
||||
[InlineData(".foo", "text/foo", "Foo")]
|
||||
[InlineData(".Json", "application/json", "json")]
|
||||
[InlineData("FOo", "text/foo", "FOO")]
|
||||
public void OutputFormatterOptions_AddFormatMapping_DiffSetGetFormat(string setFormat, string contentType, string getFormat)
|
||||
{
|
||||
// Arrange
|
||||
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
||||
OutputFormatterOptions options = new OutputFormatterOptions();
|
||||
options.AddFormatMapping(setFormat, mediaType);
|
||||
|
||||
// Act
|
||||
var returnmediaType = options.GetContentTypeForFormat(getFormat);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(mediaType, returnmediaType);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("xml", null)]
|
||||
[InlineData(".json", null)]
|
||||
[InlineData(null, "application/json")]
|
||||
[InlineData("", "text/foo")]
|
||||
public void OutputFormatterOptions_AddFormatMapping_Invalid(string format, string contentType)
|
||||
{
|
||||
// Arrange
|
||||
MediaTypeHeaderValue mediaType = null;
|
||||
if (!string.IsNullOrEmpty(contentType))
|
||||
{
|
||||
mediaType = MediaTypeHeaderValue.Parse(contentType);
|
||||
}
|
||||
|
||||
OutputFormatterOptions options = new OutputFormatterOptions();
|
||||
options.AddFormatMapping(format, mediaType);
|
||||
|
||||
// Act and Assert
|
||||
Assert.Throws<ArgumentException>(() => options.GetContentTypeForFormat(format));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -245,6 +245,119 @@ namespace Microsoft.AspNet.Mvc.Routing
|
|||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("moo/{p1}.{p2?}", "/moo/foo.bar", "foo", "bar", null)]
|
||||
[InlineData("moo/{p1?}", "/moo/foo", "foo", null, null)]
|
||||
[InlineData("moo/{p1?}", "/moo", null, null, null)]
|
||||
[InlineData("moo/{p1}.{p2?}", "/moo/foo", "foo", null, null)]
|
||||
[InlineData("moo/{p1}.{p2?}", "/moo/foo..bar", "foo.", "bar", null)]
|
||||
[InlineData("moo/{p1}.{p2?}", "/moo/foo.moo.bar", "foo.moo", "bar", null)]
|
||||
[InlineData("moo/{p1}.{p2}", "/moo/foo.bar", "foo", "bar", null)]
|
||||
[InlineData("moo/foo.{p1}.{p2?}", "/moo/foo.moo.bar", "moo", "bar", null)]
|
||||
[InlineData("moo/foo.{p1}.{p2?}", "/moo/foo.moo", "moo", null, null)]
|
||||
[InlineData("moo/.{p2?}", "/moo/.foo", null, "foo", null)]
|
||||
[InlineData("moo/{p1}.{p2?}", "/moo/....", "..", ".", null)]
|
||||
[InlineData("moo/{p1}.{p2?}", "/moo/.bar", ".bar", null, null)]
|
||||
[InlineData("moo/{p1}.{p2}.{p3?}", "/moo/foo.moo.bar", "foo", "moo", "bar")]
|
||||
[InlineData("moo/{p1}.{p2}.{p3?}", "/moo/foo.moo", "foo", "moo", null)]
|
||||
[InlineData("moo/{p1}.{p2}.{p3}.{p4?}", "/moo/foo.moo.bar", "foo", "moo", "bar")]
|
||||
[InlineData("{p1}.{p2?}/{p3}", "/foo.moo/bar", "foo", "moo", "bar")]
|
||||
[InlineData("{p1}.{p2?}/{p3}", "/foo/bar", "foo", null, "bar")]
|
||||
[InlineData("{p1}.{p2?}/{p3}", "/.foo/bar", ".foo", null, "bar")]
|
||||
public async Task AttributeRoute_WithOptionalCompositeParameter_Valid(
|
||||
string template,
|
||||
string request,
|
||||
string p1,
|
||||
string p2,
|
||||
string p3)
|
||||
{
|
||||
// Arrange
|
||||
var expectedRouteGroup = string.Format("{0}&&{1}", 0, template);
|
||||
|
||||
// We need to force the creation of a closure in order to avoid an issue with Moq and Roslyn.
|
||||
var numberOfCalls = 0;
|
||||
Action<RouteContext> callBack = ctx => { ctx.IsHandled = true; numberOfCalls++; };
|
||||
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(r => r.RouteAsync(It.IsAny<RouteContext>()))
|
||||
.Callback(callBack)
|
||||
.Returns(Task.FromResult(true))
|
||||
.Verifiable();
|
||||
|
||||
var firstRoute = CreateMatchingEntry(next.Object, template, order: 0);
|
||||
|
||||
// We setup the route entries in reverse order of precedence to ensure that when we
|
||||
// try to route the request, the route with a higher precedence gets tried first.
|
||||
var matchingRoutes = new[] { firstRoute };
|
||||
var linkGenerationEntries = Enumerable.Empty<AttributeRouteLinkGenerationEntry>();
|
||||
var route = new AttributeRoute(next.Object, matchingRoutes, linkGenerationEntries, NullLoggerFactory.Instance);
|
||||
var context = CreateRouteContext(request);
|
||||
|
||||
// Act
|
||||
await route.RouteAsync(context);
|
||||
|
||||
// Assert
|
||||
Assert.True(context.IsHandled);
|
||||
if (p1 != null)
|
||||
{
|
||||
Assert.Equal(p1, context.RouteData.Values["p1"]);
|
||||
}
|
||||
if (p2 != null)
|
||||
{
|
||||
Assert.Equal(p2, context.RouteData.Values["p2"]);
|
||||
}
|
||||
if (p3 != null)
|
||||
{
|
||||
Assert.Equal(p3, context.RouteData.Values["p3"]);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("moo/{p1}.{p2?}", "/moo/foo.")]
|
||||
[InlineData("moo/{p1}.{p2?}", "/moo/.")]
|
||||
[InlineData("moo/{p1}.{p2}", "/foo.")]
|
||||
[InlineData("moo/{p1}.{p2}", "/foo")]
|
||||
[InlineData("moo/{p1}.{p2}.{p3?}", "/moo/foo.moo.")]
|
||||
[InlineData("moo/foo.{p2}.{p3?}", "/moo/bar.foo.moo")]
|
||||
[InlineData("moo/foo.{p2}.{p3?}", "/moo/kungfoo.moo.bar")]
|
||||
[InlineData("moo/foo.{p2}.{p3?}", "/moo/kungfoo.moo")]
|
||||
[InlineData("moo/{p1}.{p2}.{p3?}", "/moo/foo")]
|
||||
[InlineData("{p1}.{p2?}/{p3}", "/foo./bar")]
|
||||
[InlineData("moo/.{p2?}", "/moo/.")]
|
||||
[InlineData("{p1}.{p2}/{p3}", "/.foo/bar")]
|
||||
public async Task AttributeRoute_WithOptionalCompositeParameter_Invalid(
|
||||
string template,
|
||||
string request)
|
||||
{
|
||||
// Arrange
|
||||
var expectedRouteGroup = string.Format("{0}&&{1}", 0, template);
|
||||
|
||||
// We need to force the creation of a closure in order to avoid an issue with Moq and Roslyn.
|
||||
var numberOfCalls = 0;
|
||||
Action<RouteContext> callBack = ctx => { ctx.IsHandled = true; numberOfCalls++; };
|
||||
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(r => r.RouteAsync(It.IsAny<RouteContext>()))
|
||||
.Callback(callBack)
|
||||
.Returns(Task.FromResult(true))
|
||||
.Verifiable();
|
||||
|
||||
var firstRoute = CreateMatchingEntry(next.Object, template, order: 0);
|
||||
|
||||
// We setup the route entries in reverse order of precedence to ensure that when we
|
||||
// try to route the request, the route with a higher precedence gets tried first.
|
||||
var matchingRoutes = new[] { firstRoute };
|
||||
var linkGenerationEntries = Enumerable.Empty<AttributeRouteLinkGenerationEntry>();
|
||||
var route = new AttributeRoute(next.Object, matchingRoutes, linkGenerationEntries, NullLoggerFactory.Instance);
|
||||
var context = CreateRouteContext(request);
|
||||
|
||||
// Act
|
||||
await route.RouteAsync(context);
|
||||
|
||||
// Assert
|
||||
Assert.False(context.IsHandled);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("template/5", "template/{parameter:int}")]
|
||||
[InlineData("template/5", "template/{parameter}")]
|
||||
|
|
@ -1196,6 +1309,96 @@ namespace Microsoft.AspNet.Mvc.Routing
|
|||
Assert.Equal("Store", path);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> OptionalParamValues
|
||||
{
|
||||
get
|
||||
{
|
||||
return new object[][]
|
||||
{
|
||||
// defaults
|
||||
// ambient values
|
||||
// values
|
||||
new object[]
|
||||
{
|
||||
"Test/{val1}/{val2}.{val3?}",
|
||||
new {val1 = "someval1", val2 = "someval2", val3 = "someval3a"},
|
||||
new {val3 = "someval3v"},
|
||||
"Test/someval1/someval2.someval3v",
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
"Test/{val1}/{val2}.{val3?}",
|
||||
new {val3 = "someval3a"},
|
||||
new {val1 = "someval1", val2 = "someval2", val3 = "someval3v" },
|
||||
"Test/someval1/someval2.someval3v",
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
"Test/{val1}/{val2}.{val3?}",
|
||||
null,
|
||||
new {val1 = "someval1", val2 = "someval2" },
|
||||
"Test/someval1/someval2",
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
"Test/{val1}.{val2}.{val3}.{val4?}",
|
||||
new {val1 = "someval1", val2 = "someval2" },
|
||||
new {val4 = "someval4", val3 = "someval3" },
|
||||
"Test/someval1.someval2.someval3.someval4",
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
"Test/{val1}.{val2}.{val3}.{val4?}",
|
||||
new {val1 = "someval1", val2 = "someval2" },
|
||||
new {val3 = "someval3" },
|
||||
"Test/someval1.someval2.someval3",
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
"Test/.{val2?}",
|
||||
null,
|
||||
new {val2 = "someval2" },
|
||||
"Test/.someval2",
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
"Test/.{val2?}",
|
||||
null,
|
||||
null,
|
||||
"Test/",
|
||||
},
|
||||
new object[]
|
||||
{
|
||||
"Test/{val1}.{val2}",
|
||||
new {val1 = "someval1", val2 = "someval2" },
|
||||
new {val3 = "someval3" },
|
||||
"Test/someval1.someval2?val3=someval3",
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData("OptionalParamValues")]
|
||||
public void AttributeRoute_GenerateLink_Match_WithOptionalParameters(
|
||||
string template,
|
||||
object ambientValues,
|
||||
object values,
|
||||
string expected)
|
||||
{
|
||||
// Arrange
|
||||
var entry = CreateGenerationEntry(template, null);
|
||||
var route = CreateAttributeRoute(entry);
|
||||
|
||||
var context = CreateVirtualPathContext(values, ambientValues);
|
||||
|
||||
// Act
|
||||
var path = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, path);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task AttributeRoute_CreatesNewRouteData()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -405,5 +405,35 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotAcceptable, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProducesAttribute_And_FormatFilterAttribute_Conflicting()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
var expectedContentType = MediaTypeHeaderValue.Parse("application/json");
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/FormatFilter/MethodWithFormatFilter.json");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProducesAttribute_And_FormatFilterAttribute_Collaborating()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/FormatFilter/MethodWithFormatFilter");
|
||||
|
||||
// Assert
|
||||
var type = response.Content.Headers.ContentType;
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
// 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.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
{
|
||||
public class FormatFilterTest
|
||||
{
|
||||
private readonly IServiceProvider _services = TestHelper.CreateServices("FormatFilterWebSite");
|
||||
private readonly Action<IApplicationBuilder> _app = new FormatFilterWebSite.Startup().Configure;
|
||||
|
||||
[Fact]
|
||||
public async Task FormatFilter_NoExtensionInRequest()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/FormatFilter/GetProduct/5");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(@"{""SampleInt"":5}", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FormatFilter_ExtensionInRequest_Default()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/FormatFilter/GetProduct/5.json");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(@"{""SampleInt"":5}", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FormatFilter_ExtensionInRequest_Custom()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/FormatFilter/GetProduct/5.custom");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(@"SampleInt:5", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FormatFilter_ExtensionInRequest_NonExistant()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/FormatFilter/GetProduct/5.xml");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FormatFilter_And_ProducesFilter_Match()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/FormatFilter/ProducesMethod/5.json");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(@"{""SampleInt"":5}", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FormatFilter_And_ProducesFilter_Conflict()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/FormatFilter/ProducesMethod/5.xml");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task FormatFilter_And_OverrideProducesFilter()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/ProducesDerived/ReturnClassName.json");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,7 +44,8 @@
|
|||
"MvcTagHelpersWebSite": "1.0.0",
|
||||
"Microsoft.Framework.ConfigurationModel.Json": "1.0.0-*",
|
||||
"xunit.runner.kre": "1.0.0-*",
|
||||
"Microsoft.AspNet.WebUtilities": "1.0.0-*"
|
||||
"Microsoft.AspNet.WebUtilities": "1.0.0-*",
|
||||
"FormatFilterWebSite": "1.0.0-*"
|
||||
},
|
||||
"commands": {
|
||||
"test": "xunit.runner.kre"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
// 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 ConnegWebSite;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace ConnegWebsite
|
||||
{
|
||||
[Produces("application/FormatFilterController")]
|
||||
public class FormatFilterController : Controller
|
||||
{
|
||||
[FormatFilter]
|
||||
public User MethodWithFormatFilter()
|
||||
{
|
||||
return new User() { Name = "Joe", Address = "1 abc way" };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,6 @@ namespace ConnegWebSite
|
|||
public virtual string ReturnClassNameContentTypeOnDerivedAction()
|
||||
{
|
||||
return "ProducesContentBaseController";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -39,6 +39,6 @@ namespace ConnegWebSite
|
|||
{
|
||||
// should be written using the content defined at derived class's class.
|
||||
return "ProducesContentOnClassController";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,7 @@ namespace ConnegWebSite
|
|||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute("ActionAsMethod", "{controller}/{action}",
|
||||
defaults: new { controller = "Home", action = "Index" });
|
||||
defaults: new { controller = "Home", action = "Index" });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,4 +15,9 @@
|
|||
<DevelopmentServerPort>49641</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties project_1json__JSONSchema="http://www.asp.net/media/4878834/project.json" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
|
|
@ -5,6 +5,7 @@ using System.Security.Claims;
|
|||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Security;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace FiltersWebSite
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
// 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 FormatFilterWebSite
|
||||
{
|
||||
[FormatFilter]
|
||||
public class FormatFilterController : Controller
|
||||
{
|
||||
public Product GetProduct(int id)
|
||||
{
|
||||
return new Product() { SampleInt = id };
|
||||
}
|
||||
|
||||
[Produces("application/custom", "application/json", "text/json")]
|
||||
public Product ProducesMethod(int id)
|
||||
{
|
||||
return new Product() { SampleInt = id };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace FormatFilterWebSite
|
||||
{
|
||||
public class ProducesBaseController : Controller
|
||||
{
|
||||
[Produces("application/custom_ProducesBaseController_Action")]
|
||||
public virtual string ReturnClassName()
|
||||
{
|
||||
// Should be written using the action's content type. Overriding the one at the class.
|
||||
return "ProducesBaseController";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
// 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 FormatFilterWebSite
|
||||
{
|
||||
[Produces("application/custom_ProducesOverrideController")]
|
||||
public class ProducesOverrideController : ProducesBaseController
|
||||
{
|
||||
[FormatFilter]
|
||||
public override string ReturnClassName()
|
||||
{
|
||||
// should be written using the content defined at base class's action.
|
||||
return "ProducesOverrideController";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace FormatFilterWebSite
|
||||
{
|
||||
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 actionReturn = context.Object as Product;
|
||||
if (actionReturn != 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.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
<?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)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>ac9be567-540e-4c70-90c2-aaf021307a80</ProjectGuid>
|
||||
<RootNamespace>FormatFilterWebSite</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">..\..\..\artifacts\obj\$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">..\..\..\artifacts\bin\$(MSBuildProjectName)\</OutputPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<DevelopmentServerPort>51135</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
<ProjectExtensions>
|
||||
<VisualStudio>
|
||||
<UserProperties project_1json__JSONSchema="http://www.asp.net/media/4878834/project.json" />
|
||||
</VisualStudio>
|
||||
</ProjectExtensions>
|
||||
</Project>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
|
||||
namespace FormatFilterWebSite
|
||||
{
|
||||
public class Product
|
||||
{
|
||||
public int SampleInt { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "SampleInt:" + SampleInt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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 Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace FormatFilterWebSite
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
var configuration = app.GetTestConfiguration();
|
||||
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.AddMvc(configuration);
|
||||
services.Configure<MvcOptions>(options =>
|
||||
{
|
||||
var formatFilter = new FormatFilterAttribute();
|
||||
options.Filters.Add(formatFilter);
|
||||
|
||||
var customFormatter = new CustomFormatter("application/custom");
|
||||
options.OutputFormatters.Add(customFormatter);
|
||||
|
||||
options.FormatterMappings.SetFormatMapping(
|
||||
"custom",
|
||||
MediaTypeHeaderValue.Parse("application/custom"));
|
||||
});
|
||||
});
|
||||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute("formatroute",
|
||||
"{controller}/{action}/{id}.{format?}",
|
||||
new { controller = "Home", action = "Index" });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"commands": {
|
||||
"web": "Microsoft.AspNet.Hosting server=Microsoft.AspNet.Server.WebListener server.urls=http://localhost:5001",
|
||||
"kestrel": "Microsoft.AspNet.Hosting --server Kestrel --server.urls http://localhost:5000"
|
||||
},
|
||||
"dependencies": {
|
||||
"Kestrel": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc": "6.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.TestConfiguration": "1.0.0",
|
||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||
"Microsoft.AspNet.Server.WebListener": "1.0.0-*",
|
||||
"Microsoft.AspNet.StaticFiles": "1.0.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"aspnet50": { },
|
||||
"aspnetcore50": { }
|
||||
},
|
||||
"webroot": "wwwroot"
|
||||
}
|
||||
Loading…
Reference in New Issue