Adding FromServicesAttribute.
This commit is contained in:
parent
ff3282827a
commit
d2aff42e25
|
|
@ -0,0 +1,27 @@
|
|||
// 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.ModelBinding;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// An <see cref="IModelBinder"/> which understands <see cref="IServiceActivatorBinderMetadata"/>
|
||||
/// and activates a given model using <see cref="IServiceProvider"/>.
|
||||
/// </summary>
|
||||
public class ServicesModelBinder : MetadataAwareBinder<IServiceActivatorBinderMetadata>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override Task<bool> BindAsync(
|
||||
[NotNull] ModelBindingContext bindingContext,
|
||||
[NotNull] IServiceActivatorBinderMetadata metadata)
|
||||
{
|
||||
var requestServices = bindingContext.OperationBindingContext.HttpContext.RequestServices;
|
||||
bindingContext.Model = requestServices.GetRequiredService(bindingContext.ModelType);
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// This attribute is used on action parameters or model properties to indicate that
|
||||
/// they will be bound using service provider.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
||||
public class FromServicesAttribute : Attribute, IServiceActivatorBinderMetadata
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// 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.ModelBinding
|
||||
{
|
||||
/// <summary>
|
||||
/// Metadata interface that indicates model binding should use the service container to get the value for a model.
|
||||
/// </summary>
|
||||
public interface IServiceActivatorBinderMetadata : IBinderMetadata
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,8 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
|
|||
/// <param name="bindingContext">The binding context which has the object to be bound.</param>
|
||||
/// <param name="metadata">The <see cref="IBinderMetadata"/> associated with the current binder.</param>
|
||||
/// <returns>A Task with a bool implying the success or failure of the operation.</returns>
|
||||
protected abstract Task<bool> BindAsync(ModelBindingContext bindingContext, TBinderMetadata metadata);
|
||||
protected abstract Task<bool> BindAsync([NotNull] ModelBindingContext bindingContext,
|
||||
[NotNull] TBinderMetadata metadata);
|
||||
|
||||
public Task<bool> BindModelAsync(ModelBindingContext context)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
options.ViewEngines.Add(typeof(RazorViewEngine));
|
||||
|
||||
// Set up ModelBinding
|
||||
options.ModelBinders.Add(typeof(ServicesModelBinder));
|
||||
options.ModelBinders.Add(typeof(BodyModelBinder));
|
||||
options.ModelBinders.Add(new TypeConverterModelBinder());
|
||||
options.ModelBinders.Add(new TypeMatchModelBinder());
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
|
||||
// Act
|
||||
var response = await client.PostAsync("http://localhost/Home/GetCustomer?Id=1234", content);
|
||||
|
||||
|
||||
//Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var customer = JsonConvert.DeserializeObject<Customer>(
|
||||
|
|
@ -75,6 +75,51 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
Assert.Equal("dummy", customer.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanModelBindServiceToAnArgument()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/FromServices_Calculator/Add?left=1234&right=1");
|
||||
|
||||
//Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("1235", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanModelBindServiceToAProperty()
|
||||
{
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync(
|
||||
"http://localhost/FromServices_Calculator/Calculate?Left=10&Right=5&Operator=*");
|
||||
|
||||
//Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("50", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CanModelBindServiceToAProperty_OnBaseType()
|
||||
{
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync(
|
||||
"http://localhost/FromServices_Calculator/CalculateWithPrecision?Left=10&Right=5&Operator=*");
|
||||
|
||||
//Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal("50", await response.Content.ReadAsStringAsync());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task MultipleParametersMarkedWithFromBody_Throws()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
[InlineData("http://localhost/Other/FromFilter")]
|
||||
[InlineData("http://localhost/Other/FromView")]
|
||||
[InlineData("http://localhost/Other/FromViewComponent")]
|
||||
[InlineData("http://localhost/Other/FromModelProperty")]
|
||||
[InlineData("http://localhost/Other/FromActionArgument")]
|
||||
public async Task RequestServices(string url)
|
||||
{
|
||||
// Arrange
|
||||
|
|
|
|||
|
|
@ -38,15 +38,17 @@ namespace Microsoft.AspNet.Mvc
|
|||
setup.Configure(mvcOptions);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(8, mvcOptions.ModelBinders.Count);
|
||||
Assert.Equal(typeof(BodyModelBinder), mvcOptions.ModelBinders[0].OptionType);
|
||||
Assert.Equal(typeof(TypeConverterModelBinder), mvcOptions.ModelBinders[1].OptionType);
|
||||
Assert.Equal(typeof(TypeMatchModelBinder), mvcOptions.ModelBinders[2].OptionType);
|
||||
Assert.Equal(typeof(CancellationTokenModelBinder), mvcOptions.ModelBinders[3].OptionType);
|
||||
Assert.Equal(typeof(ByteArrayModelBinder), mvcOptions.ModelBinders[4].OptionType);
|
||||
Assert.Equal(typeof(GenericModelBinder), mvcOptions.ModelBinders[5].OptionType);
|
||||
Assert.Equal(typeof(MutableObjectModelBinder), mvcOptions.ModelBinders[6].OptionType);
|
||||
Assert.Equal(typeof(ComplexModelDtoModelBinder), mvcOptions.ModelBinders[7].OptionType);
|
||||
var i = 0;
|
||||
Assert.Equal(9, mvcOptions.ModelBinders.Count);
|
||||
Assert.Equal(typeof(ServicesModelBinder), mvcOptions.ModelBinders[i++].OptionType);
|
||||
Assert.Equal(typeof(BodyModelBinder), mvcOptions.ModelBinders[i++].OptionType);
|
||||
Assert.Equal(typeof(TypeConverterModelBinder), mvcOptions.ModelBinders[i++].OptionType);
|
||||
Assert.Equal(typeof(TypeMatchModelBinder), mvcOptions.ModelBinders[i++].OptionType);
|
||||
Assert.Equal(typeof(CancellationTokenModelBinder), mvcOptions.ModelBinders[i++].OptionType);
|
||||
Assert.Equal(typeof(ByteArrayModelBinder), mvcOptions.ModelBinders[i++].OptionType);
|
||||
Assert.Equal(typeof(GenericModelBinder), mvcOptions.ModelBinders[i++].OptionType);
|
||||
Assert.Equal(typeof(MutableObjectModelBinder), mvcOptions.ModelBinders[i++].OptionType);
|
||||
Assert.Equal(typeof(ComplexModelDtoModelBinder), mvcOptions.ModelBinders[i++].OptionType);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
// 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 ModelBindingWebSite
|
||||
{
|
||||
public class CalculatorContext
|
||||
{
|
||||
[FromServices]
|
||||
public ICalculator Calculator { get; set; }
|
||||
|
||||
public int Left { get; set; }
|
||||
|
||||
public int Right { get; set; }
|
||||
|
||||
public char Operator { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.ModelBinding;
|
||||
|
||||
namespace ModelBindingWebSite.Controllers
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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 Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace ModelBindingWebSite.Controllers
|
||||
{
|
||||
public class FromServices_CalculatorController : Controller
|
||||
{
|
||||
public int Calculate(CalculatorContext context)
|
||||
{
|
||||
return context.Calculator.Operation(context.Operator, context.Left, context.Right);
|
||||
}
|
||||
|
||||
public int Add(int left, int right, [FromServices] ICalculator calculator)
|
||||
{
|
||||
return calculator.Operation('+', left, right);
|
||||
}
|
||||
|
||||
public int CalculateWithPrecision(DefaultCalculatorContext context)
|
||||
{
|
||||
return context.Calculator.Operation(context.Operator, context.Left, context.Right);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
// 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.Framework.Logging;
|
||||
|
||||
namespace ModelBindingWebSite
|
||||
{
|
||||
public class DefaultCalculator : ICalculator
|
||||
{
|
||||
private ILogger _logger;
|
||||
|
||||
public DefaultCalculator(ILoggerFactory loggerFactory)
|
||||
{
|
||||
_logger = loggerFactory.Create(typeof(DefaultCalculator).FullName);
|
||||
}
|
||||
|
||||
public int Operation(char @operator, int left, int right)
|
||||
{
|
||||
switch (@operator)
|
||||
{
|
||||
case '+': return left + right;
|
||||
case '-': return left - right;
|
||||
case '*': return left * right;
|
||||
case '/': return left / right;
|
||||
default:
|
||||
_logger.WriteError("Unrecognized operator:" + @operator);
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// 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 ModelBindingWebSite
|
||||
{
|
||||
public class DefaultCalculatorContext : CalculatorContext
|
||||
{
|
||||
public int Precision { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// 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 ModelBindingWebSite
|
||||
{
|
||||
public interface ICalculator
|
||||
{
|
||||
int Operation(char @operator, int left, int right);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ using Microsoft.AspNet.Builder;
|
|||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.Logging;
|
||||
|
||||
namespace ModelBindingWebSite
|
||||
{
|
||||
|
|
@ -24,6 +25,8 @@ namespace ModelBindingWebSite
|
|||
m.MaxModelValidationErrors = 8;
|
||||
m.ModelBinders.Insert(0, typeof(TestMetadataAwareBinder));
|
||||
});
|
||||
|
||||
services.AddSingleton<ICalculator, DefaultCalculator>();
|
||||
});
|
||||
|
||||
// Add MVC to the request pipeline
|
||||
|
|
|
|||
|
|
@ -39,5 +39,17 @@ namespace RequestServicesWebSite
|
|||
{
|
||||
return View("ViewComponent");
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public string FromModelProperty(RequestModel requestContext)
|
||||
{
|
||||
return requestContext.RequestIdService.RequestId;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public string FromActionArgument([FromServices] RequestIdService requestIdService)
|
||||
{
|
||||
return requestIdService.RequestId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// 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 RequestServicesWebSite
|
||||
{
|
||||
public class RequestModel
|
||||
{
|
||||
[FromServices]
|
||||
public RequestIdService RequestIdService { get; set; }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue