Incorporating PR comments - 1/19
This commit is contained in:
parent
c8b911b596
commit
7ee80020e1
|
|
@ -98,6 +98,7 @@ namespace MvcSample.Web
|
||||||
services.AddSingleton<PassThroughAttribute>();
|
services.AddSingleton<PassThroughAttribute>();
|
||||||
services.AddSingleton<UserNameService>();
|
services.AddSingleton<UserNameService>();
|
||||||
services.AddTransient<ITestService, TestService>();
|
services.AddTransient<ITestService, TestService>();
|
||||||
|
|
||||||
// Setup services with a test AssemblyProvider so that only the
|
// Setup services with a test AssemblyProvider so that only the
|
||||||
// sample's assemblies are loaded. This prevents loading controllers from other assemblies
|
// sample's assemblies are loaded. This prevents loading controllers from other assemblies
|
||||||
// when the sample is used in the Functional Tests.
|
// when the sample is used in the Functional Tests.
|
||||||
|
|
|
||||||
|
|
@ -13,8 +13,8 @@ using System.Collections.Generic;
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This will look at the format parameter if present in the route data or query data and
|
/// This will look at the format parameter if present in the route data or query data and sets the content type in
|
||||||
/// sets the content type in ObjectResult corresponding to the format value.
|
/// ObjectResult corresponding to the format value.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
|
||||||
public class FormatFilterAttribute : Attribute, IFormatFilter, IResourceFilter, IResultFilter
|
public class FormatFilterAttribute : Attribute, IFormatFilter, IResourceFilter, IResultFilter
|
||||||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// As a resourceFilter, this filter looks at the request and rejects it
|
/// As a resourceFilter, this filter looks at the request and rejects it
|
||||||
/// before going ahead if
|
/// before going ahead if
|
||||||
/// 1. The Format in the request doesnt match any format in the map.
|
/// 1. The format in the request doesnt match any format in the map.
|
||||||
/// 2. If there is a conflicting producesFilter.
|
/// 2. If there is a conflicting producesFilter.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="context"></param>
|
/// <param name="context"></param>
|
||||||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
var format = GetFormat(context);
|
var format = GetFormat(context);
|
||||||
|
|
||||||
if (format != null && !string.IsNullOrEmpty(format.ToString()))
|
if (!string.IsNullOrEmpty(format))
|
||||||
{
|
{
|
||||||
var formatContentType = GetContentType(format, context);
|
var formatContentType = GetContentType(format, context);
|
||||||
if (formatContentType == null)
|
if (formatContentType == null)
|
||||||
|
|
@ -44,6 +44,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
if (responseTypeFilters.Count() != 0)
|
if (responseTypeFilters.Count() != 0)
|
||||||
{
|
{
|
||||||
var contentTypes = new List<MediaTypeHeaderValue>();
|
var contentTypes = new List<MediaTypeHeaderValue>();
|
||||||
|
|
||||||
foreach (var filter in responseTypeFilters)
|
foreach (var filter in responseTypeFilters)
|
||||||
{
|
{
|
||||||
filter.SetContentTypes(contentTypes);
|
filter.SetContentTypes(contentTypes);
|
||||||
|
|
@ -58,11 +59,15 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public void OnResourceExecuted([NotNull] ResourceExecutedContext context)
|
public void OnResourceExecuted([NotNull] ResourceExecutedContext context)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This method looks at the format that request has and sets it in the context
|
||||||
|
/// </summary>
|
||||||
public void OnResultExecuting([NotNull] ResultExecutingContext context)
|
public void OnResultExecuting([NotNull] ResultExecutingContext context)
|
||||||
{
|
{
|
||||||
var format = GetFormat(context);
|
var format = GetFormat(context);
|
||||||
|
|
@ -80,11 +85,18 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
public void OnResultExecuted([NotNull] ResultExecutedContext context)
|
public void OnResultExecuted([NotNull] ResultExecutedContext context)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks at the current request for the format parameter. If it contains format, it returns the content type
|
||||||
|
/// for it.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="context"></param>
|
||||||
|
/// <returns></returns>
|
||||||
public MediaTypeHeaderValue GetContentTypeForCurrentRequest(FilterContext context)
|
public MediaTypeHeaderValue GetContentTypeForCurrentRequest(FilterContext context)
|
||||||
{
|
{
|
||||||
var format = GetFormat(context);
|
var format = GetFormat(context);
|
||||||
|
|
@ -96,7 +108,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private object GetFormat(FilterContext context)
|
private string GetFormat(FilterContext context)
|
||||||
{
|
{
|
||||||
object format = null;
|
object format = null;
|
||||||
|
|
||||||
|
|
@ -105,17 +117,22 @@ namespace Microsoft.AspNet.Mvc
|
||||||
if (context.HttpContext.Request.Query.ContainsKey("format"))
|
if (context.HttpContext.Request.Query.ContainsKey("format"))
|
||||||
{
|
{
|
||||||
format = context.HttpContext.Request.Query.Get("format");
|
format = context.HttpContext.Request.Query.Get("format");
|
||||||
|
return format.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return format.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
return format;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaTypeHeaderValue GetContentType(object format, FilterContext context)
|
private MediaTypeHeaderValue GetContentType(object format, FilterContext context)
|
||||||
{
|
{
|
||||||
Debug.Assert(format != null);
|
Debug.Assert(format != null);
|
||||||
var options = context.HttpContext.RequestServices.GetService<IOptions<MvcOptions>>();
|
var options = context.HttpContext.RequestServices.GetRequiredService<IOptions<MvcOptions>>();
|
||||||
var contentType = options.Options.FormatterMappings.GetContentTypeForFormat(format.ToString());
|
var contentType = options.Options.FormatterMappings.GetMediaTypeForFormat(format.ToString());
|
||||||
return contentType;
|
return contentType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,14 @@ using System;
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Implement this interface if you want to have your own implementation of FormatFilter
|
/// Implement this interface if you want to have your own implementation of FormatFilter. A FormatFilter decides
|
||||||
|
/// what content type to use if the format is present in the Url.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IFormatFilter : IFilter
|
public interface IFormatFilter : IFilter
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Get the <see cref="MediaTypeHeaderValue"/> registered fot the format in the request.
|
||||||
|
/// </summary>
|
||||||
MediaTypeHeaderValue GetContentTypeForCurrentRequest(FilterContext context);
|
MediaTypeHeaderValue GetContentTypeForCurrentRequest(FilterContext context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,15 +11,24 @@ using Microsoft.AspNet.Mvc.Core;
|
||||||
namespace Microsoft.AspNet.Mvc
|
namespace Microsoft.AspNet.Mvc
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// These options are used to specify mapping between the Url Format and corresponding ContentType.
|
/// Used to specify mapping between the Url Format and corresponding <see cref="MediaTypeHeaderValue"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class FormatterMappings
|
public class FormatterMappings
|
||||||
{
|
{
|
||||||
private readonly Dictionary<string, MediaTypeHeaderValue> _map =
|
private readonly Dictionary<string, MediaTypeHeaderValue> _map =
|
||||||
new Dictionary<string, MediaTypeHeaderValue>(StringComparer.OrdinalIgnoreCase);
|
new Dictionary<string, MediaTypeHeaderValue>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
public void SetFormatMapping([NotNull] string format, [NotNull] MediaTypeHeaderValue contentType)
|
/// <summary>
|
||||||
|
/// This will set mapping for the format to specified <see cref="MediaTypeHeaderValue"/>.
|
||||||
|
/// If the format already exists, the <see cref="MediaTypeHeaderValue"/> will be overwritten with the new value.
|
||||||
|
/// </summary>
|
||||||
|
public void SetMediaTypeMappingForFormat([NotNull] string format, [NotNull] MediaTypeHeaderValue contentType)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrEmpty(format))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "format");
|
||||||
|
}
|
||||||
|
|
||||||
if (contentType == null)
|
if (contentType == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentException((Resources.ArgumentCannotBeNullOrEmpty), "contentType");
|
throw new ArgumentException((Resources.ArgumentCannotBeNullOrEmpty), "contentType");
|
||||||
|
|
@ -29,7 +38,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
_map[format] = contentType;
|
_map[format] = contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MediaTypeHeaderValue GetContentTypeForFormat(string format)
|
/// <summary>
|
||||||
|
/// Gets <see cref="MediaTypeHeaderValue"/> for the specified format.
|
||||||
|
/// </summary>
|
||||||
|
public MediaTypeHeaderValue GetMediaTypeForFormat(string format)
|
||||||
{
|
{
|
||||||
format = RemovePeriodIfPresent(format);
|
format = RemovePeriodIfPresent(format);
|
||||||
MediaTypeHeaderValue value = null;
|
MediaTypeHeaderValue value = null;
|
||||||
|
|
@ -39,10 +51,6 @@ namespace Microsoft.AspNet.Mvc
|
||||||
|
|
||||||
private string RemovePeriodIfPresent(string format)
|
private string RemovePeriodIfPresent(string format)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(format))
|
|
||||||
{
|
|
||||||
throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "format");
|
|
||||||
}
|
|
||||||
if (format.StartsWith("."))
|
if (format.StartsWith("."))
|
||||||
{
|
{
|
||||||
format = format.Substring(1);
|
format = format.Substring(1);
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,9 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to specify mapping between the Url Format and corresponding <see cref="MediaTypeHeaderValue"/>.
|
||||||
|
/// </summary>
|
||||||
public FormatterMappings FormatterMappings { get; }
|
public FormatterMappings FormatterMappings { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
options.OutputFormatters.Add(new JsonOutputFormatter());
|
options.OutputFormatters.Add(new JsonOutputFormatter());
|
||||||
|
|
||||||
// Set up default mapping for json extensions to content type
|
// Set up default mapping for json extensions to content type
|
||||||
options.FormatterMappings.SetFormatMapping("json", MediaTypeHeaderValue.Parse("application/json"));
|
options.FormatterMappings.SetMediaTypeMappingForFormat("json", MediaTypeHeaderValue.Parse("application/json"));
|
||||||
|
|
||||||
// Set up default input formatters.
|
// Set up default input formatters.
|
||||||
options.InputFormatters.Add(new JsonInputFormatter());
|
options.InputFormatters.Add(new JsonInputFormatter());
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ namespace Microsoft.AspNet.Mvc
|
||||||
[Fact]
|
[Fact]
|
||||||
public void FormatFilter_ContextContainsFormat_InRouteAndQueryData()
|
public void FormatFilter_ContextContainsFormat_InRouteAndQueryData()
|
||||||
{
|
{
|
||||||
|
// If the format is present in both route and query data, the one in route data wins
|
||||||
|
|
||||||
// Arrange
|
// Arrange
|
||||||
var mediaType = MediaTypeHeaderValue.Parse("application/json");
|
var mediaType = MediaTypeHeaderValue.Parse("application/json");
|
||||||
|
|
||||||
|
|
@ -116,7 +118,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
var resultExecutingContext = CreateResultExecutingContext(format, place);
|
var resultExecutingContext = CreateResultExecutingContext(format, place);
|
||||||
var resourceExecutingContext = CreateResourceExecutingContext(new IFilter[] { }, format, place);
|
var resourceExecutingContext = CreateResourceExecutingContext(new IFilter[] { }, format, place);
|
||||||
var options = resultExecutingContext.HttpContext.RequestServices.GetService<IOptions<MvcOptions>>();
|
var options = resultExecutingContext.HttpContext.RequestServices.GetService<IOptions<MvcOptions>>();
|
||||||
options.Options.FormatterMappings.SetFormatMapping(format, MediaTypeHeaderValue.Parse(contentType));
|
options.Options.FormatterMappings.SetMediaTypeMappingForFormat(format, MediaTypeHeaderValue.Parse(contentType));
|
||||||
|
|
||||||
var filter = new FormatFilterAttribute();
|
var filter = new FormatFilterAttribute();
|
||||||
|
|
||||||
|
|
@ -194,7 +196,7 @@ namespace Microsoft.AspNet.Mvc
|
||||||
new string[] { "application/foo", "text/bar" });
|
new string[] { "application/foo", "text/bar" });
|
||||||
var context = CreateResourceExecutingContext(new IFilter[] { produces }, "star", FormatSource.RouteData);
|
var context = CreateResourceExecutingContext(new IFilter[] { produces }, "star", FormatSource.RouteData);
|
||||||
var options = context.HttpContext.RequestServices.GetService<IOptions<MvcOptions>>();
|
var options = context.HttpContext.RequestServices.GetService<IOptions<MvcOptions>>();
|
||||||
options.Options.FormatterMappings.SetFormatMapping("star", MediaTypeHeaderValue.Parse("application/*"));
|
options.Options.FormatterMappings.SetMediaTypeMappingForFormat("star", MediaTypeHeaderValue.Parse("application/*"));
|
||||||
|
|
||||||
var filter = new FormatFilterAttribute();
|
var filter = new FormatFilterAttribute();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,8 @@ namespace Microsoft.AspNet.Mvc.Test
|
||||||
return new ResultExecutingContext(
|
return new ResultExecutingContext(
|
||||||
CreateActionContext(),
|
CreateActionContext(),
|
||||||
filters,
|
filters,
|
||||||
new ObjectResult("Some Value"));
|
new ObjectResult("Some Value"),
|
||||||
|
controller: new object());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ActionContext CreateActionContext()
|
private static ActionContext CreateActionContext()
|
||||||
|
|
|
||||||
|
|
@ -21,13 +21,13 @@ namespace Microsoft.AspNet.Mvc
|
||||||
// Arrange
|
// Arrange
|
||||||
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
var mediaType = MediaTypeHeaderValue.Parse(contentType);
|
||||||
var options = new FormatterMappings();
|
var options = new FormatterMappings();
|
||||||
options.SetFormatMapping(setFormat, mediaType);
|
options.SetMediaTypeMappingForFormat(setFormat, mediaType);
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
var returnmediaType = options.GetContentTypeForFormat(getFormat);
|
var returnMediaType = options.GetMediaTypeForFormat(getFormat);
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.Equal(mediaType, returnmediaType);
|
Assert.Equal(mediaType, returnMediaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
|
|
@ -45,9 +45,10 @@ namespace Microsoft.AspNet.Mvc
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = new FormatterMappings();
|
var options = new FormatterMappings();
|
||||||
|
var expectedError = "Value cannot be null or empty." + Environment.NewLine + "Parameter name: format";
|
||||||
|
|
||||||
// Act and Assert
|
// Act and Assert
|
||||||
Assert.Throws<ArgumentException>(() => options.SetFormatMapping(format, mediaType));
|
Assert.Throws<ArgumentException>(() => options.SetMediaTypeMappingForFormat(format, mediaType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -432,8 +432,9 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
var response = await client.GetAsync("http://localhost/FormatFilter/MethodWithFormatFilter");
|
var response = await client.GetAsync("http://localhost/FormatFilter/MethodWithFormatFilter");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
var type = response.Content.Headers.ContentType;
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
var body = await response.Content.ReadAsStringAsync();
|
var body = await response.Content.ReadAsStringAsync();
|
||||||
|
Assert.Equal(body, "MethodWithFormatFilter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
{
|
{
|
||||||
public class FormatFilterTest
|
public class FormatFilterTest
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _services = TestHelper.CreateServices("FormatFilterWebSite");
|
private readonly IServiceProvider _services = TestHelper.CreateServices(nameof(FormatFilterWebSite));
|
||||||
private readonly Action<IApplicationBuilder> _app = new FormatFilterWebSite.Startup().Configure;
|
private readonly Action<IApplicationBuilder> _app = new FormatFilterWebSite.Startup().Configure;
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
|
|
@ -45,6 +45,21 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
Assert.Equal(@"{""SampleInt"":5}", await response.Content.ReadAsStringAsync());
|
Assert.Equal(@"{""SampleInt"":5}", await response.Content.ReadAsStringAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task FormatFilter_ExtensionInRequest_Optional()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var server = TestServer.Create(_services, _app);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var response = await client.GetAsync("http://localhost/FormatFilter/GetProduct.json");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||||
|
Assert.Equal(@"{""SampleInt"":0}", await response.Content.ReadAsStringAsync());
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task FormatFilter_ExtensionInRequest_Custom()
|
public async Task FormatFilter_ExtensionInRequest_Custom()
|
||||||
{
|
{
|
||||||
|
|
@ -60,6 +75,21 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||||
Assert.Equal(@"SampleInt:5", await response.Content.ReadAsStringAsync());
|
Assert.Equal(@"SampleInt:5", await response.Content.ReadAsStringAsync());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task FormatFilter_ExtensionInRequest_CaseInsensitivity()
|
||||||
|
{
|
||||||
|
// 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]
|
[Fact]
|
||||||
public async Task FormatFilter_ExtensionInRequest_NonExistant()
|
public async Task FormatFilter_ExtensionInRequest_NonExistant()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,21 @@ namespace ConnegWebsite
|
||||||
[Produces("application/FormatFilterController")]
|
[Produces("application/FormatFilterController")]
|
||||||
public class FormatFilterController : Controller
|
public class FormatFilterController : Controller
|
||||||
{
|
{
|
||||||
[FormatFilter]
|
public override void OnActionExecuted(ActionExecutedContext context)
|
||||||
public User MethodWithFormatFilter()
|
|
||||||
{
|
{
|
||||||
return new User() { Name = "Joe", Address = "1 abc way" };
|
var result = context.Result as ObjectResult;
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
result.Formatters.Add(new CustomFormatter("application/FormatFilterController"));
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnActionExecuted(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
[FormatFilter]
|
||||||
|
public string MethodWithFormatFilter()
|
||||||
|
{
|
||||||
|
return "MethodWithFormatFilter";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ namespace FormatFilterWebSite
|
||||||
[FormatFilter]
|
[FormatFilter]
|
||||||
public class FormatFilterController : Controller
|
public class FormatFilterController : Controller
|
||||||
{
|
{
|
||||||
public Product GetProduct(int id)
|
public Product GetProduct(int id = 0)
|
||||||
{
|
{
|
||||||
return new Product() { SampleInt = id };
|
return new Product() { SampleInt = id };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ namespace FormatFilterWebSite
|
||||||
var customFormatter = new CustomFormatter("application/custom");
|
var customFormatter = new CustomFormatter("application/custom");
|
||||||
options.OutputFormatters.Add(customFormatter);
|
options.OutputFormatters.Add(customFormatter);
|
||||||
|
|
||||||
options.FormatterMappings.SetFormatMapping(
|
options.FormatterMappings.SetMediaTypeMappingForFormat(
|
||||||
"custom",
|
"custom",
|
||||||
MediaTypeHeaderValue.Parse("application/custom"));
|
MediaTypeHeaderValue.Parse("application/custom"));
|
||||||
});
|
});
|
||||||
|
|
@ -37,6 +37,10 @@ namespace FormatFilterWebSite
|
||||||
routes.MapRoute("formatroute",
|
routes.MapRoute("formatroute",
|
||||||
"{controller}/{action}/{id}.{format?}",
|
"{controller}/{action}/{id}.{format?}",
|
||||||
new { controller = "Home", action = "Index" });
|
new { controller = "Home", action = "Index" });
|
||||||
|
|
||||||
|
routes.MapRoute("optionalroute",
|
||||||
|
"{controller}/{action}.{format?}",
|
||||||
|
new { controller = "Home", action = "Index" });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
Loading…
Reference in New Issue